Wiki

Что нового в Qt 3.2

Jasmin Blanchette, Harald Fernengel (перевод Andi Peredri)

Сейчас уже доступна Qt 3.2. В этой версии появилось много новых классов и возможностей, которые вам бы наверняка захотелось должным образом использовать в своих Qt-приложениях. Большинство из них мы рассмотрим в этой статье. С полным списком изменений в Qt 3.2.0 можно ознакомиться здесь: Changes 3.2.0.

Экранная заставка

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

  • Функция setStatus() переименована в message().
  • После создания QSplashScreen вам необходимо явно вызвать функцию show(), так как она больше не вызывается конструктором. Причина, по которой конструктор QSplashScreen не вызывает show(), заключается в неявном вызове виртуальной функции drawContents(), которая может быть переопределена в производном классе. В C++ при вызове виртуальной функции из конструктора вызывается ее реализация из текущего класса, а не производного. Это происходит из-за того, что к этому моменту времени таблица виртуальных функций объекта еще не полностью инициализирована.

Новый элемент интерфейса ToolBox

Панель инструментов QToolBox, впервые появившаяся в Qt Designer 3.1, стала стандартным интерфейсным элементом Qt, который вы можете использовать в своих собственных программах.

Toolboxes

В среде Windows элемент QToolBox имеет внешний вид стандартного для этой платформы элемента ToolBox. При использовании стилей Mac и Motif страницы, входящие в состав элемента, изображаются в виде вкладок.

Qt Designer обеспечивает полную поддержку элемента QToolBox. Для этого из списка интерфейсных элементов выберите ToolBox и затем поместите его в вашу форму. Теперь вы можете заполнить вкладки элемента точно так же, как заполняли раньше вкладки QTabWidget или QWidgetStack.

Локальная область данных потока

В много-поточных приложениях статические и глобальные переменные доступны для всех потоков. Если вы хотите, чтобы у каждого потока была своя копия данных, то используйте для хранения переменных новый шаблонный класс QThreadStorage. Этот класс обеспечивает механизм хранения локальных данных потока, известный также как Thread-Local Storage (TLS). До выхода Qt 3.2 это можно было сделать только с помощью платформо-зависимого API. Теперь это делается так:

  • Переменная должна быть объявлена как QThreadStorage , где T - тип данных.
  • Функция setLocalData() инициализирует локальную переменную потока.
  • Функция hasLocalData() возвращает true, если переменная потока имеет ненулевое значение, и false в противном случае.
  • Функция localData() возвращает указатель на локальную переменную потока.

В каких случаях может использоваться QThreadStorage? Обычно для хранения глобальных и статических переменных, к которым должен быть запрещен одновременный доступ из нескольких потоков. В качестве примера может послужить кэш, одновременный доступ к которому из нескольких потоков может привести к ошибкам. (В качестве альтернативного решения можно использовать QMutex.)

Управление памятью в QString

Часто увеличение длины строки QString приводит к повторному перераспределению памяти, как показано в следующем примере:

while (...) {
    str += getChar();
}

Такое автоматическое перераспределение памяти в классе QString является приемлемым для большинства приложений. Для более гибкого управления памятью используйте три следующих функции QString:

  • reserve() резервирует пространство для определенного числа символов.
  • capacity() возвращает число символов, которое может быть размещено в зарезервированном пространстве. Таким образом, результат capacity() не может быть меньше, чем length().
  • squeeze() освобождает все неиспользуемое пространство.

Эти функции не изменяют значение объекта QString, а лишь влияют на скорость его работы и использование им памяти. Ниже представлен пример, в котором вызов reserve() гарантирует, что во время работы цикла while не будет перераспределяться память, а последующий вызов squeeze() обеспечивает освобождение всей неиспользуемой памяти:

QString str;
int len = 0;
str.reserve(maxLen);
while (...) {
    str[len++] = getChar();
}
str.squeeze();
 

QString с несколькими аргументами

Механизм QString::arg() накладывает ограничения на использование символа % в строковых параметрах. Например, следующий код будет работать некорректно, если appName содержит %0, %1 или %2:

QString("%1 - %2").arg(appName).arg(fileName)

Для решения этой проблемы Qt 3.2 предлагает использовать перегруженную функцию arg() с различным числом строковых параметров. Вот как следует переписать этот участок кода, чтобы избежать возможных проблем:

QString("%1 - %2").arg(appName, fileName)

Функция arg() в качестве параметров может принимать до четырех строковых значений. Если вам необходимо передать нестроковое значение, например, int или float, воспользуйтесь для этого сначала одноаргументной версией arg(), а затем многоаргументной arg() для передачи строк.

