Russian Qt Forum

Qt => Model-View (MV) => Тема начата: dxp от Июнь 06, 2011, 09:06



Название: Логика взаимодействия между QSqlTableModel, QTableView и его делегатом
Отправлено: 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.


Название: Re: Логика взаимодействия между QSqlTableModel, QTableView и его делегатом
Отправлено: pokidoff от Июнь 06, 2011, 09:40
По первому вопросу.
Попробуй ловить у модели сигнал modelAboutToBeReset, записываеть во временную переменную tableView->selectionModel(), а по сигналу modelReset восстанавливать модель выделения. Или посмотри еще какие-нибудь сигналы, по которым можно сохранить текущее выделение и позже восстановить его.


Название: Re: Логика взаимодействия между QSqlTableModel, QTableView и его делегатом
Отправлено: dxp от Июнь 07, 2011, 07:29
Спасибо за ответ. К сожалению, сигнал modelAboutToBeReset() (как и modelReset()) не ловятся - видимо, ресета не происходит при синхронизации с базой. Буду копать дальше, искать подходящие сигналы. Мне, собсно, нужен сигнал, эмиттируемый по окончании синхронизации. Выцепить состояние виджетов до того я могу по сигналу делегата commitData().


Название: Re: Логика взаимодействия между QSqlTableModel, QTableView и его делегатом
Отправлено: dxp от Июнь 07, 2011, 11:00
Вот тут http://www.prog.org.ru/topic_14599_0.html, вроде, говорят, что есть решение. Только оно не работает (там оба сигнала эмиттятся ещё до синхронизации с базой).


Название: Re: Логика взаимодействия между QSqlTableModel, QTableView и его делегатом
Отправлено: dxp от Июнь 09, 2011, 09:47
Обнаружил такую фичу: если в модели добавить пустую строку, то вся логика работы начинает соответствовать желаемому. Чудесато.


Название: Re: Логика взаимодействия между QSqlTableModel, QTableView и его делегатом
Отправлено: sarbash от Июнь 17, 2011, 11:13
Надо же, я как раз сейчас занимался этой проблемой, почему и забрёл на форум. Спасибо, dxp, за наводку по проблеме с фокусом, вот не думал, что такой глупый баг.
У меня ещё интереснее задача - в строке должно быть непустое значение. В связи с чем, при добавлении новых строк получаются неожиданные эффекты. Один из вариантов обойти проблему, - при добавлении новых строк подставлять какое-нибудь умолчательное значение, чтобы изначально ячейка непустая была. Другого пока не придумал...


Название: Re: Логика взаимодействия между QSqlTableModel, QTableView и его делегатом
Отправлено: dxp от Июнь 17, 2011, 16:24
Надо же, я как раз сейчас занимался этой проблемой, почему и забрёл на форум. Спасибо, dxp, за наводку по проблеме с фокусом, вот не думал, что такой глупый баг.
Скорее это не баг, а фича. Только не документированная должным образом.

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