Qt:Документация 4.3.2/qtsql

Материал из Wiki.crossplatform.ru

Версия от 10:52, 6 ноября 2008; Root (Обсуждение | вклад)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск
40px Внимание: Актуальная версия перевода документации находится здесь

__NOTOC__

Image:qt-logo.png

Главная · Все классы · Основные классы · Классы по группам · Модули · Функции

Image:trolltech-logo.png

[Предыдущая: Модуль QtOpenGL ] [ Модуль Qt ] [Следующая: Модуль QtSvg ]

Содержание

[править] Модуль QtSql

Модуль QtSql помогает реализовать бесшовную реализацию ваших приложений с базами данных. Далее...

[править] Пространства Имен

QSql Различные идентификаторы, используемые в разных библиотеках Qt SQL

[править] Классы

QSqlDatabase Предоставляет соединение с базой данных
QSqlDriver Абстрактный базовый класс для доступа к специфическим базам данных SQL
QSqlDriverCreator Класс-шаблон, предоставляющий фабрику драйверов SQL для специфических типов драйверов
QSqlDriverCreatorBase Базовый класс для фабрик драйверов SQL
QSqlDriverPlugin Абстрактный базовый класс для собственных плагинов QSqlDriver
QSqlError Информация об ошибке базы данных SQL
QSqlField Управление полями в таблицах и представлениях базы данных SQL
QSqlIndex Функции для управления индексами базы данных и их описания
QSqlQuery Средства управления выражениями SQL и их выполнения
QSqlQueryModel Модуль данных только-для-чтения результирующей SQL-выборки
QSqlRecord Заключает в себе запись базы данных
QSqlRelation Содержит информацию о внешнем ключе SQL
QSqlRelationalDelegate Делегат, используемый для отображения и редактирования данных модели QSqlRelationalTableModel
QSqlRelationalTableModel Модель данных для редактирования одной таблицы базы данных с поддержкой внешних ключей
QSqlResult Абстрактный интерфейс для доступа к данным специфичной базы SQL
QSqlTableModel Модуль данных для редактирования одной таблицы базы данных

[править] Подробное описание

Модуль QtSql помогает реализовать бесшовную реализацию Ваших приложений с базами данных.

Классы SQL подразделяются на три слоя:

Слой Описание
Слой Драйвера Включает классы QSqlDriver, QSqlDriverCreator<T>, QSqlDriverCreatorBase, QSqlDriverPlugin и QSqlResult. Этот слой предоставляет низкоуровневый мост между определенными базами данных и слоем SQL API. Для получения более подробной информации, см. Драйвера баз данных SQL.
Слой SQL API Эти классы предоставляют доступ к базам данных. Связь устанавливается с помощью класса QSqlDatabase. Взаимодействие с базой данных осуществляется с помощью класса QSqlQuery. В дополнение к классам QSqlDatabase и QSqlQuery, слой SQL API опирается на классы QSqlError, QSqlField, QSqlIndex и QSqlRecord.
Слой пользовательского интерфейса Эти классы связывают данные из базы данных с дата-ориентироваными виджетами. Сюда входят такие классы, как QSqlQueryModel, QSqlTableModel и QSqlRelationalTableModel. Эти классы разработаны для работы с каркасом Qt модель/представление.

Для включения определений классов модуля, используйте следующую директиву:

    #include <QtSql>

Для сборки Вашего проекта с модулем, добавьте в Ваш qmake .pro-файл следующую строку:

    QT += sql

Модуль QtSql входит в состав Qt Console Edition, Qt Desktop Edition и Qt Open Source Edition.

Данный обзор предполагает, что вы имеете, по крайней мере, базовые знания об SQL. Вы должны иметь представления о простейших выражениях SELECT, INSERT, UPDATE и DELETE. Несмотря на то, что класс QSqlTableModel предоставляет интерфейс для просмотра и редактирования базы данных без знания SQL, наличие базовых представлений об SQL настоятельно рекомендуется. Стандартное описание баз данных SQL - это An Introduction to Database Systems (7th Ed.) by C. J. Date, ISBN 0201385902.

Разделы:

[править] Соединение с базой данных

