Основная идея развития

Здесь представлен свободный открытый проект развития классов QSqlTableModel и QTableView.

Почему это произошло. Надо признать, что после перепродажи прав на Qt примерно в 2012г.  никто впоследствие в общем-то по-видимому не планировал развивать и улучшать технологию модель-представление для работы с базами данных. А жаль, ведь все предпосылки для этого были. Но чтобы что-то развивать надо сначала хорошо изучить, что мы собираемся развивать, а с этим похоже и есть главная проблема ибо троли задрали планку очень высоко.

Поискав вдоволь по просторам интернета мы не нашли грамотного развития  концепции, которое решает вопросы с relational полями, изолирую программиста от каких-то дополнительных запросов к базе данных, чтобы получать id этих полей. Под relational полями мы подразумеваем текстовые подстановки из других таблиц по так называемому id связи. Это было изначально основным стимулом подумать как сделать так, чтобы при вставке строки, копировании строки все происходило без лишних усилий. Также при двойном клике по этому полю сразу открывалась таблица для выбора текста. Очевидные на первый взгляд вещи, но даже в QSqlRelationalTableModel троли не успели это реализовать.

В результате, поизучав исходники QtSql мы поняли - что мы хотим и главное как это сделать. Таким образом мы взяли на себя смелость предложить мировому сообществу один из вариантов развития концепции модель-представление.

Проект реализован из двух частей:
развитие модели данных в виде класса QpSqlTableModel и развитие модели представления в виде класса QpTableViewWrapper. Только открытое наследование, в исходниках самого Qt мы ничего не исправляли, хотя иногда и очень хотелось.

 

фотка 1

Для установки связи с внешней таблицей и реализации автоматической подстановки поля из другой таблицы мы предлагаем использовать метод setRelation. Все необходимые поля этой связи указываются как строки, то есть как наименования, никаких номеров колонок. Один раз вызываем после setTable и все.

А почему бы не добавить и какие-то вычисляемые поля по данным другой таблицы. Например общую сумму или количество продано товара. Для этого реализован метод setCalc

Вы можете в нем указать какую функцию вы используете: суммирование по колонке таблицы (sum), подсчет количества (count), и т.д. в соответствии с набором языка sql. Можно указывать и несколько колонок, по которым будет работать эта функция 

В версии начиная с 10.х к relational полям добавлена технология субучета. Это когда установка значения одного поля приводит к выбору значения для другого зависимого поля. Для этого надо один раз после setTable вызвать наш метод setSubAccounting и все.

Например выбор наименования одежды или обуви вызывает выбор размера.

Примечание: что останавливает использование Qt сегодня? То, что и вчера и позавчера - огромный объем  исходного кода. Выгода Qt становится очевидной только после изучения исходников. Чтобы понять логику и взаимосвязь классов уходит не один год, век живи век учись.

Что касается визуального представления  в  QpTableViewWrapper встроен поиск по колонкам таблицы и отбор по значению конкретного поля таблицы. Есть сортировка (по всем типам колонок).

В модели данных есть возможность указать выравнивание в ячейках. Можно указать количество точек после запятой для чисел с плавающей точкой.

Есть возможность встроить выпадающий список (QComboBox) в поле, есть вариант чекбокс для поля.

Развитие позволяет работать с всеми тремя стратегиями редактирования, которые можно переключать вручную из QpTableViewWrapper.

Конфигурирование

Идея в простоте. Структура постоянна и следовательно мы можем ее представить в виде static функций, которые для удобства доступа будут еще методами одного глобального класса. Для доступа к этим функциям в конструкторе модели данных передается указатель на этиу функцию.

Тогда например настройка связей и представления всех таблиц будет производится в одной паре файлов config.h/cpp  (конфигурирование базы данных)

Для каждого своего проекта, для своей структуры базы данных вы создаете свою пару config.h/cpp со своими настройками. 

Таким образом все конфигурирование базы данных отделено от основного функционала развития,  статично и констатно.

Примечание: проект тестируется пока только с SQLite3,  под Windows, на Qt 4.8.1.

Базовая идея развития представлена на картинке ниже. Переопределяется метод selectStatement и получаем любой нужный набор полей по данным многих таблиц.  Новая функция translateFieldNames обеспечивает исключение записи в базу данных сервисных и вычисляемых полей, просто проставляем им значение generated no.

фотка 2

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

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

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

А не сделать ли нам вообще свой QTableView, смотрите QTableView новые возможности.

Самый лучший способ правильно развивать классы это использовать их в боевых проектах. У нас есть первый наш коммерческий проект это БИТ драйвер ККТ и готовится более крупный проект следующий БИТ Сейл. Именно на них мы обкатываем функциональность нашего развития.

Небольшое отвлечение на тему - а правильный ли мы вообще сделали выбор в сторону фреймворка Qt здесь Почему наш выбор Qt