[Solved]QSortFilterProxyModel Crashes
-
I have Data->QAbstractTableModel->QSortFilterProxyModel->QTableView.
But if I show then hide a column, click a cell, QSortFilterProxyModel crashes on mapToSource().
Could anyone help, please?Thanks
#include <QAbstractItemModel> ProxyModel::ProxyModel(QObject *parent) : QSortFilterProxyModel(parent) { } bool ProxyModel::isMaxMinShown() const { return _isMaxMinShown; } void ProxyModel::setIsMaxMinShown(bool isMaxMinShown) { _isMaxMinShown = isMaxMinShown; } bool ProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { return true; } bool ProxyModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const { if(source_column==1){ return _isMaxMinShown; } return true; }
TableModel
Vm::Vm(QObject *parent) : QAbstractTableModel(parent) { } int Vm::rowCount(const QModelIndex &parent) const { return 20; } int Vm::columnCount(const QModelIndex &parent) const { return 5; } QVariant Vm::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role == Qt::DisplayRole) { switch(index.column()){ case 0: // name return QString::number(index.row()); case 1: // min return 0.1; case 2: // percentage return 0.2; case 3: // max return 0.3; case 4: // LOD or sigma return 0.4; } } // back ground if(role == Qt::TextAlignmentRole){ return Qt::AlignCenter; } return QVariant(); } QVariant Vm::headerData(int section, Qt::Orientation orientation, int role) const { if(role == Qt::DisplayRole && orientation == Qt::Horizontal){ switch(section){ case 0: return tr("A"); case 1: return tr("B"); case 2: return tr("C"); case 3: return tr("D"); case 4: return "E"; } } return QVariant::Invalid; } Qt::ItemFlags Vm::flags(const QModelIndex &index) const { if(index.isValid()){ return Qt::ItemIsEnabled; } return Qt::NoItemFlags; }
MainWindow
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); _proxyModel = new ProxyModel(this); _vm = new Vm(this); _proxyModel->setSourceModel(_vm); ui->tableView->setModel(_proxyModel); //QScroller::grabGesture(ui->tableView, QScroller::LeftMouseButtonGesture); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { _proxyModel->setIsMaxMinShown(!_proxyModel->isMaxMinShown()); emit _vm->layoutChanged(); }
-
Hi,
You should run your application through the debugger, it will show you the exact point of crash.
Note that you are doing something wrong: you are trying to emit a signal from another class.
-
@SGaist
Depends on mouse click cell first or show/hide column first, I got this two stack.
And disassember shows, don't know how to show code yet.
And here is the project if anyone could try it.
Tested with (Qt 5.3 linux, qt5.5 linux, qt5.5 windows)
Sometimes crash on parent();
0 QSortFilterProxyModel::parent(QModelIndex const&) const 0x7ffff70f9ced
1 QPersistentModelIndex::parent() const 0x7ffff70d8d73Sometimes crash on here,
0 QSortFilterProxyModelPrivate::index_to_iterator D:/Qt/5.5/mingw492_32/bin/Qt5Cored.dll 187 0x114d743
1 QSortFilterProxyModelPrivate::proxy_to_source D:/Qt/5.5/mingw492_32/bin/Qt5Cored.dll 376 0xfb3536
2 QSortFilterProxyModel::mapToSource D:/Qt/5.5/mingw492_32/bin/Qt5Cored.dll 2718 0xfbab5f
3 QSortFilterProxyModel::flags D:/Qt/5.5/mingw492_32/bin/Qt5Cored.dll 2200 0xfb9ae1 -
@SGaist
Found a work around.
Clear proxy model first, then set source model again._proxyModel->clear(); _proxyModel->setIsMaxMinShown(!_proxyModel->isMaxMinShown()); _proxyModel->setSourceModel(_vm); emit _vm->layoutChanged(); // change this to emit from vm class.
-
@sharethl
Clear and set source model again still have chances to crash..... -
@sharethl
Remove this line working
emit _vm->layoutChanged(); // change this to emit from vm class. -
to update your table, you better use
emit dataChanged(modelIndexFrom, modelIndexTo);
-
Are you sure _vm is not null ? And again, don't call emit on other classes like that, it feels like your doing some bad design.
-
You have to emit layoutAboutToBeChanged() before you change your model
and emit layoutChanged after your model changes to reflect the changes to the ui
(see documentation void QAbstractItemModel::layoutChanged())some code
void MainWindow::on_pushButton_clicked() { _vm->tellLayoutAboutToBeChanged(); _proxyModel->setIsMaxMinShown(!_proxyModel->isMaxMinShown()); _vm->tellLayoutChanged(); } void Vm::tellLayoutChanged() { emit layoutChanged(); } void Vm::tellLayoutAboutToBeChanged() { emit layoutAboutToBeChanged(); }
-
That design is completely wrong. It's the responsibility of the model to know when to emit anything. The proxy will make the signals follow. It's not the role of MainWindow at all to call these functions.
-
@SGaist Yes, bad design, will correct this.
-
@SGaist
You are absolutely right.
But the question was for the reason the application crashes.The reason for the crash is not the architecture but the missing layoutAboutToBeChanged()
-
Still, that call is not done at the right place, so you're currently just lucky it works.