Прежде, чем получить доступ к базе данных с помощью классов QSqlQuery или QSqlQueryModel, вы должны установить с базой данных хотя бы одно соединение.

Соединения с базой данных идентифицируются с помощью произвольных строк. QSqlDatabase также поддерживает концепцию соединения по умолчанию, которое используется классом Qt SQL если никакое другое соединение не указано. Этот механизм очень удобен для приложений, использующих только одно соединение с базой данных.

Следующий код устанавливает соединение с базой данных MySQL с именем flightdb на хосте bigblue:

        QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
        db.setHostName("bigblue");
        db.setDatabaseName("flightdb");
        db.setUserName("acarlson");
        db.setPassword("1uTbSbAs");
        bool ok = db.open();

Первый аргумент QSqlDatabase::addDatabase() - это имя драйвера. Для получения списка драйверов, см. документацию addDatabase(). Для инициализации данных соединения мы вызываем setHostName(), setDatabaseName(), setUserName() и setPassword().

Так как имя соединения не определено, соединение становится соединением по умолчанию. Для определения имени, передайте его в качестве второго аргумента в QSqlDatabase::addDatabase(). Например:

        QSqlDatabase firstDB = QSqlDatabase::addDatabase("QMYSQL", "first");
        QSqlDatabase secondDB = QSqlDatabase::addDatabase("QMYSQL", "second");

Как только соединение инициализировано, мы должны вызвать QSqlDatabase::open() для открытия бызы данных и получения доступа к данным. Если запрос соединения потерпит неудачу, функция возвратит false; информацию об ошибке можно получить из QSqlDatabase::lastError().

Как только соединение установлено, мы можем получить указатель на него из любого места прораммы, вызвав статическую функцию QSqlDatabase::database(). Если мы вызываем данную функцию без параметра, она возвратит указатель на соединение по умолчанию. Если функция вызывается с идентификатором, использованным при установке соединения, она возвратит ссылку на указанное соединение. Например:

        QSqlDatabase defaultDB = QSqlDatabase::database();
        QSqlDatabase firstDB = QSqlDatabase::database("first");
        QSqlDatabase secondDB = QSqlDatabase::database("second");

Для удаления соединения с базой данных, сначала закройте базу данных с помощью QSqlDatabase::close(), а затем, удалите ее с помощью статического метода QSqlDatabase::removeDatabase().

[править] Выполнение инструкций SQL

Класс QSqlQuery предоставляет интерфейс для выполнения инструкций SQL и навигации по результирующей ваборке запроса.

Классы QSqlQueryModel и QSqlTableModel, описанные в следующем разделе, предоставляют высокоуровневый интерфейс для доступа к базам данных. Если вы не знакомы с SQL, Вам, возможно, захочется сразу перейти к следующему разделу ( Использование классов SQL моделей).

[править] Выполнение Запроса

Для выполнения SQL запросов, просто создают объект QSqlQuery и вызывают QSqlQuery::exec(). Например, вот так:

        QSqlQuery query;
        query.exec("SELECT name, salary FROM employee WHERE salary > 50000");

Конструктор QSqlQuery принимает необязательный аргумент QSqlDatabase, который указывает, какое соединение с базой данных используется. В нижеприведенном примере, мы не указываем соединение, поэтому используется соединение по умолчанию.

Если возникает ошибка, exec() возвращает false. Доступ к ошибке можно получить с помощью QSqlQuery::lastError().

[править] Навигация по результирующей выборке

QSqlQuery предоставляет единовременный доступ к результирующей выборке одного запроса. После вызова exec(), внутренний указатель QSqlQuery указывает на позицию перед первой записью.Мы должны вызвать метод QSqlQuery::next() один раз, чтобы переместить указатель к первой записи, затем снова повторять next(), чтобы получать доступ к другим записям, до тех пор пока он не вернет false. Вот типичный цикл перебирающий все записи по порядку:

        while (query.next()) {
            QString name = query.value(0).toString();
            int salary = query.value(1).toInt();
            qDebug() << name << salary;
        }

