My Qt QAbstractProxyModel crashes with ChartView but not with TableView? - c++

I have a custom QAbstractTableModel and a proxy model which flips the axes of the first model. With the table this works, I just switch the model. When I switch to my proxy model for the chart it crashes at the point where I assign the rows to the QHXYModelMapper. What have I screwed up?
This is the table model:
#include "tablemodel.h"
TableModel::TableModel(QObject *parent) :
QAbstractTableModel(parent)
{
}
int TableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_data.count();
}
int TableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
if(m_data.count() < 1)
{
return 0;
}
return m_data[0].count();
}
QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal) {
if (section % 2 == 0)
return "x";
else
return "y";
} else {
return QString("%1").arg(section + 1);
}
}
QVariant TableModel::data(const QModelIndex &index, int role) const
{
if (!role == Qt::DisplayRole)
{
return QVariant();
}
return m_data[index.row()].at(index.column());
}
bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole) {
m_data[index.row()].replace(index.column(), value.toDouble());
emit dataChanged(index, index);
return true;
}
return false;
}
void TableModel::appendRow(QVector<double> row)
{
emit layoutAboutToBeChanged();
emit beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_data.append(row);
emit endInsertRows();
emit layoutChanged();
}
void TableModel::clear()
{
for(int i = 0; i < m_data.count(); ++i)
{
m_data[i].clear();
}
m_data.clear();
}
This is the proxy implementation:
HorizontalProxyModel::HorizontalProxyModel(QObject *parent) : QAbstractProxyModel(parent)
{
}
QModelIndex HorizontalProxyModel::mapToSource(const QModelIndex &proxyIndex) const
{
if (sourceModel()) {
return sourceModel()->index(proxyIndex.column(), proxyIndex.row());
} else {
return QModelIndex();
}
}
QModelIndex HorizontalProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
{
return index(sourceIndex.column(), sourceIndex.row());
}
QModelIndex HorizontalProxyModel::index(int row, int column, const QModelIndex &) const
{
return createIndex(row, column, (void*) 0);
}
QModelIndex HorizontalProxyModel::parent(const QModelIndex &) const
{
return QModelIndex();
}
int HorizontalProxyModel::rowCount(const QModelIndex &) const
{
return sourceModel() ? sourceModel()->columnCount() : 0;
}
int HorizontalProxyModel::columnCount(const QModelIndex &) const
{
return sourceModel() ? sourceModel()->rowCount() : 0;
}
QVariant HorizontalProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (!sourceModel()) { return QVariant(); }
Qt::Orientation new_orientation = orientation == Qt::Horizontal ?
Qt::Vertical : Qt::Horizontal;
return sourceModel() ? sourceModel()->headerData(section, new_orientation, role) : 0;
}
QVariant HorizontalProxyModel::data(const QModelIndex &index) const
{
qDebug() << "h model data";
return sourceModel() ? sourceModel()->data(sourceModel()->index(index.column(), index.row())) : 0;
}
And this is where I assign the model:
void MainWindow::plot(QAbstractItemModel* m)
{
QChart* chart = new QChart;
qDebug() << m->rowCount() << " " << m->columnCount();
for(int row = 0; row < m->rowCount(); ++row)
{
QLineSeries *series = new QLineSeries;
QHXYModelMapper* mapper = new QHXYModelMapper;
QString name = "Row " + QString::number(row);
series->setName(name);
mapper->setModel(m);
mapper->setSeries(series);
mapper->setXRow(row); //crashes here if proxy model
mapper->setYRow(row);
chart->addSeries(series);
}
chart->createDefaultAxes();
QChart* oldChart = chartView->chart();
chartView->setChart(chart);
oldChart->deleteLater();
}
EDIT
Some more info...
Looking at the debugger, it seems that the index being created in the ProxyModel and passed to the original model is -1/-1 (invalid). Does line 9 in this debug output mean that the base class QAbstractProxyModel::data() is being called, instead of the one from my derived proxy model? If so, why?
1 __pthread_kill
0x7fff91eaff06
2 pthread_kill 0x7fff907204ec
3 abort 0x7fff876cd6df
4 qt_message_fatal(QtMsgType, QMessageLogContext const&, QString const&) 0x100ac3e79
5 QMessageLogger::fatal(const char *, ...) const 0x100ac5847
6 qt_assert_x(const char *, const char *, const char *, int) 0x100ac0682
7 QList<QVector<double>>::operator[](int) const qlist.h 541 0x10000fced
8 TableModel::data(QModelIndex const&, int) const tablemodel.cpp 46 0x10000f8f1
9 QAbstractProxyModel::data(QModelIndex const&, int) const 0x100c4c28b
10 QtCharts::QXYModelMapperPrivate::valueFromModel(QModelIndex) 0x10171dfb3
11 QtCharts::QXYModelMapperPrivate::initializeXYFromModel() 0x10171d92f
12 QtCharts::QHXYModelMapper::setYRow(int) 0x101720bf4
13 MainWindow::plot(QAbstractItemModel *)
UDPATE: FIX
So, the fix I have right now is to call QHXYModelMapper::setColumnCount() manually, like so:
mapper->setModel(m);
mapper->setSeries(series);
mapper->setColumnCount(m->columnCount());
mapper->setXRow(row);
mapper->setYRow(row);
The docs seem to imply that the default value will use the total number of columns in the model, if I don't explicitly set this:
http://doc.qt.io/qt-5/qhxymodelmapper.html#columnCount-prop

