Problem to access QStandardItemModel object
-
wrote on 30 Aug 2019, 18:51 last edited by
I have built a class which contains an object "QTreeView" linked to an object "QStandardItemModel".
Inside this class, a button is linked to a "slot function" which inserts lines in the "QTreeView" and it works very well.
But if I call this function from outside this object, it crashes because the functions of the object "QStandardItemModel" are not accessible anymore. And I don't understand why...The image below shows the very simple interface:
- The object "QTreeView" with 2 columns
- The left button "Insert Line" which belongs to the same class as the "QStandardItemModel" and the "QTreeView". This button is linked to a function "void InsertLine()" with QObject::connect process. This button works.
- The button at the bottom "Test" does not belong to this class: it is connected to an intermediate function which calls the method "InsertLine()". This button does not work.
The line which causes the crash is:
nbColumns = SIM_table.columnCount();
The header file of the main class "mainwindow.h" is:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include "blocktablefields.h" #include <QMainWindow> #include <QPushButton> #include <QStandardItemModel> #include <QTreeView> QT_BEGIN_NAMESPACE class QAction; class QLabel; class QMenu; QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); private slots: void Test(); private: QWidget *centralWidget; QVBoxLayout *vertLayout_Main; BlockTableFields *BTF_test; QPushButton *BT_test; }; #endif
The corresponding .cpp file:
#include <QtWidgets> #include "mainwindow.h" MainWindow::MainWindow() { QString titleTest; QList<QString> *listHeaders; // Initializations titleTest = QString("Tests"); listHeaders = new QList<QString>; listHeaders->push_back("Field 1"); listHeaders->push_back("Field 2"); vertLayout_Main = new QVBoxLayout(); BlockTableFields *BTF_test = new BlockTableFields(this, &titleTest, listHeaders); vertLayout_Main->addWidget(BTF_test); BT_test = new QPushButton("Test"); QObject::connect(BT_test, SIGNAL(clicked()), this, SLOT(Test())); vertLayout_Main->addWidget(BT_test); centralWidget = new QWidget; setCentralWidget(centralWidget); centralWidget->setLayout(vertLayout_Main); setWindowTitle(tr("Test")); resize(400, 200); } void MainWindow::Test() { BTF_test->InsertLine(); }
The header file of the class which contains the objects "QTreeView" and "QStandardItemModel" is:
#ifndef BLOCKTABLEFIELDS_H #define BLOCKTABLEFIELDS_H #include <QWidget> #include <QLabel> #include <QBoxLayout> #include <QPushButton> #include <QStandardItemModel> #include <QTreeView> class BlockTableFields : public QWidget { Q_OBJECT public: explicit BlockTableFields(QWidget *parent = nullptr, QString *blockTitle = nullptr, QList<QString> *listHeaders = nullptr); signals: public slots: void InitTable(); void InsertLine(); private: QLabel *LB_title; QStandardItemModel SIM_table; QTreeView *TV_table; QPushButton *BT_AddLineBefore; // Layouts QHBoxLayout *horizLayout_All; QVBoxLayout *vertLayout_Text; QVBoxLayout *vertLayout_Buttons; }; #endif // BLOCKTABLEFIELDS_H
The corresponding .cpp file:
#include "blocktablefields.h" BlockTableFields::BlockTableFields(QWidget *parent, QString *blockTitle, QList<QString> *listHeaders) : QWidget(parent) { int numHeader; // Title LB_title = new QLabel(); if (blockTitle != nullptr) { LB_title->setText(*blockTitle); } // Headers // if no header is given, a table with only 1 column is built, with an empty header // else, the number of columns is fixed by the number of headers if ((listHeaders != nullptr) && (listHeaders->size() > 0)) { SIM_table.setColumnCount(int(listHeaders->size())); for (numHeader = 0; numHeader < int(listHeaders->size()); numHeader++) { SIM_table.setHeaderData(numHeader, Qt::Horizontal, listHeaders->at(numHeader)); } } else { SIM_table.setColumnCount(1); SIM_table.setHeaderData(0, Qt::Horizontal, QObject::tr("")); } // Creation of the first line InitTable(); // Creation of the link between SIM_table and TV_table TV_table = new QTreeView; TV_table->setRootIsDecorated(false); TV_table->setAlternatingRowColors(true); TV_table->setModel(&SIM_table); // Buttons vertLayout_Buttons = new QVBoxLayout(); // Add new line before the current line BT_AddLineBefore = new QPushButton("Insert Line"); QObject::connect(BT_AddLineBefore, SIGNAL(clicked()), this, SLOT(InsertLine())); vertLayout_Buttons->addWidget(BT_AddLineBefore); // Spaces at the beginning and the end vertLayout_Buttons->insertStretch(0); vertLayout_Buttons->addStretch(); // Vertical Layout (Title and field for text) vertLayout_Text = new QVBoxLayout(); vertLayout_Text->addWidget(LB_title); vertLayout_Text->addWidget(TV_table); // Main Layout horizLayout_All = new QHBoxLayout(); this->setLayout(horizLayout_All); horizLayout_All->addLayout(vertLayout_Buttons); horizLayout_All->addLayout(vertLayout_Text); } void BlockTableFields::InitTable() { int numColumn; QStandardItem *defaultItem = new QStandardItem(QString("")); QList<QStandardItem *> defaultLine; for (numColumn = 0; numColumn < SIM_table.columnCount(); numColumn++){ defaultLine.push_back(defaultItem); } SIM_table.insertRow(0, defaultLine); } void BlockTableFields::InsertLine() { QModelIndex tableIndex; int numLine = 0, numColumn, nbColumns; QStandardItem *defaultItem = new QStandardItem(QString("")); QList<QStandardItem *> defaultLine; nbColumns = SIM_table.columnCount(); for (numColumn = 0; numColumn < nbColumns; numColumn++){ defaultLine.push_back(defaultItem); } tableIndex = TV_table->currentIndex(); if (tableIndex.isValid()) { numLine = tableIndex.row(); SIM_table.insertRow(numLine, defaultLine); tableIndex = SIM_table.index(numLine, tableIndex.column()); TV_table->setCurrentIndex(tableIndex); } else { numLine = 0; SIM_table.insertRow(numLine, defaultLine); tableIndex = SIM_table.index(numLine, 0); TV_table->setCurrentIndex(tableIndex); } }
The complete project (very light) can be downloaded here:
Complete_projectIf someone can tell me why it does not work, it would be very usefull for me!
Thank you in advance for your help!
Laurent -
Your member MainWindow ::BTF_test is not initialized.
Apart from this you're leaking listHeaders (don't know why you need a pointer here) and your InitTable does not set anything correct since you're setting the same item on more than one cell which is not allowed. -
Your member MainWindow ::BTF_test is not initialized.
Apart from this you're leaking listHeaders (don't know why you need a pointer here) and your InitTable does not set anything correct since you're setting the same item on more than one cell which is not allowed.wrote on 30 Aug 2019, 20:36 last edited by@christian-ehrlicher
Thank you very much for your answer !
Indeed, there was a double declaration of "BTF_test" which was the cause of my problem.
I will check the other points you mentionned to avoid new bugs.
1/3