Програмування Qt 4
Продовжимо знайомство з парадигмою модель-вид, реалізованою в Qt 4. Приклад попередньої статті був, мабуть, занадто простим для того, щоб ви могли відчути переваги системи Interview Framework. На цей раз ми ускладнимо нашу базу даних та програми, призначені для роботи з нею. Тепер замість однієї таблиці ми матимемо три.
Малюнок 1. Структура тестової бази даних
Мітка PK вказує, що це поле є первинним ключем таблиці, мітка FK позначає зовнішні ключі. Жирним шрифтом виділено поля, які можуть мати порожні значення. Стрілки вказують на зв'язки, створені між таблицями за допомогою зовнішніх ключів.
Крім таблиць, ми створюємо уявлення view_all, яке зводить повну інформацію про кожну композицію в одну таблицю.
Подивимося тепер уявлення таблиці compositions з допомогою моделі QSqlQueryModel, як у прикладі з попередньої статті (рис. 2). Дані виглядають приблизно так, як вони зберігаються в таблиці БД (тільки порожнє значення поля album_id у другому рядку замінено неіснуючим індексом 0), проте з погляду користувача таке подання даних не можна назвати задовільним.
Малюнок 2. Відображення таблиці compositions файл pic2.png.
При показі даних користувачеві бажано замінити посилання записи таблиць albums і artists інформацією з цих таблиць. Саме це завдання вирішує клас QSqlRelationalTableModel. Розглянемо фрагмент програми relational_model, повний текст якої ви знайдете за посиланням наприкінці сторінки.
Малюнок 3. Відображення таблиці композицій за допомогою моделі QSqlRelationalTableModel
Редагування даних
Нововведення починаються з наступного рядка програми, в якому ми встановлюємо стратегію редагування. методомsetEditStrategy() передається одна з констант, яка вказує, як зміни, внесені в модель, повинні фіксуватися в базі даних. Вибір стратегії QSqlTableModel::OnFieldChange призведе до того, що будь-яка зміна в моделі відразу фіксуватиметься в базі даних. Цей варіант зручний, якщо зміни вносяться до моделі автоматично (і нечасто). Однак користувач, який редагує базу даних вручну, може помилитися під час заповнення значення поля. При виправленні кожної помилки програмі доведеться звертатися до БД, що створить занадто багато звернень. При виборі константи QSqlTableModel::OnRowChange зміни будуть вноситися до бази даних при переході користувача до нового рядка. Особисто я вважаю найбільш підходящим для наших цілей третій варіант - QSqlTableModel::OnManualSubmit, при якому для внесення в БД змін, зроблених у моделі, потрібна окрема команда.
Метод insertRow() додає до таблиці новий рядок, який розташовується після того рядка, номер якого передано як аргумент insertRow(). Ми передаємо методу номер останнього рядка (значення model()->rowCount()), так що новий рядок завжди додається до кінця таблиці. Метод submitAll() вносить зміни до БД, а метод revertAll() скасовує всі зміни, зроблені під час поточного сеансу редагування (якщо вони ще не були внесені до БД). Зверніть увагу, що метод insertRow() реалізований у базовому класі QAbstractItemModel, який у принципі передбачає роботу з будь-якими структурами даних. Пояснюється це тим, що у моделях Interview Framework дані зберігаються як ієрархії таблиць, незалежно від цього, яка їх вихідна структура.
Повернемося до функції main(). Під час редагування таблиць БД слід врахувати один важливий момент: у програмі relational_model ми видалили з моделіДаний перший стовпець таблиці складається за допомогою методу removeColumn(), оскільки він не містить корисної для користувача інформації. У додатку albums_editor, який вносить зміни до таблиці albums, ми не можемо видаляти стовпці з моделі albumsRelation (тим більш первинні ключі) оскільки в цьому випадку всі SQL-команди, що редагують БД, виявляться сформованими неправильно. Проте, нам не потрібно показувати користувачеві перший стовпець таблиці albums (при додаванні рядків до таблиці унікальні числові значення цього стовпця все одно генеруються автоматично). Ми приховуємо від користувача нецікавий йому стовпець, але не лише на рівні моделі даних, але в рівні представлення (об'єкт view), з допомогою методу setColumnHidden().
Малюнок 4. Вікно таблиці з розкривним списком допустимих значенні комірки.
Настав час ближче познайомитися з системою Interview Framework. Один із основоположних принципів Interview Framework полягає у приведенні найрізноманітніших даних, незалежно від їх вихідної структури та методу їх отримання, до єдиного внутрішнього подання. Саме цей принцип забезпечує універсалізм Interview Framework, при якому різні об'єкти-види та об'єкти-моделі можуть вільно взаємодіяти між собою. Для доступу до даних Interview Framework застосовує індекси. Індекси Interview Framework – це спеціальні об'єкти, які дозволяють отримати доступ до окремих елементів даних. Одне із завдань індексу полягає в тому, щоб ізолювати дані від безпосереднього доступу, тому при роботі з індексами потрібно дотримуватися певних обмежень. Індекс представляє нам доступ до елемента даних, виходячи зі стану моделі даних на момент отримання індексу. Якщо після отримання індексу стан моделі зміниться,індекс може втратити валідність Це означає, що звичайні індекси слід використовувати для елементарних операцій редагування даних, причому для кожної операції слід отримувати новий індекс (навіть якщо ми працюємо з тим самим елементом даних). У складніших випадках можна скористатися постійними (persistent) індексами.