[Solved] Subclassing QAbstractTableModel



  • I have got implemented all the virtual function than subclassing QAbstractTableModel needs, anyway I can't see anything. Just an empty table.

    I made a simple example which reproduces this issues:
    @#ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include <QAbstractTableModel>

    namespace Ui {
    class MainWindow;
    }

    //////////////////////////////////////////////////
    /// \brief The MainWindow class
    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    private:
    Ui::MainWindow *ui;
    };

    //////////////////////////////////////////////////
    /// \brief The ThreadModel class
    class ThreadModel : public QAbstractTableModel
    {
    Q_OBJECT

    public:
    explicit ThreadModel(QObject *parent = 0);
    ~ThreadModel();

    int rowCount(const QModelIndex&/* parent = QModelIndex()*/) const override;
    int columnCount(const QModelIndex&/* parent = QModelIndex()*/) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
    

    protected:
    QList<QList<int>> threadList;
    };

    #endif // MAINWINDOW_H
    @

    @#include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <sstream>
    using namespace std;

    ////////////////////////////////////////////////
    /// \brief The ThreadDetail class
    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);

    ThreadModel model;
    ui->tableView->setModel(&model);
    

    }

    MainWindow::~MainWindow()
    {
    delete ui;
    }

    //////////////////////////////////////////////////
    /// \brief The ThreadModel class
    ThreadModel::ThreadModel(QObject parent/ = 0*/)
    {
    QList<int> column1;
    column1.push_back(10);
    column1.push_back(20);
    column1.push_back(30);
    column1.push_back(40);

    threadList.push_back(column1);
    
    QList<int> column2;
    column2.push_back(50);
    column2.push_back(60);
    column2.push_back(70);
    column2.push_back(80);
    
    threadList.push_back(column2);
    

    }

    ThreadModel::~ThreadModel()
    {
    }

    int ThreadModel::rowCount(const QModelIndex&/* parent*/) const
    {
    return threadList[0].size();
    }

    int ThreadModel::columnCount(const QModelIndex&/* parent*/) const
    {
    return threadList.size();
    }

    QVariant ThreadModel::data(const QModelIndex &index, int role) const
    {
    if (role == Qt::DisplayRole)
    return threadList[index.column()][index.row()];

    return QVariant::Invalid;
    

    }

    QVariant ThreadModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
    if (role == Qt::DisplayRole)
    {
    stringstream ss;
    if (orientation == Qt::Horizontal)
    {
    ss << "H_" << section;
    return QString(ss.str().c_str());
    }
    else if (orientation == Qt::Vertical)
    {
    ss << "H_" << section;
    QString debug = QString(ss.str().c_str());
    return QString(ss.str().c_str());
    }
    }

    return QVariant::Invalid;
    

    }
    @

    What else do I need to do? :S


  • Lifetime Qt Champion

    Hi,

    If the role is not something you handle, return the base class function's implementation otherwise your view won't have any information to show you anything



  • What do you mean with "handling the rol"? What else do I need to do?


  • Lifetime Qt Champion

    @ if (role == Qt::DisplayRole)@

    You only handle DisplayRole, returning QVariant::Invalid for every other role just gives the views nothing to work on.

    What to do ? What I already wrote, for every other role return the base class implementation result of data and headerData



  • First, you CAN'T to return the base class implementation, because it's PURE virtual. You know, the data function is = 0.
    And second, even no handling the rol (without condition) it shows nothing.


  • Lifetime Qt Champion

    Yes you can. You can have have a pure virtual function with a default implementation which is not the case for QAbstractTableModel.

    Anyway, you are missing some checks like e.g. the validity for the index given as a parameter. Did you also ensure that all your methods are called ?

    You can have a look at the Pixelator example, it uses a custom QAbstractTableModel



  • Let's see if we are talking about the same. If we have:
    @#include <iostream>
    using namespace std;

    class A
    {
    public:
    virtual void foo() = 0; // Now, you NEED to override this method!
    };

    void A::foo()
    {
    cout << "A::foo" << endl;
    }

    class B : public A
    {
    public:
    void foo() override; // Overriding base foo. You get a compiling error if not!:
    // Cannot declare variable 'b' to be of abstract type 'B' B b; because the following virtual functions are pure within 'B'
    };

    void B::foo()
    {
    cout << "B::foo" << endl;
    }

    int main(int argc, char *argv[])
    {
    B b;

    b.foo();
    
    return 0;
    

    }@

    As I said before, I can't to call a pure virtual function (=0). You need to override it on its derived class.



  • I stumbled upon a similar problem when reading the "Model/View Tutorial":http://qt-project.org/doc/qt-5/modelview.html . One of your problem(s) might be, that you create a Stack-variable "model" in your MainWindow constructor, which you then pass to the tableView as model. When the constructor is done, the Stack-variable won't exist anymore.

    You could try allocating "model" on the heap and see if this is fixing your problem. I.e. change

    @MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);

    ThreadModel model;
    ui->tableView->setModel(&model);
    

    }@

    ... to ...

    @MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);

    ThreadModel *model = new ThreadModel();
    ui->tableView->setModel(model);
    

    }@


  • Lifetime Qt Champion

    yetanotherbender has the right solution, I missed that one in your code.

    As for our little understanding problem:

    @
    #include <iostream>
    using namespace std;

    class A
    {
    public:
    virtual void foo() = 0; // Now, you NEED to override this method! << Correct and agreed
    };

    void A::foo()
    {
    cout << "A::foo" << endl;
    }

    class B : public A
    {
    public:
    void foo() override; // Overriding base foo. You get a compiling error if not!: << still correct and agreed
    };

    void B::foo()
    {
    A::foo() // If your B class doesn't do anything special you can call the base class default implementation
    }

    int main(int argc, char *argv[])
    {
    B b;

    b.foo();
    
    return 0;
    

    }
    @



  • [quote author="yetanotherbender" date="1403608883"]You could try allocating “model” on the heap and see if this is fixing your problem[/quote]

    Great! That fixed the problem! Thank you SO F*much!! :D

    SGaist, thank you for trying and being pacient!! :)


  • Lifetime Qt Champion

    You're welcome !

    Happy Qt coding ! :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.