Talked it over on the Qt forums a bit, this appears to be a bug, where the default value for the HXYModelMapper columnCount property does not actually retrieve the proper columnCount from the model. The workaround is to call setColumnCount yourself and set it to the columnCount of your model.
mapper->setModel(m);
mapper->setSeries(series);
mapper->setColumnCount(m->columnCount());
mapper->setXRow(row);
mapper->setYRow(row);
Bug report: https://bugreports.qt.io/browse/QTBUG-57342

Related

How to create a QTreeView that can handle very large amount of data?

I'm adding data loaded form a file on disk to a QTreeView , the file contains more than 60.000 rows and new 'rows'/data will be constantly added to it while its being executed, so each time the GUI is reloaded/reopened the file will contain more data.
I tried to load this data using another thread just to figure out that QAbstractItemModel is not thread safe.
Then I tried to created a 'lazy load' subclass of a QAbstractItemModel , that 'process' the items as they get visible in the
QTreeview.
At the beginning it worked great, as it doesn't freeze the entire GUI for like 10~ seconds at runtime anymore.
However when i scroll the QTreeView it get frozen for many seconds, i think its 'loading' the data.
I was reading the documentation of QAbstractItemModel and see that it have these two functions: fetchMore() and canFetchMore(), to control how the data is loaded, but i didn't understand how to use it and if they could help in this case.
How I could dynamically load/unload the data as it get visible in the QTreeView? and free the memory of the rows that are not visible/not visible anymore, instead of having the entire file loaded into the memory.
Here is what I already did, using Qt 6.4.
Reproducible example:
#include "treeview.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindowClass())
{
ui->setupUi(this);
QGridLayout* layout = new QGridLayout(this);
ui->centralWidget->setLayout(layout);
auto treeView = new TreeView(this);
layout->addWidget(treeView);
QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_F2), this);
connect(shortcut, &QShortcut::activated, [=] {
treeView->setInfo();
qDebug() << "rowCount: " << treeView->model->rowCount();
});
}
treeview.h
class LazyLoadingModel : public QAbstractItemModel
{
Q_OBJECT
public:
LazyLoadingModel(QObject *parent = nullptr) : QAbstractItemModel(parent) {}
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
return m_rows.count();
}
int columnCount(const QModelIndex &parent = QModelIndex()) const override
{
return m_columns.count();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
{
if (!index.isValid())
return QVariant();
int row = index.row();
int column = index.column();
if (row >= m_rows.count() || column >= m_columns.count())
return QVariant();
if (role == Qt::DisplayRole)
{
return m_rows[row][column];
}
return QVariant();
}
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
{
if (!index.isValid())
return false;
int row = index.row();
int column = index.column();
if (row >= m_rows.count() || column >= m_columns.count())
return false;
if (role == Qt::EditRole)
{
m_rows[row][column] = value.toString();
emit dataChanged(index, index);
return true;
}
return false;
}
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
{
if (!parent.isValid())
return createIndex(row, column);
else
return QModelIndex();
}
QModelIndex parent(const QModelIndex &index) const override
{
return QModelIndex();
}
void setColumns(const QStringList &columns)
{
m_columns = columns;
}
void addData(const QVector<QStringList> &row_info)
{
beginInsertRows(QModelIndex(), m_rows.count(), m_rows.count() + row_info.count() - 1);
for (const auto &row : row_info)
m_rows.append(row);
endInsertRows();
}
private:
QStringList m_columns;
QList<QStringList> m_rows;
};
class TreeView : public QTreeView {
Q_OBJECT
public:
LazyLoadingModel* model = new LazyLoadingModel();
TreeView(QWidget* parent = 0) : QTreeView(parent) {
setModel(model);
}
void setInfo() {
QElapsedTimer timer;
timer.start();
model->setColumns({ "Column 0", "Column 1", "Column 2", "Column 3" });
//
// Load the data from disk and parse it into a qvector
// or:
// Create some random data, just to debug the model:
QVector<QStringList> info{};
QStringList list;
for (size_t i = 0; i < 60000; i++) {
list = {};
QString str = QString::number(i);
for (size_t i = 0; i < 4; i++)
list << str;
info.emplace_back(list);
}
model->addData(info);
qint64 elapsed = timer.elapsed();
qDebug() << "[T] Elapsed time (ms):" << elapsed;
}
};