Функция QSqlQuery::value() возвращает значение поля текущей записи. Поля задаются индексами начиная с нуля. Функция QSqlQuery::value() возвращает значение типа QVariant, который может хранить значения различных типов C++ и ядра Qt, такие как int, QString и QByteArray. Различные типы значений базы данных автоматически приводятся к ближайшему эквиваленту в Qt. В предыдущем примере кода мы вызывали QVariant::toString() и QVariant::toInt(), чтобы конвертировать возвращенное значение в QString и int соответственно.

Вы можете перемещаться взад и вперед по выборке, используя функции QSqlQuery::next(), QSqlQuery::previous(), QSqlQuery::first(), QSqlQuery::last() и QSqlQuery::seek(). Текущий номер строки можно получить с помощью QSqlQuery::at(), а общее количество строк в выборке, если это поддерживается базой данных, возвращается функцией QSqlQuery::size().

Определить, поддерживает ли драйвер базы данных определенную особенность можно с помощью вызова функции QSqlDriver::hasFeature(). В следующем примере мы вызываем QSqlQuery::size() для определения размера результирующей выборке, только в том случае, если база данных поддерживает такую возможность; в противном случае мы перемещаемся к последней записи и используем ее позицию в выборке для определения количечества записей.

        QSqlQuery query;
        int numRows;
        query.exec("SELECT name, salary FROM employee WHERE salary > 50000");
 
        QSqlDatabase defaultDB = QSqlDatabase::database();
        if (defaultDB.driver()->hasFeature(QSqlDriver::QuerySize)) {
            numRows = query.size();
        } else {
            // this can be very slow
            query.last();
            numRows = query.at() + 1;
        }

Если вы перебираете результирующую выборку только с помощью вызовов next() и seek() с положительными значениями, то можете перед вызовом exec() вызвать QSqlQuery::setForwardOnly(true). Эта небольшая оптимизация сильно ускорит выполнение запросов, возвращающих большие выборки.

[править] Вставка, изменение и удаление записей

QSqlQuery может выполнять произвольные запросы SQL, а не только SELECT. Следующий пример вставляет запись в таблицу используя выражение INSERT:

        QSqlQuery query;
        query.exec("INSERT INTO employee (id, name, salary) "
                   "VALUES (1001, 'Thad Beaumont', 65000)");

Если вы хотите одновременно вставить множество записей, то зачастую эффективней отделить запрос от реально вставляемых значений. Это можно сделать с помощью вставки значений через параметры. Qt поддерживает два синтаксиса вставки значений: поименованые параметры и позиционные параметры. В следующем примере показана вставка с помощью поименованного параметра:

        QSqlQuery query;
        query.prepare("INSERT INTO employee (id, name, salary) "
                      "VALUES (:id, :name, :salary)");
        query.bindValue(":id", 1001);
        query.bindValue(":name", "Thad Beaumont");
        query.bindValue(":salary", 65000);
        query.exec();

В этом примере показана вставка с помощью позиционного параметра:

        QSqlQuery query;
        query.prepare("INSERT INTO employee (id, name, salary) "
                      "VALUES (?, ?, ?)");
        query.addBindValue(1001);
        query.addBindValue("Thad Beaumont");
        query.addBindValue(65000);
        query.exec();

Оба синтаксиса работают со всеми драйверами баз данных предоставляемыми Qt. Если база данных поддерживает синтаксис, Qt просто пересылает запрос в СУБД; в противном случае, Qt симулирует синтаксис параметров и осуществляет предобработку запроса. Фактический запрос, который поступает на выполнение в СУБД доступен с помощью QSqlQuery::executedQuery().

При вставке множества записей, Вам требуется вызвать QSqlQuery::prepare() только однажды. После этого вы можете вызвать bindValue() или addBindValue() с последующим вызовом exec() столько раз, сколько потребуется.

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

Изменение записей очень похоже на вставку в таблицу:

        QSqlQuery query;
        query.exec("UPDATE employee SET salary = 70000 WHERE id = 1003");

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

В конце приведем пример выражения DELETE:

        QSqlQuery query;
        query.exec("DELETE FROM employee WHERE id = 1007");

[править] Транзакции

