QSortFilterProxyModel с QStandardItemModel после appendRow не работают

Вот что у меня есть:

  • виджет QTreeView (*);
  • Исходная модель MainModel наследуется от QStandardItemModel. Виртуальный метод data() const не перереализован;
  • Прокси MainFilterProxyModel наследуется от QSortFilterProxyModel;

Дерево:

[PERIOD 1]
   [CHILD 1]
   [CHILD 2]
      [SUBCHILD 2.1]
      ...
   [CHILD N]
[PERIOD 2]
...
[PERIOD N]

Итак, основная проблема возникает, когда я пытаюсь добавить CHILD-row, как это делает (**) код. Модель прокси фильтра после добавления документа в исходную модель не знает о новой строке и не показывает ее в дереве.

Я уверен, что прокси не получил сигнал от QStandardItemModel, когда метод appendRow выполняет свою работу, поэтому прокси не может фильтровать новую строку и не делает ее видимой.

Любая помощь?

Спасибо.

PS: Если я отключу прокси, все будет добавлено просто отлично. Но проблема не в прокси. Прокси просто не получает сигнал о добавлении новой строки к основной исходной модели...


(*) Вот QTreeView:

MainView::MainView( QWidget* parent /* = 0 */ ) : QTreeView( parent )
{
     if( !model_ )
     {
          model_ = new MainModel( this );
     }

     if( !proxy_ )
     {
          proxy_ = new MainFilterProxyModel( this );
          proxy_->setDynamicSortFilter( true );
          proxy_->setSourceModel( model_ );

          setModel( proxy_ );
     }
}

(**) Вот моя функция добавления:

void MainModel::addRow( const DocumentPtr& document, QStandardItem* parentItem )
{
     assert( document );

     QList< QStandardItem* > items;
     items << ( new QStandardItem );
     items << ( new QStandardItem );
     items << ( new QStandardItem );
     items << ( new QStandardItem );
     items << ( new QStandardItem );
     items << ( new QStandardItem );
     items << ( new QStandardItem );

     updateRow( document, items );

     if( !parentItem )
     {
          BOOST_FOREACH( const TimePeriod& period, TimePeriod::all() )
          {
               if( period.contains( QDateTime::fromTime_t( document->creationDate() ) ) )
               {
                    QStandardItem* periodItem = itemByPeriod( period );
                    Q_ASSERT( periodItem );

                    periodItem->appendRow( items );

                    break;
               }
          }
     }
     else
     {
          parentItem->appendRow( items );
     }
}

person mosg    schedule 01.08.2012    source источник
comment
В представленном примере вы добавляете элементы не к модели, а к QStandardItems, которые вы получаете способом, не видимым в примере. Можете ли вы упростить свой код, чтобы он выглядел полностью и при этом воспроизводимым со сбоями?   -  person Pavel Zdenek    schedule 01.08.2012
comment
@vtmarvin Я не очень понимаю, что мне нужно делать, но я помещаю исходный файл сюда: pastebin.com/RMLqHZhS Надеюсь на помощь!   -  person mosg    schedule 01.08.2012
comment
хорошо, если вы даже не показываете код MainFilterProxyModel, как мы должны увидеть, почему он не получает сигнал?   -  person    schedule 04.08.2012
comment
@нус Ты прав. Вот заголовок прокси ( pastebin.com/pjYsLVs4 ) и источник ( pastebin.com/udTPS0c6 ) файлы...   -  person mosg    schedule 06.08.2012
comment
@mosg Я все еще не могу следить за ходом вашей программы, потому что отсутствует main-model.h. Что такое model_ и proxy_? Являются ли они членами данных? Вы пытались заменить свой собственный прокси на стандартный, чтобы увидеть, в чем ошибка: в вашем прокси или в вашей основной модели?   -  person    schedule 06.08.2012


Ответы (1)


Базовый класс для моделирования — QAbstractItemModel. Лучше использовать методы абстрактного класса, чтобы делать то, что вы хотите. QStandardItemModel представляет собой простую реализацию абстрактных методов QAbstractItemModel, а большинство QStandardItemModel новых методов используются повторно реализованными абстрактными функциями. Вот код для добавления элемента и подэлемента с использованием методов абстрактного класса:

QAbstractItemModel * pModel = new QStandardItemModel(parent);

int nRows = pModel->rowCount();
pModel->insertRow(nRows); // this will emit rowsAboutToBeInserted() and rowsInserted() signals
pModel->insertColumn(0); // this will emit columnsAboutToBeInserted() and columnsInserted() signals
const QModelIndex indexFirstItem = pModel->index(nRows, 0);
pModel->setData(indexFirstItem, "Item text"); // this will emit dataChanged() signal
int nChildRows = pModel->rowCount(indexFirstItem);
pModel->insertRow(nChildRows, indexFirstItem); // this will emit rowsInserted()
pModel->insertColumn(0, indexFirstItem); // we also need to do this for the item's children
const QModelIndex indexChild = pModel->index(nChildRows, 0, indexFirstItem);
pModel->setData(indexChild, "Child item text");

Если мы попытаемся сделать то же самое, используя методы QStandardItemModel, это будет выглядеть так:

QStandardItemModel *pModel = new QStandardItemModel(parent);
QStandardItem *pItem = new QStandardItem("Item text");
pItem->appendRow(new QStandardItem); // pItem is not yet added to pModel and rowsInserted won't be emitted
pModel->appendRow(pItem); // this will probably emit rowsInserted() signal but since we set tha text of the item when creating the pItem the dataChanged() signal won't be emitted.

Таким образом, если вы делаете pItem->appendRow() для добавления подэлементов и если pItem еще не добавлен в модель, вы, вероятно, не получите сигнал rowsInserted() и, следовательно, прокси-модель не будет уведомлена. По моему опыту, первый метод работает лучше и надежнее, хотя вам нужно написать пару дополнительных строк. Работа непосредственно с методами QStandardItemModel часто заканчивается отсутствием сигналов или другими головными болями. Все, что вам нужно, это просмотреть документацию QAbstractItemModel и QModelIndex.

person Uga Buga    schedule 30.04.2013