How to map a multi-level object model with a QAbstractItemModel

I start to lern MVC pattern in Qt.
I have the simple data structure, like this:
class Stage
{
public:
QString name;
int number;
};
class Doc
{
public:
Doc();
~Doc();
QString name;
int number;
QList<Stage *> *stages;
};
I want to view this structure in TreeView. For this i create model class:
class Model: public QAbstractItemModel
{
Q_OBJECT
public:
Model(QObject *parent);
~Model();
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column, const QModelIndex &parent) const;
QModelIndex parent(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
private:
QList<Doc*> *docs;
If I have only one level of data (doc without stage), everything works fine, but I can't understand how to add second tree level to the model(stage)?
Code example (one level)
Model::Model(QObject *parent) : QAbstractItemModel(parent)
{
docs = new QList<Doc*>();
for (int i = 0; i < 3; ++i) {
Doc *d = new Doc();
d->name = "name_" + QString::number(i);
d->number = i;
docs->append(d);
}
}
Model::~Model()
{
delete docs;
}
QModelIndex Model::index(int row, int column, const QModelIndex &parent) const
{
if (!parent.isValid()) {
Doc *d = docs->at(row);
return createIndex(row, column, d);
}
return QModelIndex();
}
QModelIndex Model::parent(const QModelIndex &index) const
{
return QModelIndex();
}
int Model::rowCount(const QModelIndex &parent) const
{
int cnt = 0;
if (!parent.isValid()) {
cnt = docs->size();
}
return cnt;
}
int Model::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 3;
}
Qt::ItemFlags Model::flags(const QModelIndex &index) const
{
if (!index.isValid())
return nullptr;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant Model::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal) {
switch (section) {
case 0:
return tr("Number");
case 1:
return tr("Code");
case 2:
return tr("Stages count");
default:
return QVariant();
}
}
return QVariant();
}
QVariant Model::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
{
Doc *d = static_cast<Doc*>(index.internalPointer());
switch (index.column()) {
case 0:
return d->name;
case 1:
return d->number;
case 2:
return d->stages->size();
default:
break;
}
}
return QVariant();
}
i think its will look like this:
Model::Model(QObject *parent) : QAbstractItemModel(parent)
{
docs = new QList<Doc*>();
for (int i = 0; i < 3; ++i) {
Doc *d = new Doc();
d->name = "name_" + QString::number(i);
d->number = i;
for (int j = 5; j < 9; ++j) {
Stage *s = new Stage();
s->name = "name_" + QString::number(j);
s->number = j;
d->stages->append(s);
}
docs->append(d);
}
}
QModelIndex Model::index(int row, int column, const QModelIndex &parent) const
{
if (!parent.isValid()) {
Doc *d = docs->at(row);
return createIndex(row, column, d);
} else {
Stage *s = static_cast<Doc*>(parent.internalPointer())->stages->at(row);
return createIndex(row, column, s);
}
return QModelIndex();
}
QModelIndex Model::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
else if (index.parent().isValid())
return createIndex(index.parent().row(), 0, index.internalPointer());
return QModelIndex();
}
int Model::rowCount(const QModelIndex &parent) const
{
int cnt = 0;
if (!parent.isValid()) {
cnt = docs->size();
} else {
cnt = static_cast<Doc*>(parent.parent().internalPointer())->stages->size();
}
return cnt;
}
but its wrong code...

