Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

fill QTableView with items from lineedit



  • I would like to add items into a QTableView. These will be retrieved from a QLineEdit whenever the pushbutton is pressed.

    What's the best way to do this?



  • @JonB @Christian-Ehrlicher @VRonin

    Thanks for all of your help!

    It works now. This is the source code for anyone who has the same question:

    void MainWindow::addItemToTableView(QString name)
    {
        QStandardItem *item = new QStandardItem(name);
        items << item;
    
        for(int i = 0; i < items.size(); i++)
        {
            for(int j = 0; j < 1; j++)
            {
    
                model->setItem(i, j, items.at(i));
            }
        }
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    private slots:
        void on_pushButton_clicked();
    
    private:
        Ui::MainWindow *ui;
    
        void addItemToTableView(QString);
        QList<QStandardItem*> items;
        QStandardItemModel  *model;
    };
    


  • just call insertRows and setData on the model



  • @VRonin I'm a beginner so I don't know much about this.

    index is basically just an integer to count how many rows have been inserted before.
    model is an QAbstractItemModel

    void MainWindow::addItemToTableView(QString name)
    {
        QModelIndex modelIndex;
        model->insertRow(index, modelIndex);
        model->setData(modelIndex, name);
        index++;
        ui->tableView->setModel(model);
    }
    

    I'd love to hear what I am doing wrong. It's not showing up in the tableView.



  • @hobbyProgrammer said in fill QTableView with items from lineedit:

    model is an QAbstractItemModel

    Before we start on your code. Do you mean your model is actually a QAbstractItemModel, or do you mean it's a class derived from that? Because as per docs

    The QAbstractItemModel class defines the standard interface that item models must use to be able to interoperate with other components in the model/view architecture. It is not supposed to be instantiated directly. Instead, you should subclass it to create new models.

    Since you're starting out QStandardItemModel would be a recommended choice. Or, your code only attempts to put a single "name" into a row, and you talk about one QLineEdit, will you actually want multiple columns, because if you only have a single column you may instead only want a QStringListModel?



  • @JonB said in fill QTableView with items from lineedit:

    Before we start on your code. Do you mean your model is actually a QAbstractItemModel, or do you mean it's a class derived from that? Because as per docs

    The model is actually a QAbstractItemModel

    Since you're starting out QStandardItemModel would be a recommended choice.

    Okay thank you. I will look into that.

    Or, your code only attempts to put a single "name" into a row, and you talk about one QLineEdit, will you actually want multiple columns, because if you only have a single column you may instead only want a QStringListModel?

    Currently I only need 1 column, but I'd like to expand it to two. So I would like to create an easily expandable solution.



  • @hobbyProgrammer
    OK. For your code, scribbled in haste:

    1. QAbstractItemModel::setData() won't do anything. So you can't use it to store data. (As an end-user of a library, you usually never want to create/instantiate any class named *Abstract*!) Try QStandardItemModel.

    2. You need to make your QModelIndex modelIndex refer to where you want to insert in your code. [EDIT From what @VRonin has just posted below, that's the magic of model->index(newRowIndex,0) (https://doc.qt.io/qt-5/qabstractitemmodel.html#index).]

    3. You can now use QStandardItemModel::insertRow(int row, QStandardItem *item) (https://doc.qt.io/qt-5/qstandarditemmodel.html#insertRow-1) instead.

    4. Don't put the ui->tableView->setModel(model); when adding an item, put it once at the start outside of here.



  • Assuming the model works:

    const int newRowIndex = model->rowCount();
    model->insertRow(newRowIndex);
    model->setData(model->index(newRowIndex,0),name);
    

    I agree the easiest way is just to use QAbstractItemModel* model = new QStandardItemModel as a model. It works out of the box and gives you the flexibility to change it in the future if you really want a custom model



  • @VRonin Hi,

    For the model I just do this in the constructor:

        model = new QStandardItemModel(100,1,this);
        ui->tableView->setModel(model);
    

    and it's in the mainwindow.h file like this:

       QStandardItemModel  *model;
    

    and to add an item:

    void MainWindow::addItemToTableView(QString name)
    {
        qDebug () << "insert: " << name;
        const int newRowIndex = model->rowCount();
        model->insertRow(newRowIndex);
        model->setData(model->index(newRowIndex, 0), name);
    }
    

    it does print insert: name in the debugger, so the function is being called, but all the cells remain empty. Any idea why?


  • Lifetime Qt Champion

    Since you're using a QStandardItemModel you have to first create an item for this index. Or even better - only work with QStandardItems since this is what QStandardItemModel is created for. See https://doc-snapshots.qt.io/qt5-dev/qstandarditemmodel.html#details on how to add a QStandardItem.
    When you check the return value of setData() you would have noticed that it returns false for you.



  • @hobbyProgrammer
    As @Christian-Ehrlicher has said and I wrote earlier, get rid of setData(), now use void QStandardItemModel::appendRow(QStandardItem *item) instead.



  • I disagree with @Christian-Ehrlicher and @JonB for once. This is rare. The QAbstractItemModel interface works perfectly well without any need to use specific subclass methods.

    This minimal complete example illustrates how it works, try it out. It should be straightforward then to adapt it to your situation

    #include <QTableView>
    #include <QGridLayout>
    #include <QLineEdit>
    #include <QStandardItemModel>
    #include <QApplication>
    #include <QPushButton>
    #include <QHeaderView>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        QWidget mainWid;
        QAbstractItemModel* model = new QStandardItemModel(&mainWid);
        model->insertColumn(0);
        model->setHeaderData(0,Qt::Horizontal,QStringLiteral("My Column"));
        QTableView* table = new QTableView(&mainWid);
        table->setModel(model);
        table->horizontalHeader()->setStretchLastSection(true);
        QPushButton* insertLineButton = new QPushButton(QStringLiteral("Insert Row"),&mainWid);
        QLineEdit* lineInsertEdit = new QLineEdit(&mainWid);
        QObject::connect(insertLineButton,&QPushButton::clicked,[model,lineInsertEdit]()->void{
            const int newRowIndex = model->rowCount();
            model->insertRow(newRowIndex);
            model->setData(model->index(newRowIndex, 0), lineInsertEdit->text());
            lineInsertEdit->clear();
        });
        QGridLayout* mainLay = new QGridLayout(&mainWid);
        mainLay->addWidget(table,0,0,1,2);
        mainLay->addWidget(lineInsertEdit,1,0);
        mainLay->addWidget(insertLineButton,1,1);
        mainWid.show();
        return a.exec();
    }
    


  • @VRonin
    I don't understand. @Christian-Ehrlicher wrote:

    When you check the return value of setData() you would have noticed that it returns false for you.

    I took him at his word! So your model->setData(model->index(newRowIndex, 0), lineInsertEdit->text()); should do noting and return false? And your code looks the same as the OP's attempt where he says "but all the cells remain empty."?

    I was actually going to create a new post to ask: I have never used QStandardItemModel, but in light of @Christian-Ehrlicher's comment I was going to ask what the "philosophy" of its design is if it does not allow setData() and you have to use a whole QStandardItem at a time instead of via row/column index? I'm confused :(



  • I'll take it as a "citation needed":
    QStandardItemModel::setData fetches the item coresponding to the cell using QStandardItemModel::itemFromIndex (see relevant code)

    itemFromIndex then has a section, marked as "lazy part" that takes care of creating the item if it wasn't done already (see relevant code).

    Hence calling setData works perfectly in any case with QStandardItemModel. It will return false only if an invalid index is passed to it

    In the case of QStandardItemModel, the only reason to use methods of the derived class rather than the interface is if you use the (rather useful) QStandardItem::setFlags.


  • Lifetime Qt Champion

    @VRonin : you're right, I missed that part.



  • @Christian-Ehrlicher said in fill QTableView with items from lineedit:

    @VRonin : you're right, I missed that part.

    OMG! OK, well at least now I don't have to post to ask why QStandardItemModel::setData() isn't implemented since it is after all, right? :)

    @VRonin

    In the case of QStandardItemModel, the only reason to use methods of the derived class rather than the interface is if you use the (rather useful) QStandardItem::setFlags.

    Don't you think e.g. QStandardItemModel::appendRow(QStandardItem *item) looks rather neater than getting the row count and setData()ing for each column? :) I agree in this case when the user only wants to set one column it's not so needed, but in other cases?



  • @JonB @Christian-Ehrlicher @VRonin

    Thanks for all of your help!

    It works now. This is the source code for anyone who has the same question:

    void MainWindow::addItemToTableView(QString name)
    {
        QStandardItem *item = new QStandardItem(name);
        items << item;
    
        for(int i = 0; i < items.size(); i++)
        {
            for(int j = 0; j < 1; j++)
            {
    
                model->setItem(i, j, items.at(i));
            }
        }
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    private slots:
        void on_pushButton_clicked();
    
    private:
        Ui::MainWindow *ui;
    
        void addItemToTableView(QString);
        QList<QStandardItem*> items;
        QStandardItemModel  *model;
    };
    


  • disappointed


Log in to reply