Если основной движок базы данных поддерживает транзакции, то QSqlDriver::hasFeature( QSqlDriver::Transactions) возвратит true. Для инициации транзакции вы можете использовать QSqlDatabase::transaction(), затем запустить инструкции SQL, которые вы хотите выполнить в пределах транзакции, а после вызвать QSqlDatabase::commit() или QSqlDatabase::rollback().

Пример:

        QSqlDatabase::database().transaction();
        QSqlQuery query;
        query.exec("SELECT id FROM employee WHERE name = 'Torild Halvorsen'");
        if (query.next()) {
            int employeeId = query.value(0).toInt();
            query.exec("INSERT INTO project (id, name, ownerid) "
                       "VALUES (201, 'Manhattan Project', "
                       + QString::number(employeeId) + ")");
        }
        QSqlDatabase::database().commit();

Транзакции можно использовать для того, чтобы гарантировать атомарность сложного действия (например, просмотр внешних ключей и создание записи) или для возможности отмены сложного действия в процессе его выполнения.

[править] Использование классов SQL моделей

В дополнение к QSqlQuery, Qt предлагает три высокоуровневых класса для работы с базами данных. Это классы QSqlQueryModel, QSqlTableModel и QSqlRelationalTableModel.

QSqlQueryModel Модель только-для-чтения, основаннная на произвольных SQL-запросах.
QSqlTableModel Модель для чтения-записи работающая с одной таблицей.
QSqlRelationalTableModel Подкласс QSqlTableModel с поддержкой внешних ключей.

Эти классы происходят от QAbstractTableModel (который в свою очередь происходит от QAbstractItemModel) и могут существенно облегчить представление данных из базы данных в элементно-ориентированых классах таких, как QListView и QTableView. Это подробно объясняется в разделе Отображение данных в таблице-представлении.

Другое преимущество использования этих классов состоит в том, что они облегчают приспособление кода к другому источнику данных. Например, если вы использовали QSqlTableModel, а затем решили вместо базы данных использовать XML-файлы для хранения данных, то изменение кода - это вопрос замены одной модели данных на другую.

[править] Модель: SQL запрос

QSqlQueryModel предлагает основанную на SQL запросе модель только-для-чтения.

Пример:

        QSqlQueryModel model;
        model.setQuery("SELECT * FROM employee");
 
        for (int i = 0; i < model.rowCount(); ++i) {
            int id = model.record(i).value("id").toInt();
            QString name = model.record(i).value("name").toString();
            qDebug() << id << name;
        }

После настройки запроса с помощью QSqlQueryModel::setQuery(), Вы, можете использовать QSqlQueryModel::record(int) для получения доступа к отдельным записям. Также можете использовать QSqlQueryModel::data() и другие функции, унаследованные от QAbstractItemModel.

Также есть перегруженный метод setQuery(), который принимает объект QSqlQuery и работает с его результирующей выборкой. Это позволяет Вам использовать любые возможности QSqlQuery для установки запроса (например, QSqlQuery::prepare()).

[править] Модель: SQL Таблица

QSqlTableModel предлагает модель для чтения и записи, которая работает одновременно только с одной таблицей SQL.

Пример:

        QSqlTableModel model;
        model.setTable("employee");
        model.setFilter("salary > 50000");
        model.setSort(2, Qt::DescendingOrder);
        model.select();
 
        for (int i = 0; i < model.rowCount(); ++i) {
            QString name = model.record(i).value("name").toString();
            int salary = model.record(i).value("salary").toInt();
            qDebug() << name << salary;
        }

QSqlTableModel - это высокоровневая альтернатива QSqlQuery для навигации по и изменения отдельной SQL таблицы. Обычно это требует меньше кода и не требует знания SQL синтаксиса.

Для получения строки таблицы используйте QSqlTableModel::record(), а для ее изменения - QSqlTableModel::setRecord(). Например, следующий код увеличивает зарплату всех сотрудников на 10 процентов:

        for (int i = 0; i < model.rowCount(); ++i) {
            QSqlRecord record = model.record(i);
            double salary = record.value("salary").toInt();
            salary *= 1.1;
            record.setValue("salary", salary);
            model.setRecord(i, record);
        }
        model.submitAll();