How to get first item as default item in combo box delegate?

I am using QAbstractTableModel and ComboBoxItemDelegate which inherits QStyledItemDelegate. I am able to populate my data in combo boxes in table view but by default nothing is displayed but after clicking correct data is visible in dropdown. How can i set first item as a default item and display it?
My Combox delegate:
class ComboBoxItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
ComboBoxItemDelegate(QObject* parent = 0);
~ComboBoxItemDelegate();
virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
virtual void setEditorData(QWidget* editor, const QModelIndex& index) const;
virtual void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
Create editor function:
QWidget* ComboBoxItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QComboBox* cb = new QComboBox(parent);
QStringList destList = SFilterEditorData::instance().getDestinationList();
cb->addItem(QString("All"));
for (int i = 0; i < destList.size(); i++)
{
cb->addItem(destList.at(i));
}
cb->setEditable(true);
return cb;
}
set Editor function:
void ComboBoxItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
if (QComboBox* cb = qobject_cast<QComboBox*>(editor)) {
//QString currentText = index.data(Qt::EditRole).toString();
QString currentText = index.model()->data(index, Qt::DisplayRole).toString();
int cbIndex = cb->findText(currentText);
// if it is valid, adjust the combobox
if (cbIndex >= 0)
cb->setCurrentIndex(cbIndex);
}
else {
QStyledItemDelegate::setEditorData(editor, index);
}
}
Inserting rows in my model:
bool STableModel::insertRows(int position, int rows, const QModelIndex &parent)
{
int columns = columnCount();
beginInsertRows(parent, position, position + rows - 1);
for (int row = 0; row < rows; ++row) {
QStringList items;
for (int column = 0; column < columns; ++column)
{
items.append(""); // This might be the reason for this issue.
}
rowList.insert(position, items);
}
endInsertRows();
return true;
}
Setting data in model:
QVariant STableModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role == Qt::DisplayRole)
return rowList[index.row()][index.column()];
else if (role == Qt::CheckStateRole && index.column() == 0)
{
int status = SFilterEditorData::instance().getStatus(index.row());
if (status)
return Qt::Checked;
else
return Qt::Unchecked;
}
else
return QVariant();
}
bool STableModel::setData(const QModelIndex &index,
const QVariant &value, int role)
{
if (!index.isValid() /*|| role != Qt::EditRole*/)
return false;
if (role == Qt::CheckStateRole)
{
if ((Qt::CheckState)value.toInt() == Qt::Checked)
{
SFilterEditorData::instance().setStatus(index.row(),1);
return true;
}
else
{
SFilterEditorData::instance().setStatus(index.row(), 0);
return true;
}
}
i have referred this link: http://www.qtcentre.org/threads/39194-setEditorData()-for-QComboBox-Delegate

Can I convert bool in model to yes/no in a QComboBox

I have a database with a column value 0/1.
I use QSqlRelationalTableModel for showing data to widget.
Is it possible to show Yes for 1 and No for 0 in a QComoboBox?
And also, when I select yes/no, it should save to DB as 1/0.
Can I do something with setData() and getData() functions? Could someone give a clue how to start?
UPDATE:
mpCountryModel->setTable("CountryMaster");
mpCountryModel->select();
ui->comboBox->setModel(mpCountryModel);
ui->comboBox->setModelColumn(5);
As in column 5 has value 0 or 1, the same will display 0 and 1, right?
Is this any good?. This worked for me.
TableModel* model = new TableModel(this);
ui->comboBox->setModel(model);
ui->comboBox->setModelColumn(TableModel::BoolColumn);
//------------- tablemodel.h --------------------
QVariant data(const QModelIndex& index, int role) const;
int columnCount(const QModelIndex& ) const
{
return 2;
}
int rowCount(const QModelIndex& parentIndex) const
{
return parentIndex.isValid() ? 0 : 2;
}
//--------------------- tablemodel.cpp ----------------
QVariant TableModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid() || index.row() > 2) {
return QVariant();
}
switch (role) {
case Qt::DisplayRole:
case Qt::EditRole:
if (index.column() == 0)
return tr("Column %1").arg(index.column());
else
if (index.row() % 2 == 0)
return "Yes";
else
return "No";
default:
break;
}
return QVariant();
}
A complete example in literate programming style follows. Let's start with a header and common constants:
// https://github.com/KubaO/stackoverflown/tree/master/questions/proxy-combo-31995345
#include <QtWidgets>
#include <QtSql>
const QString kYes = QStringLiteral("Yes");
const QString kNo = QStringLiteral("No");
First of all, you have to translate the data from the database into form suitable for display and editing. For display, you need to map 0->No and 1->Yes. For editing, you need to map 0->false and 1->true so that the combo box editor is used. You need a proxy model:
/// Maps a given column from {0,1} to {false, true} for editing and {kNo, kYes} for display
class BoolProxy : public QIdentityProxyModel {
int m_column;
public:
BoolProxy(int column, QObject * parent = nullptr) :
QIdentityProxyModel{parent}, m_column{column} {}
QVariant data(const QModelIndex & index, int role) const override {
auto val = QIdentityProxyModel::data(index, role);
if (index.column() != m_column) return val;
if (role == Qt::DisplayRole || role == Qt::EditRole) {
if (val.toInt() == 0) {
if (role == Qt::DisplayRole) return kNo;
return false;
} else {
if (role == Qt::DisplayRole) return kYes;
return true;
}
}
return val;
}
bool setData(const QModelIndex & index, const QVariant & value, int role) override {
auto val = value;
if (index.column() == m_column && role == Qt::EditRole)
val = val.toBool() ? 1 : 0;
return QIdentityProxyModel::setData(index, val, role);
}
};
Secondly, you need to modify the entries displayed by the boolean combo box editor. By default they are "True" and "False". You need to change them to "Yes" and "No", respectively:
class YesNoDelegate : public QStyledItemDelegate {
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
auto ed = QStyledItemDelegate::createEditor(parent, option, index);
auto combo = qobject_cast<QComboBox*>(ed);
combo->setItemText(0, kNo);
combo->setItemText(1, kYes);
return ed;
}
};
Let's put these all together:
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
if (! db.open()) return 1;
db.exec("create table example (name text, inuse numeric);");
db.exec("insert into example (name, inuse) values "
"('Zaphod', 0), ('Beeblebrox', 1);");
QSqlTableModel model;
model.setTable("example");
model.select();
BoolProxy proxy{1};
proxy.setSourceModel(&model);
QTableView ui;
YesNoDelegate delegate;
ui.setItemDelegateForColumn(1, &delegate);
ui.setModel(&proxy);
ui.show();
return app.exec();
}

