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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Логика взаимодействия между QSqlTableModel, QTableView и его делегатом  (Прочитано 5241 раз)
dxp
Гость
« : Июнь 06, 2011, 09:06 »

Ситуация следующая. Есть таблица БД, которая редактируется через связку QTableView/QSqlTableModel. От этой связки хочется поведения, присущего обычной таблице a-la Excel - т.е. редактируем элемент, выходим из режима редактирования либо по нажатию Enter, либо при переходе в другую ячейку, например, нажав Down (или Up). При этом, если нажат Enter, то текущая ячейка и должна оставаться выбранной. А при переходе в другую ячейку, текущей должна быть эта, в которую перешли.

В режиме по умолчанию вышеописанная функциональность не получается. При нажатии на Enter фокус уходит непонятно куда, и редактировать эту же ячейку (или просто одним действием выбрать соседнюю) сходу не получается. А при переходе на другую ячейку фокус остаётся на объекте QTableView, но её текущий модельный индекс слетает в невалидное состояние (выдаёт координаты -1, -1).

Эксперименты показали, что это поведение возникает исключительно из-за взаимодействия с БД. Т.е. из-за того, что модель скидывает изменения в БД и обновляет содержимое себя через select(). Иными словами, если установить стратегию редактирования QSqlTableModel в OnManualSubmit, то пока синхронизации с базой нет (она принудительная в этом случае), то модель/таблица ведут себя отлично - всё как желается, интуитивное поведение для таблиц выполняется.

Если включить синхронизацию с базой, то после select() поведение нарушается. Главным образом из-за ухода фокуса и сброса модельного индекса текущего элемента. С фокусом оказалось всё достаточно просто - при нажатии на Enter редактирование в делегате завершается, а фокус почему-то остаётся на объекте делегата. Не знаю, баг это или фича, в документации ничего на этот счёт не нашёл. Хотя то, что в режиме без синхронизации такого не происходит и с фокусом всё в порядке, наводит на мысль. что что-то там не то. Поведение, насколько понимаю, должно быть одинаковым, чтобы для пользователя было прозрачно с какой моделью он работает - QTableModel или QSqlTableModel. Обойти это оказалось довольно просто - достаточно в слоте, обрабатывающем сигнал от делегата commitData(), установить фокус обратно на объект QTableView.

А вот с вариантом завершения редактирования при переходе к другой ячейке всё оказалось как-то более сложно. Там в процессе синхронизации модели с базой сбрасывается модельный индекс текущей ячейки. Где это происходит, не нашёл. Обойти просто тоже не получается - тут надо, чтобы код, который делает синхронизацию и сброс модельного индекса, как-то информировал об окончании этого процесса - тут можно было бы текущий индекс установить в нужное значение. Но как это сделать (просигналить об окончании), не нашёл.

В связи с этим пара вопросов.

1. Возможно ли каким-то вменяемым путём добиться функционирования таблицы, синхронизирующейся с базой, ровно такого же, как у таблицы, модель которой хранит данные в себе? Или тут ничего не поделать и если хочется вышеописанного поведения, то лучше оставить стратеию OnManualSubmit и делать синхронизацию отдельной командой?

2. Проверил два сигнала от делегата - closeEditor и commitData(). Оказалось, что в обоих случаях завершения редактирования (по Enter и при переходе к другой ячейке) срабатывает только слот на commitData(), а на closeEditor() не срабатывает. Вопрос: closeEditor - это что за событие? Разве при завершении редактирования редактор не закрывается?

P.S. Версия Qt: 4.6.3.
Записан
pokidoff
Гость
« Ответ #1 : Июнь 06, 2011, 09:40 »

По первому вопросу.
Попробуй ловить у модели сигнал modelAboutToBeReset, записываеть во временную переменную tableView->selectionModel(), а по сигналу modelReset восстанавливать модель выделения. Или посмотри еще какие-нибудь сигналы, по которым можно сохранить текущее выделение и позже восстановить его.
Записан
dxp
Гость
« Ответ #2 : Июнь 07, 2011, 07:29 »

Спасибо за ответ. К сожалению, сигнал modelAboutToBeReset() (как и modelReset()) не ловятся - видимо, ресета не происходит при синхронизации с базой. Буду копать дальше, искать подходящие сигналы. Мне, собсно, нужен сигнал, эмиттируемый по окончании синхронизации. Выцепить состояние виджетов до того я могу по сигналу делегата commitData().
Записан
dxp
Гость
« Ответ #3 : Июнь 07, 2011, 11:00 »

Вот тут http://www.prog.org.ru/topic_14599_0.html, вроде, говорят, что есть решение. Только оно не работает (там оба сигнала эмиттятся ещё до синхронизации с базой).
Записан
dxp
Гость
« Ответ #4 : Июнь 09, 2011, 09:47 »

Обнаружил такую фичу: если в модели добавить пустую строку, то вся логика работы начинает соответствовать желаемому. Чудесато.
Записан
sarbash
Гость
« Ответ #5 : Июнь 17, 2011, 11:13 »

Надо же, я как раз сейчас занимался этой проблемой, почему и забрёл на форум. Спасибо, dxp, за наводку по проблеме с фокусом, вот не думал, что такой глупый баг.
У меня ещё интереснее задача - в строке должно быть непустое значение. В связи с чем, при добавлении новых строк получаются неожиданные эффекты. Один из вариантов обойти проблему, - при добавлении новых строк подставлять какое-нибудь умолчательное значение, чтобы изначально ячейка непустая была. Другого пока не придумал...
Записан
dxp
Гость
« Ответ #6 : Июнь 17, 2011, 16:24 »

Надо же, я как раз сейчас занимался этой проблемой, почему и забрёл на форум. Спасибо, dxp, за наводку по проблеме с фокусом, вот не думал, что такой глупый баг.
Скорее это не баг, а фича. Только не документированная должным образом.

У меня ещё интереснее задача - в строке должно быть непустое значение. В связи с чем, при добавлении новых строк получаются неожиданные эффекты. Один из вариантов обойти проблему, - при добавлении новых строк подставлять какое-нибудь умолчательное значение, чтобы изначально ячейка непустая была. Другого пока не придумал...
Может, это как-то связано со свойствами таблицы? В частности, у меня при создании таблицы идёт параметр NOT NULL, т.е. сервер не проверяет поля на предмет заполненности. Посмотрите ваши настройки. Тут на стыке этих "наук" могут быть эффекты любой степени удивительности.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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