Вы можете использовать QSqlTableModel::data() и QSqlTableModel::setData(), которые унаследованные от QAbstractItemModel, для доступа к данным . В следующем примере показано, как изменить запись с помощью setData():

        model.setData(model.index(row, column), 75000);
        model.submitAll();

Здесь показано, как вставить строку и заполнить ее:

        model.insertRows(row, 1);
        model.setData(model.index(row, 0), 1013);
        model.setData(model.index(row, 1), "Peter Gordon");
        model.setData(model.index(row, 2), 68500);
        model.submitAll();

Пример удаления пяти следующих друг за другом строк:

        model.removeRows(row, 5);
        model.submitAll();

В качестве первого элемента QSqlTableModel::removeRows() передается индекс первой удаляемой строки.

После окончания редактирования записи, вы должны вызвать QSqlTableModel::submitAll() для того, чтобы гарантировать запись изменений в базу данных.

Когда и где Вам требуется вызывать submitAll() зависит от стратегии редактирования таблицы. По умолчанию установлена стратегия QSqlTableModel::OnRowChange, которая указывает, что произведенные изменения будут внесены в базу данных при выборе пользователем другой строки. Другие стратегии это - QSqlTableModel::OnManualSubmit (все изменения кэшируются в модели до вызова submitAll()) и QSqlTableModel::OnFieldChange (где изменения не кэшируются). Они, в основном, полезны, когда QSqlTableModel используется с представлением.

Хотя кажется, что QSqlTableModel::OnFieldChange обещает, что Вам никогда не придется вызывать submitAll(). Есть два нюанса:

  • Без кэширования может снизиться скорость работы.
  • Если вы изменили первичный ключ, то запись может ускользнуть от Вас, пока вы пытаетесь ее заполнить,.

[править] Модель: реляционной SQL таблицы

QSqlRelationalTableModel расширяет QSqlTableModel для предоставления поддержки внешних ключей. Внешний ключ - это связть один-к-одному, установленная между полем одной таблицы и полем первичного ключа другой таблицы. Например, если таблица book имеет поле с названием authorid, которое ссылается на поле id таблицы авторов, вы указываете, что поле authorid является первичным ключем.

center center

Левый скриншот показывает QSqlTableModel в QTableView. Внешние ключи (city и country) не представлены удобочитаемыми значениями. Правый скриншот показывает QSqlRelationalTableModel, в котором внешние ключи представлены удобочитаемыми текстовыми строками.

Следующий отрывок кода демонстрирует настройку QSqlRelationalTableModel:

        model->setTable("employee");
 
        model->setRelation(2, QSqlRelation("city", "id", "name"));
        model->setRelation(3, QSqlRelation("country", "id", "name"));

Более подробную информацию см. в описании QSqlRelationalTableModel.

[править] Отображение данных в таблице-представлении

Классы QSqlQueryModel, QSqlTableModel и QSqlRelationalTableModel могут использоваться в качестве источников данных для классов представлений Qt, таких как QListView, QTableView и QTreeView. На практике, наиболее часто используется QTableView в связи с тем, что результирующая SQL выборка, по существу, представляет собой двумерную структуру данных.

center

В следующем примере создается представление основанное на модели данных SQL:

        QTableView *view = new QTableView;
        view->setModel(model);
        view->show();

Если модель является моделью для чтения-записи (например, QSqlTableModel), то представление позволяет редактировать поля. Вы можете запретить это вызвав

        view->setEditTriggers(QAbstractItemView::NoEditTriggers);

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

Классы-представления, для обозначения колонок, наверху отображают заголовки. Для изменения текста заголовка, вызовите setHeaderData() модели. Текстом заголовка по умолчанию является наименование поля. Например:

        model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
        model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));
        model->setHeaderData(2, Qt::Horizontal, QObject::tr("City"));
        model->setHeaderData(3, Qt::Horizontal, QObject::tr("Country"));

QTableView также имеет вертикальные заголовки, слева, содержащие номера строк. Если вы программно вставляете строки с помощью QSqlTableModel::insertRows(), новые колонки будут обозначены звездочкой (*) до тех пор, пока они не будут помещены в базу данных с помощью submitAll() или автоматически при переходе пользователя к другой записи (если стратегия редактирования равна QSqlTableModel::OnRowChange).

