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; };
-
@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 QAbstractItemModelvoid 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 docsThe 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 oneQLineEdit
, will you actually want multiple columns, because if you only have a single column you may instead only want aQStringListModel
? -
@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 docsThe 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 aQStringListModel
?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:-
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*
!) TryQStandardItemModel
. -
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 ofmodel->index(newRowIndex,0)
(https://doc.qt.io/qt-5/qabstractitemmodel.html#index).] -
You can now use
QStandardItemModel::insertRow(int row, QStandardItem *item)
(https://doc.qt.io/qt-5/qstandarditemmodel.html#insertRow-1) instead. -
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?
-
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 ofsetData()
, now usevoid 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 allowsetData()
and you have to use a wholeQStandardItem
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 usingQStandardItemModel::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 withQStandardItemModel
. It will return false only if an invalid index is passed to itIn 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
. -
@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? :)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 andsetData()
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; };