QAbstractItemModel data() is NEVER called

I'm attempting to create a QTreeView and use a custom model for it. I have placed qDebug() statements at various places, and I have determined that data() is never being called. How can I fix this problem?
The model's code is below
#include "ModelItemNeural.h"
ModelItemNeural::ModelItemNeural(QObject *parent, NeuralNode *rootNode)
: QAbstractItemModel(parent)
{
this->rootNode = 0;
}
QModelIndex ModelItemNeural::index(int row, int column, const QModelIndex &parent) const
{
// Out of bounds and null rootNode check.
if (rootNode == 0 || row < 0 || column < 0)
{
return QModelIndex();
}
NeuralNode* parentNode = nodeFromIndex(parent);
NeuralNode* childNode = parentNode->getInputs().value(row);
if (childNode == 0)
{
return QModelIndex();
}
return createIndex(row, column, childNode);
}
QModelIndex ModelItemNeural::parent(const QModelIndex &child) const
{
NeuralNode* node = nodeFromIndex(child);
if (node == 0)
{
return QModelIndex();
}
NeuralNode* parentNode = node->getParent();
if (parentNode == 0)
{
return QModelIndex();
}
NeuralNode* grandParentNode = parentNode->getParent();
if (grandParentNode == 0)
{
return QModelIndex();
}
int row = grandParentNode->getInputs().indexOf(parentNode);
return createIndex(row, 0, parentNode);
}
int ModelItemNeural::rowCount(const QModelIndex& parent) const
{
if (parent.isValid() == false)
{
return 0;
}
if (parent.column() > 0)
{
return 0;
}
NeuralNode* parentNode = nodeFromIndex(parent);
if (parentNode == 0)
{
return 0;
}
return parentNode->getInputs().length();
}
int ModelItemNeural::columnCount(const QModelIndex &parent) const
{
return 2;
}
QVariant ModelItemNeural::data(const QModelIndex &index, int role) const
{
qDebug() << "Data";
if (index.isValid() == false)
{
return QVariant();
}
if (role != Qt::DisplayRole)
{
return QVariant();
}
NeuralNode* node = nodeFromIndex(index);
if (node == 0)
{
return QVariant();
}
switch (index.column())
{
case 0:
{
// Stripping the name of the NeuralNode type.
QString name = typeid(node).name();
int index = name.indexOf(" ");
if (index >= 0)
{
name = name.remove(0, index + 1);
}
qDebug() << "Name Column";
return "Test";
return name;
}
case 1:
{
qDebug() << "Value Column";
return node->getWeight();
}
}
return QVariant();
}
QVariant ModelItemNeural::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
switch (section)
{
case 0:
{
return "Node";
}
case 1:
{
return "Weight";
}
}
}
return QVariant();
}
NeuralNode * ModelItemNeural::nodeFromIndex(const QModelIndex &index) const
{
if (index.isValid() == true)
{
//return (NeuralNode*)(index.internalPointer());
return static_cast<NeuralNode *>(index.internalPointer());
}
else
{
return rootNode;
}
}
void ModelItemNeural::setRootNode(NeuralNode *rootNode)
{
delete this->rootNode;
this->rootNode = rootNode;
reset();
}
The code from the MainWindow where the view is located is below.
#include "MainWindow.h"
#include "ui_MainWindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
NeuralNetwork* network = new NeuralNetwork();
modelNeural = new ModelItemNeural();
modelNeural->setRootNode(network);
ui->treeView->setModel(modelNeural);
update();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionNew_triggered()
{
NeuralNetwork* network = new NeuralNetwork();
modelNeural->setRootNode(network);
ui->treeView->update();
}
I should mention that the header does display for this model. However, even when I set an item, nothing is displayed in the widget save the header.
Oh and NeuralNetwork is a sub of NeuralNode.
The problem is this fragment:
int ModelItemNeural::rowCount(const QModelIndex& parent) const
{
if (parent.isValid() == false)
{
return 0;
}
You're basically saying that the root node (indicated by invalid parent index) has zero children i.e. the model has zero top-level rows. So the view queries no further.
Just drop this check and it should work. nodeFromIndex seems to handle root node correctly.
Did you add the model (not the item) to the treeview control?
Did you create items of your derived type and add them to the model?
data() should be called if your model is being accessed.
You have to override the following method in your QAbstractItemModel inherited class:
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
Then write this within:
return createIndex(row, column, nullptr);
Something like this:
QModelIndex index(int row, int column, const QModelIndex &parent) const {
return createIndex(row, column, nullptr);
}