QSortFilterProxyModel аварийно завершает работу при удалении строки из исходной модели через функцию исходной модели - PullRequest
3 голосов
/ 31 августа 2011

Я создал пользовательскую модель, производную от QAbstractItemModel, которая содержит набор XML-данных в древовидной иерархической форме, которые будут отображаться в QTreeView, как показано на следующем рисунке:

http://imageshack.us/photo/my-images/840/xmltreeview.png

Эта модель успешно прошла ModelTest и некоторые базовые тесты редактирования. Однако я столкнулся с некоторыми проблемами при попытке выполнить фильтрацию в этой модели, чтобы разделить модель на несколько разных видов. Я пытался QSortFilterProxyModel, и он много сбоев. После некоторого исправления он все еще падает после попытки удалить строку из модели.

Консольное приложение отображает эти сообщения при возникновении сбоя:

ratbr QModelIndex (0,0,0xd162000, CGHXmlModel (0xb197e68)) 0 0

rr QModelIndex (0,0,0xd162000, CGHXmlModel (0xb197e68)) 0 0

и это стек вызовов, когда произошел сбой:

0   QSortFilterProxyModelPrivate::index_to_iterator qsortfilterproxymodel.cpp   193 0x0134714b  
1   QSortFilterProxyModel::parent   qsortfilterproxymodel.cpp   1654    0x0111a677  
2   QModelIndex::parent qabstractitemmodel.h    389 0x6a2ad95e  
3   QPersistentModelIndex::parent   qabstractitemmodel.cpp  347 0x6a1f7320  
4   QItemSelectionRange::isValid    qitemselectionmodel.h   108 0x01341ea4  
5   QItemSelectionModel::isSelected qitemselectionmodel.cpp 1187    0x010f0b58  
6   QTreeView::drawRow  qtreeview.cpp   1602    0x010db133  
7   QTreeView::drawTree qtreeview.cpp   1441    0x010da4f4  
8   QTreeView::paintEvent   qtreeview.cpp   1274    0x010d9bed  
9   QWidget::event  qwidget.cpp 8333    0x00c1492d  
10  QFrame::event   qframe.cpp  557 0x00f8e6bc  
11  QAbstractScrollArea::viewportEvent  qabstractscrollarea.cpp 1043    0x0101bf0f  
12  QAbstractItemView::viewportEvent    qabstractitemview.cpp   1619    0x010a5785  
13  QTreeView::viewportEvent    qtreeview.cpp   1256    0x010d9aa3  
14  QAbstractScrollAreaPrivate::viewportEvent   qabstractscrollarea_p.h 100 0x01276a13  
15  QAbstractScrollAreaFilter::eventFilter  qabstractscrollarea_p.h 116 0x0127506c  
16  QCoreApplicationPrivate::sendThroughObjectEventFilters  qcoreapplication.cpp    847 0x6a1ffc73  
17  QApplicationPrivate::notify_helper  qapplication.cpp    4392    0x00bc96e5  
18  QApplication::notify    qapplication.cpp    4361    0x00bc9586  
19  QCoreApplication::notifyInternal    qcoreapplication.cpp    732 0x6a1ff9dc  
20  QCoreApplication::sendSpontaneousEvent  qcoreapplication.h  218 0x0123d53e

Я все еще довольно новичок в программировании на Qt Model / View, и эта ошибка действительно устрашала меня и заставляла меня чесать голову в течение нескольких дней. Я надеюсь, что кто-то здесь может помочь мне здесь, прежде чем я потеряю все свои волосы! Спасибо!

РЕДАКТИРОВАТЬ: обновить, чтобы включить некоторые исходные коды

Мой тестовый проект имеет два диалоговых окна, по одному QTreeView в каждом. Одним из них является главное окно, содержащее член класса, производного от QAbstractItemModel, а другое - дочернее окно, содержащее член класса, производного от QSortFilterProxyModel. Дочернее окно также имеет указатель QAbstractItemModel на фактическую модель.

Главное окно:

class CGHXMLModelDialog : public QDialog
{
    Q_OBJECT
...
private:
    Ui::CGHXMLModelDialog *ui;
    CGHXmlModel*            m_mainModel;
    CGHXMLParameterDialog*  m_ParamDialog;


...

}

Дочернее окно:

class CGHXMLParameterDialog : public QDialog
{
    Q_OBJECT
...

private:
    void setupProxyModel();

    Ui::CGHXMLParameterDialog*      ui;
    QAbstractItemModel*             m_coreModel;//A CGHXMLModel
    CGHXMLSortFilterProxyModel*     m_ParamModel;

...

}

В конструкторе CGHXMLModelDialog:

m_mainModel = new CGHXmlModel(theDomDocument, this);
ui->CGHXMLTreeView->setModel(m_mainModel);

//Create sub-dialog window containing proxy filter model
m_ParamDialog = new CGHXMLParameterDialog(m_mainModel, this);

, который затем вызывает метод setupProxyModel ():

CGHXMLParameterDialog::CGHXMLParameterDialog(QAbstractItemModel* coreModel, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::CGHXMLParameterDialog),
    m_coreModel(coreModel)
{
    ui->setupUi(this);
    setupProxyModel();
}

void CGHXMLParameterDialog::setupProxyModel()
{
    m_ParamModel = new CGHXMLSortFilterProxyModel(this);
    m_ParamModel->setSourceModel(m_coreModel);

    m_ParamModel->setFilterRegExp(QRegExp("Parameter"));
    m_ParamModel->setFilterKeyColumn(0);
    m_ParamModel->setDynamicSortFilter(true);

    ui->CGHXMLParamView->setModel(m_ParamModel);
}

Я протестировал вставку строк, редактирование содержимого строки, вставку атрибута XML с помощью редактирования столбца (пользовательская обработка столбца; я не буду подробно останавливаться) и т. Д. Непосредственно на исходной модели, и она работала как с использованием фильтра сортировки, так и без него. модель. Проблема возникает, когда я пытаюсь удалить «строку», которая является элементом XML для моей модели, когда к ней присоединена модель Sort-Filter.

Вот мой код для removeRows:

bool CGHXmlModel::removeRows(int rowposition, int rows, const QModelIndex &parent)
{
    CGHXMLTreeItem *parentItem = getItem(parent);
    bool success = false;

    beginRemoveRows(parent, rowposition, rowposition + rows - 1);
    success = parentItem->removeChildren(rowposition, rows);
    endRemoveRows();

    if(success)//Works!
    {
        emit layoutChanged();
    }

    return success;
}

, который вызывается обработчиком события кнопки в главном окне:

void CGHXMLModelDialog::on_deleteRowButton_clicked()
{
    QModelIndex currIndex = ui->CGHXMLTreeView->selectionModel()->currentIndex();

    if(!m_mainModel->removeRow(currIndex.row(), currIndex.parent()))
    {
        qDebug() << "Fail to remove row from Model.";
        return;
    }
}
//Program crashes after this function returns.

Обновление : Неправильно ли создавать layoutChanged () без использования layoutAboutToBeChanged ()?

Ответы [ 2 ]

1 голос
/ 01 сентября 2011

Я решил эту проблему, прокомментировав строку «emit layoutChanged ()» для моих методов insertRows, removeRows.Первоначально в коде не было этой строки, но проблема обновления с QTreeView заставила меня включить ее, не включая «emit layoutAboutToChanged ()».Кажется, проблема обновления почему-то исчезла.

В любом случае, спасибо тем, кто пытался помочь.Я обязательно буду нуждаться в большем количестве в ближайшем будущем.

1 голос
/ 31 августа 2011

Знаете ли вы, что индексы из QAbstractItemModel и QSortFilterProxyModel нельзя смешивать?

Если у вас есть QModelIndex из вашей модели filterProxy, то вам нужно преобразовать его в QModelIndex из модели элементов, используя QAbstractProxyModel :: mapToSource ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...