Russian Qt Forum

Qt => Model-View (MV) => Тема начата: Serega от Апрель 20, 2015, 21:18



Название: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 20, 2015, 21:18
Для QFileSystemModel есть метод setNameFilters для фильтрации по списку.
Подскажите пожалуйста как организовать подобное для QSortFilterProxyModel + QListView?


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 21, 2015, 05:15
Решил вопрос переопределением метода filterAcceptsRow:
Код
C++ (Qt)
bool ProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
 QStringList filterList;
 filterList << "expression1" << "expression2"<< "expression3";
 return filterList.contains(sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).toString());
}
Есть ли еще более оптимальные решения?


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: ksk- от Апрель 21, 2015, 07:09
Решил вопрос переопределением метода filterAcceptsRow:

Насколько я помню, это именно так и делается.


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Fregloin от Апрель 21, 2015, 09:48
несколько замечаний
по первых вместо списка лучше использовать QSet<QString>, который намного быстрее выполняет contains(). Проверено на личном опыте, в разы быстрее.
Из QListWidget можно получить методом QSet::fromList<QString>(list).
и сделать ваш qset члентом класса для более быстрого доступа (хотя может вы просто код упростили).


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 21, 2015, 10:01
Спасибо! Мне как раз как воздух необходимы советы по оптимизации кода. Личная практика очень мала, а кодидь хочется сразу правильно.


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 21, 2015, 11:11
По поводу второго совета.
В ригинале QStringListModel + QListView - хранит поступающие данные. Необходимо организовать различную фильтрацию. Использую QSortFilterProxyModel.


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 22, 2015, 09:04
Если добавляю в Model (QListView) новое слово, то в ProxyModel изменения происходят параллельно.
При добавлении нового слова в фильтрующий список QSet или при его смене, изменей в ProxyModel нет пока не дабавлю новое слово в основную модель.
Как поправить?


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 22, 2015, 09:30
После смены фильтрующего списка QSet, вызвал метод invalidateFilter ();. Вроде как работает.
Подскажите правильно ли я понял этот метод?
Код
C++ (Qt)
void ProxyModel::openFilterFile( QString const & name )
{
 m_filterSet.clear();
 
 QFile file(name);
 if (file.open(QIODevice::ReadOnly)) {
   QTextStream stream(&file);
   while (!stream.atEnd()) {
     QString line = stream.readLine();
     m_filterSet.insert(line);
   }
 }
 
 invalidateFilter ();
}


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Fregloin от Апрель 23, 2015, 09:22
если работет, то правильно  :)


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 23, 2015, 10:10
Работает та без проблем. Но может этот метод просто выдает какой сигнал, который обновляет представление, а сам предназначен для чего то иного. Честно не осознал для чего. Работает, но не хотелось бы что бы что то работало в холостую. Хотелось бы использовать именно то, что для этого и предназначено.


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 24, 2015, 09:36
Основной список несортирован.
При установке прокси список так же не сортирован.
Создаю меню - Сортровать по алфавиту. Здесь все в порядке.

Создаю меню - Отменить сортировку. Как вернуть в исходное состояние Проксимодель? Метод invalidate() не помогает.


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: gil9red от Апрель 24, 2015, 09:47
Исходное состояние у вас есть в QStringListModel


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 24, 2015, 10:13
К сожалению не осознал.
Для прокси свое окно. И повторная установка оригинальной модели не дает результат:
m_proxyModel->setSourceModel(m_sourseModel);
m_proxyList->setModel(m_proxyModel);


Даже если перед этим поставть метод invalidate();


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 24, 2015, 12:09
Сбрость m_proxyModel не удается.
Создал слот:
Код
C++ (Qt)
void proxyPaneWidget::noSortProxy()
{
 m_proxyModel = new ProxyModel( this );
 m_proxyModel ->setSourceModel( m_sourseModel );
 m_proxyList->setModel( m_proxyModel );
}

Однако изначально m_proxyModel инициализируется в конструкторе, таким же образом: m_proxyModel = new ProxyModel( this );.
Насколько корректно такое решение и какими неприятностями оно может грозить? Может ли привести к утечке памяти? И может все таки можно как то сбросить исходную модель? Метод reset() не помогает и invalidate() вроде как отвечает за сброс сортировки, так же почему то не срабатывает. Какие могут быть ошибки?


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 26, 2015, 14:34
Еще заморочка. Комбинирую фильтр с RegExp. Ловлю QString со строки ввода. И тут все в порядке:
Код
C++ (Qt)
bool proxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
 QString word = sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).toString();
 
 if(m_filterSet.contains(word))
 {
   QRegExp rx(filterRegExp().pattern(), Qt::CaseInsensitive, QRegExp::WildcardUnix);
 
   emit proxyDataChanged(); //HOW TO DO
 
   return word.contains(rx);
 }
 return false;
}

Но необходимо обновить счетчик пойманных слов в другом объекте. Отправляю сигнал emit proxyDataChanged();. Однако с этого переопределенного слота сигнал не отправляется. Как быть?


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Апрель 26, 2015, 14:56
Хорошо. Выкрутился снова:
Код
C++ (Qt)
 connect( m_proxyLineEdit, SIGNAL( textChanged( QString const & ) ),
          m_proxyModel, SLOT( setFilterWildcard( QString const & ) ) );
 
 connect( m_proxyLineEdit, SIGNAL( textChanged( QString const & ) ),
          m_proxyModel, SIGNAL( proxyDataChanged() ) );

Но как то не совсем интуитивно по поводу приоритета сигналов. Может ли случиться, сначала перерасчет счетчика, а затем фильтрация?
Но тем не менее работает правильно.


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Май 01, 2015, 06:58
Как то весьма не эффективно получается такое переопределение (намеренно упростил):
Код
C++ (Qt)
bool ProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
 QString word = sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).toString();
 qDebug() << "word" << word;
 
 return true;
}
При добавлении нового пункта в список, весь список идет полностью по кругу через фильтр.
Или это происходит потому, что пункт добавляю в модель-источник?


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Май 02, 2015, 18:04
Все таки не удается толком сбросить фильтрацию прокси модели после упорядочивания по возрастанию или убыванию. Сброс простой. emit resetFilter(); отсылает сигнал прокси модели выдать invalidate();. Далее перезаряжаем список источника m_sourse->importFromFile( m_ExportPath );:
Код
C++ (Qt)
void ProxyPaneWidget::resetProxy()
{
 emit resetFilter();
 m_sourse->importFromFile( m_ExportPath );
}

Код
C++ (Qt)
void ProxyModel::clearFilterSet()
{
 invalidate();
 reset();
}
reset(); - то же пробовал на всякий случай.
Список источника перезаряжается, что ведет к исходному упорядочиванию в виджете представления прокси модели.
Однако при добавлении очередного пункта в источник, автоматически весь список снова сортируется по возрастанию или убыванию в зависимости, что до этого было установлено. Т.е. invalidate(); не работает как ожидалось.
Иными словами не удается отменить сортировку.
В чем может быть ошибка?


Название: Re: QSortFilterProxyModel - фильтр по списку
Отправлено: Serega от Май 02, 2015, 18:56
Снова способ проб и ошибок дал результат. Все очень просто, не надо даже перезаряжать модель-источник. Но как то халтурно:
Код
C++ (Qt)
void ProxyPaneWidget::resetProxy()
{
 m_proxyModel->sort(1);
}