center

Аналогично, если вы удаляете строки с помощью removeRows(), строки будут отмечены восклицательным знаком (!) пока изменения не будут внесены в базу данных.

Элемены представления отображаются с помощью делегата. Делегат по умолчанию: QItemDelegate, содержит большинство общих типов данных (int, QString, QImage и т.д.). Также делегат отвечает за предоставление виджета-редактора (например, combobox), пользователь начинает редактировать элемент представления. Вы можете создавать свои собственные делегаты наследуя QAbstractItemDelegate или QItemDelegate. Для получения более подробной информации см. Программирование Модель/Представление.

QSqlTableModel оптимизирован для работы с одной таблицей в один момент времени. Если Вам нужна модель для чтения-записи, которая может работать с произвольной результирующей выборкой, вы можете создать подкласс QSqlQueryModel и заново реализовать flags() и setData() для возможности осуществлять чтение-запись. Две следующие функции делают поля 1 и 2 модели SQL запроса редактируемыми:

    Qt::ItemFlags EditableSqlModel::flags(
            const QModelIndex &amp;index) const
    {
        Qt::ItemFlags flags = QSqlQueryModel::flags(index);
        if (index.column() == 1 || index.column() == 2)
            flags |= Qt::ItemIsEditable;
        return flags;
    }
 
    bool EditableSqlModel::setData(const QModelIndex &amp;index, const QVariant &amp;value, int /* role */)
    {
        if (index.column() < 1 || index.column() > 2)
            return false;
 
        QModelIndex primaryKeyIndex = QSqlQueryModel::index(index.row(), 0);
        int id = data(primaryKeyIndex).toInt();
 
        clear();
 
        bool ok;
        if (index.column() == 1) {
            ok = setFirstName(id, value.toString());
        } else {
            ok = setLastName(id, value.toString());
        }
        refresh();
        return ok;
    }

Вспомогательная функция setFirstName() определяется следующим образом:

    bool EditableSqlModel::setFirstName(int personId, const QString &amp;firstName)
    {
        QSqlQuery query;
        query.prepare("update person set firstname = ? where id = ?");
        query.addBindValue(firstName);
        query.addBindValue(personId);
        return query.exec();
    }

Функция setLastName() подобна ей. Полный код реализации можно посмотреть в примере Query Model.

Создание подклассов модели делает возможной настройку собственной модели различными способами: вы можете предоставлить подсказки к элементам, изменить цвет фона, отобразить вычисляемые значения, разрешать различным значениям быть отображенными и отредактированными, отдельно обработать нулевые значения и т.д. Для получения более подробной информации см. Программирование Модель/Представление и описание класса QAbstractItemView.

Если все, что Вам требуется - это разрешить внешний ключ для более понятного представления, вы можете использовать QSqlRelationalTableModel. Для получения лучшего результата, вам следует использовать дилегат QSqlRelationalDelegate, который предоставляет для изменения значения внешнего ключа виджет-редактор в виде выпадающего списка.

center

Пример Relational Table Model иллюстрирует использование QSqlRelationalTableModel в совокупности с QSqlRelationalDelegate для представления таблицы с поддержкой внешнего ключа.

[править] Создание информационно-связанных форм

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

Такие информационно-связанные формы могут быть созданы с помощью класса QDataWidgetMapper, общий компонент модель-представление, которого используется, чтобы отобразить данные из модели, в определенный виджет в пользовательском интерфейсе.

QDataWidgetMapper работает с определенной таблицей базы данных, отображая элементы таблицы в базисе row-by-row или column-by-column. В результате, использование QDataWidgetMapper с SQL моделью так же просто, как использование его с любыми другими табличными моделями.

center

Демонстрация Books показывает, как информация может быть представлена для легкого доступа используя QDataWidgetMapper и набор простых виджетов ввода.

[Предыдущая: Модуль QtOpenGL ] [ Модули Qt ] [Следующая: Модуль QtSvg ]


Copyright © 2007 Trolltech Trademarks
Qt 4.3.2