Поддержка масок в QLineEdit

Элемент QLineEdit теперь поддерживает ввод по маске. Маска состоит из специальных символов и разделителей. Специальные символы определяют допустимый диапазон ввода, разделители всегда видимы и не могут быть изменены. Например, в маске 990.990.990.990 девятки определяют поля опционального ввода цифр, нули - поля обязательного ввода, а точки являются разделителями. Такая маска может использоваться для ввода IP-адреса, такого как 123.54.129.255.

Masks

Маски дополняют валидаторы (validators). Основная проблема валидаторов заключалась в отсутствии визуального представления. В то же время, для контроля ввода маски могут использовать разделители.

В любой момент времени вы можете проверить введенные данные на корректность с помощью функции hasAcceptableInput(). Если в поле ввода ожидалось цифровое значение, QLineEdit не позволит ввести буквенное, однако пользователь может не вводить всю необходимую информацию, и в этом случае hasAcceptableInput() возвратит false.

Более подробную информацию об используемых в масках специальных символах и примеры готовых масок можно найти в описании свойства inputMask. Наиболее простой способ поэкспериментировать с масками - запустить Qt Designer, установить для элемента QLineEdit свойство inputMask и включить предварительный просмотр формы (Ctrl+T).

Полная поддержка индийского и сирийского языков

В Qt 3.0 был выполнен большой объем работ, связанный с поддержкой языков с левосторонним чтением, таких как арабский, персидский и иврит. В Qt 3.2 эта поддержка была расширена на семейство индийских языков, включая бенгальский, тамильский и деванагари.

Scripts

Также в список поддерживаемых языков с левосторонним чтением был добавлен сирийский. Для поддержки этих языков со стороны Windows должен использоваться Uniscribe, а со стороны X11 - XFT и шрифты OpenType.

Угловые интерфейсные элементы в QTabWidget

Assistant-Tabs

Класс QTabWidget теперь поддерживает угловые элементы с двух сторон поля вкладок. Эту возможность использует Qt Assistant для отображения слева и справа от поля вкладок кнопок добавления и удаления текущей вкладки.

Const Begin и Const End

Классы неявного совместного доступа (implicitly shared classes) QMap, QValueList и QValueVector наряду с функциями begin() и end() сейчас поддерживают функции constBegin() и constEnd(). При просмотре классов-контейнеров с использованием const-итераторов функции constBegin() и constEnd() оказываются более быстрыми, чем их не-const аналоги, потому что им не нужно проверять наличие совместного доступа к данным. Для большинства приложений выигрыш в скорости при использовании этих функций окажется небольшим, но Qt сейчас использует их везде, где это возможно.

Если вы хотите использовать эти функции в своих приложениях, найдите все вхождения const_iterator или ConstIterator, например:

QValueVector<int>::const_iterator it = vec.begin();
while (it != vec.end()) {
    ++it;
}

и замените функции begin() и end() функциями constBegin() и constEnd():

QValueVector<int>::const_iterator it = vec.constBegin();
while (it != vec.constEnd()) {
    ++it;
}

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

QTextEdit::setMaxLogLines()

Одним из нововведений в Qt 3.1 был режим LogText в QTextEdit. Этот режим был оптимизирован для просмотра больших текстов. Сейчас QTextEdit позволяет задать максимальное число строк текста для этого режима. Если это число будет превышено, верхние строки будут автоматически удаляться.

Поддержка Long Long

В настоящее время для использования в приложениях Qt предлагает переносимые предопределенные 64-битные целые типы Q_LLONG и Q_ULLONG. Поддержка Q_LLONG и Q_ULLONG в QVariant позволяет избежать конвертирования данных в строку и обратно при доступе к 64-битным полям SQL-баз данных. Также с целью поддержки 64-битных целых типов были расширены интерфейсы QString и QDataStream.

Изменение модальности

В классе QDialog появился новый метод setModal(bool), который делает излишним параметр bool modal конструктора этого класса. Теперь при создании собственного подкласса QDialog вам достаточно определить конструктор вида:

MyDialog(QWidget *parent = 0, const char *name = 0);

Если вам необходимо сделать диалог модальным, вы можете либо вызвать метод exec() (который всегда показывает модальный диалог), либо последовательно вызвать setModal(true) и show(). Второй подход также позволяет сделать диалог немодальным.

About Qt

Статическая функция QMessageBox::aboutQt() выводит диалоговое окно About Qt. В Qt 3.2 появился одноименный слот QApplication::aboutQt( ), который может быть связан непосредственно с соответствующим QAction:

aboutQtAct = new QAction(tr("About &Qt"), 0, this);
connect(aboutQtAct, SIGNAL(activated()), qApp, SLOT(aboutQt()));

Это более удобно, чем создание собственного слота aboutQt(), вызывающего статическую функцию QMessageBox::aboutQt().

Помимо информирования о том, что вы используете высококачественный инструментарий, окно About Qt показывает номер версии библиотеки Qt, использованной для сборки приложения, что может быть полезным при отладке и поддержке.

Умные Actions

Класс QAction теперь имеет новые конструкторы, которые не требуют явного указания названия выполняемого действия. Старый стиль:

openAct = new QAction(tr("Open"), tr("&Open..."), tr("Ctrl+O"), this);

Новый стиль:

openAct = new QAction(tr("&Open..."), tr("Ctrl+O"), this);

Класс QAction достаточно умен для того, чтобы получить текст всплывающей подсказки из названия пункта меню путем удаления амперсанда ("&") и завершающих точек ("..."). В некоторых языках, например, японском, такой стиль может работать некорректно, в этих случаях используйте setToolTip().

Местонахождение исполняемых файлов

Функции QApplication::applicat ionDirPath() и QApplication::applicationFilePath() возвращают путевое имя каталога и путевое имя исполняемого файла соответственно. Эта информация может быть использована для определения местонахождения файлов изображений или других данных программы.

 

Новые возможности SQL-модуля

Помимо драйверов доступа к Microsoft SQL Server, MySQL, Oracle, PostgreSQL, Sybase Adaptive Server и ODBC SQL-модуль теперь включает драйвер IBM DB2 (под названием QDB2).

Класс QSqlError теперь содержит метод showMessage(), который с помощью QMessageBox может сообщить об ошибках драйвера и сервера баз данных.

Класс QSqlCursor упрощает вывод содержимого таблицы базы данных и заполнение форм редактирования. В предыдущих версиях Qt для отображения результатов JOIN вам нужно было либо наследовать QSqlCursor, либо создавать вид и привязывать к нему QSqlCursor. Новый класс QSqlSelectCursor предлагает более удобное решение. Он может быть использован для вывода результатов любого SQL-запроса SELECT. По умолчанию класс выводит данные в режиме только для чтения, однако, переопределяя соответствующие виртуальные методы, можно реализовать функции INSERT, UPDATE и DELETE.

Включение SQL-драйверов в приложения

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

QSqlDatabase::registerSqlDriver( "MYDRIVER", new QSqlDriverCreator<MyDriver>());

Теперь MYDRIVER может быть использован точно так же, как и любой другой SQL-плагин Qt.

Параметризированные запросы

В Qt 3.1 для поддержки IN-параметров был использован механизм привязки значений. Qt 3.2 распространяет использование этого механизма для поддержки параметров OUT и INOUT. Это может быть особенно полезным при работе с сохраненными процедурами.

QSqlQuery query;
query.prepare("CALL GET_NEXT_SEQ_ID(:table, :seqid)");
query.bindValue(":table", "INVOICES");
query.bindValue(":seqid", 0, QSql::Out);
query.exec();
int sequenceNumber = query.boundValue(":seqid");

Переменная :table используется в качестве IN-параметра (по умолчанию). Также bindValue() поддерживает тип параметра QSql::InOut.

Защищенный SQL

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

Включение шифрования должно быть активизировано перед установкой соединения с помощью QSqlDatabase::

open(). Вот как вы можете установить безопасное соединение с сервером MySQL:
QSqlDatabase* db = new QSqlDatabase("QMYSQL3");
// Set username, host, password, etc.
db->setConnectOptions("CLIENT_SSL");
if (!db->open()) {
    // Fallback to unencrypted connection
    db->setConnectOptions("");
    db->open();
    if (!db->open())
        // Cannot connect at all
}

Шифрование включается с помощью опции установки соединения с MySQL CLIENT_SSL. Опции установки соединения очищаются с помощью вызова setConnectOptions(""). К сожалению, эти опции специфичны для каждой базы данных. Например, для установки безопасного соединения с сервером PostgreSQL необходимо использовать совершенно другую опцию:

db->setConnectOptions("requiressl=1");

Несколько параметров должны быть разделены точкой с запятой. Вот пример того, как для установки соединения с сервером MySQL использовать одновременно шифрование и компрессию:

db->setConnectOptions("CLIENT_SSL;CLIENT_COMPRESS");

Обзор доступных опций установки соединения приводится в документации класса QSqlDatabase.


Copyright © 2002 Trolltech. Trademarks