Russian Qt Forum
Ноябрь 23, 2024, 03:16 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Qt-4.5.2 поиск по образцу в QTreeView (иерархический справочник )  (Прочитано 11767 раз)
mal
Гость
« : Август 27, 2009, 10:23 »

Всем привет!

Ситуация следующая:
Для работы с иерархическим справочником (~200 тысяч записей) взял за основу пример simpletreemodel.
Для сортировки задал вью  QSortFilterProxyModel. И для управления выделением строк задал QItemSelectionModel.
Исходный список неотсортирован - сортирую A-Z.
Заглушил QTreeView::keyboardSearch , так как мне нужен сквозной поиск по образцу.
Образец для поиска задается пользователем: и, ив, ива ... и т.д.
При вводе каждой новой буквы беру образец, определяю текущую строку в TreeView, и зову match со следующей строки.
Код:
QModelIndex idx_cur = tree_view->currentIndex();
QModelIndex idx_next;
if(idx_cur.isValid())
idx_next = model->index(idx_cur.row() + 1, idx_cur.column());
else
idx_next = model->index(0,0);
...
QModelIndexList indexList = proxyModel->match(ind_ex, Qt::DisplayRole, var, 1, Qt::MatchStartsWith | Qt::MatchWrap | Qt::MatchRecursive);

if(indexList.count() > 0)
{
QModelIndex index = indexList.first();
if(index.isValid())
{
selectionModel->select(index, QItemSelectionModel::Select);
tree_view->scrollTo(index ,QAbstractItemView::PositionAtCenter);
slot_itemSelected(index);
selectionModel->setCurrentIndex(index, QItemSelectionModel::Select );
}
}

Образец поиска находится. При последующем поиске с тем же образцом, повторяю действия выше для поиска со следующей строки от текущей. Вроде бы все работает. И по идее при достижении конца списка поиск должен повториться с нулевой строки.

Но вот в чем проблема: поиск "зацикливается" внутри первых 3 веток иерархии. Т.е.  образец "и" выдает по кругу (предположим) строку "Ира"  в  ветках иерархий (предположим по годам) 1970, 1971, 1972. Т.е. поиск крутится внутри нескольких корневых веток по циклу, не выходя за них.
Хотя "Ира" присутствует также и во всех последующих корневых ветках справочника  - годах 1975,1976 и т.д.

Причем если задать поиск с hits = -1, то размерность QModelIndexList indexList - будет несколько тысяч, т.е. поиск поднимает все включения "Ир".  Но такой вариант мне не приемлем (найти все образцы за раз, а потом уже идти по таблице беря номера строк из готового indexList).
Так как быстрее найти 1-е включение, потом перейти на следующую строку, найти следующее включение и т.д.

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

 
« Последнее редактирование: Август 27, 2009, 11:05 от mal » Записан
mal
Гость
« Ответ #1 : Август 27, 2009, 23:51 »

Поковырялся немного. Вижу уже ошибку: при определении следующего индекса для поиска надо проверять есть ли дети у текущей строки.
Если есть, то "проваливаемся" глубже, если нет, то смотрим есть ли парент у текущей записи, проверяем сколько детей у парента, и если их больше, чем номер текущей строки, строим индекс для поиска увеличивая номер текущей строки, и  используем парент текущей строки

Код:
QModelIndex idx_cur = tree_view->currentIndex();
QModelIndex idx_next;
if( proxyModel->hasChildren( idx_cur ))
{
idx_next = proxyModel->index(0,idx_cur.column(), idx_cur); // дети есть  - проваливаемся глубже
}
else
{
QModelIndex idx_parent = proxyModel->parent(idx_cur);
if(idx_parent.isValid()) // парент есть?
{
int row = proxyModel->rowCount(idx_parent); // число детей у парента
if(idx_cur.row() < row) // число детей больше чем номер текущего ребенка
{
idx_next = proxyModel->index(idx_cur.row()+1, 0, idx_parent); // увеличиваем строку ребенка
}
}

}

правда пока не понял как выходить выше, если в текущей ветке не найдено больше строк с заданным образцом поиска, т.е.

Код:
QModelIndexList indexList = proxyModel->match(idx_next , Qt::DisplayRole, var, 1, Qt::MatchStartsWith | Qt::MatchWrap | Qt::MatchRecursive);
if(indexList.count() == 0)
{
// что то делать - как то выходить вверх по текущей иерархии
}
роюсь дальше.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #2 : Август 28, 2009, 08:22 »

idx_next.parent?
Записан
mal
Гость
« Ответ #3 : Август 28, 2009, 10:57 »

Авварон
нет это понятно, вопрос скорее алгоритмический:

стоим мы на текущей строке, у нее есть дети. образец для поиска не меняется - т.е. по акселератору продолжаем поиск с тем же образцом.
Случилось так, что внутри иерархии текущей строки, не нашлось строки совпадающей с образцом поиска. Т.е. indexList.count() == 0.
Текущая строка не сменилась. В теории надо сдвинуться дальше по текущему уровню иерархии и повторить поиск. Если текущая строка в иерархии последняя - вернуться на уровень выше ( если есть парент) или, если текущая строка последняя в корневой иерархии - вернуться на начало таблицы и повторить поиск с индексом idx_next = proxyModel->index(0,0)
Далее возникает вопрос как не свалиться в бесконечный цикл, если искомой строки в списке нет вовсе.
Например мы стоим где то внутри  списка и задаем имя начинающееся с твердого знака. Такой строки в таблице нет.
----
Хотя наверно если поиск шел сначала списка  и не нашлось искомых совпадений - тут и  поиску конец.  Улыбающийся
« Последнее редактирование: Август 28, 2009, 11:10 от mal » Записан
BRE
Гость
« Ответ #4 : Август 28, 2009, 11:00 »

Далее возникает вопрос как не свалиться в бесконечный цикл, если искомой строки в списке нет вовсе.
Например мы стоим где то внутри  списка и задаем имя начинающееся с твердого знака. Такой строки в таблице нет.
Можно запомнить строку (индекс) с которой начался поиск (по данной маске) и если мы опять пришли к ней, обойдя все дерево, остановиться.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #5 : Август 28, 2009, 11:27 »

что-то тут явно не так:( зачем искать в текущей, если в случае облома мы все равно обходим все дерево?
added: а, то есть результат из текущей ветки приоритетней? тут 2 способа - либо искать в ней, а затем сразу с корня, либо искать с корня все похожие и смотреть чтобы результат был внутри нужной ветки
« Последнее редактирование: Август 28, 2009, 11:29 от Авварон » Записан
mal
Гость
« Ответ #6 : Август 28, 2009, 11:33 »

"...Хотя наверно если поиск шел сначала списка  и не нашлось искомых совпадений - тут и  поиску конец.  Улыбающийся ..."
это конечно бред

Авварон

а что ты предлагаешь?
у текущей есть дети, у которых в свою очередь детей уже нет (последний уровень иерархии для текущей ветки) и среди этих детей искомого образца не найдено. Надо двигаться дальше насквозь через всю таблицу.
Вероятно, надо сделать так, как советует BRE .

Авваарон
Цитировать
added: а, то есть результат из текущей ветки приоритетней? тут 2 способа - либо искать в ней, а затем сразу с корня, либо искать с корня все похожие и смотреть чтобы результат был внутри нужной ветки

да конечно - нужно найти ближайшее включение внутри текущей иерархии, и если оно не найдено - перемещаться на другие корни
« Последнее редактирование: Август 28, 2009, 11:36 от mal » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #7 : Август 28, 2009, 11:41 »

хм, ближайшее или любое, кроме внутритекущего? возможно что рекурсивное понятие вверх и имеет смысл
Записан
mal
Гость
« Ответ #8 : Август 28, 2009, 12:00 »

Авварон

ближайшее от текущего положения вниз, потом, при следующем поиске, ближайшее от найденного и т.д. по кругу Улыбающийся
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #9 : Август 28, 2009, 12:19 »

не найденного?
Записан
mal
Гость
« Ответ #10 : Август 28, 2009, 12:26 »

Авварон

предположим в списке есть 10 идентичных строк в разных уровнях иерархии. В том числе и в разных подуровнях от главного корня.
Юзер ввел строку "Ира". Жмет искать. Находим самую первую "Иру" от текущего положения в списке. Найденную строку делаем текущей (скролимся к ней, выделяем ее)
Жмет искать еще раз - находим следующую "Иру" ближайшую и т.д.
*Ищем от текущего места вглубь иерархии если дети есть, если нет детей  - переходим на следущую строку в текущей иерархии и ведем поиск от нее. Если текущая строка последняя в текущей иерархии - поднимаемся на уровень выше, перемещаемся на следущую строку в этом уровне и снова *.

Таким образом обходим все дерево.

А если во всем дереве не нашлось искомого образца - прерываем поиск как советовал BRE.
Вот так я все это вижу.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #11 : Август 28, 2009, 12:29 »

а я так понял, что мы ищем один раз, и поднимаемся вверх только если в текущей ветке ничего не нашли...
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.055 секунд. Запросов: 23.