|
||
![]() |
||
В этой главе мы расскажем -- как использовать функциональные возможности библиотеки Qt, для создания графического интерфейса с пользователем, в программах на языке C++. Напишем несколько небольших программ. А так же дадим краткое введение в два ключевых понятия Qt: "сигналы и слоты" и "разметка" (layout). В Главе 2 будут даны более обширные сведения, а в Главе 3 рассмотрим пример создания настоящего приложения.
Ниже приводится текст простейшей Qt программы:
1 #include <qapplication.h> 2 #include <qlabel.h> 3 int main(int argc, char *argv[]) 4 { 5 QApplication app(argc, argv); 6 QLabel *label = new QLabel("Hello, Qt!", 0); 7 app.setMainWidget(label); 8 label->show(); 9 return app.exec(); 10 }Здесь, в строках 1 и 2, подключаются определения классов QApplication и QLabel.
В строке 5 создается экземпляр класса QApplication, который управляет ресурсами приложения. Конструктору QApplication передаются аргументы argc и argv, поскольку Qt имеет возможность обрабатывать аргументы командной строки.
В строке 6 создается визуальный компонент QLabel, который отображает надпись "Hello, Qt!". В терминологии Qt, все визуальные компоненты, из которых строится графический интерфейс, называются виджетами (widgets). Кнопки, меню, полосы прокрутки и разнообразные рамки -- все это виджеты. Одни виджеты могут содержать в себе другие виджеты, например, главное окно приложения -- это самый обычный виджет, который может содержать QMenuBar, QToolBar, QStatusBar и др. Аргумент 0, передаваемый конструктору QLabel (в строке 6) -- это "пустой" (null) указатель, который сообщает о том, что этот виджет не имеет "хозяина", т.е. не включается в другой виджет.
В строке 7 назначается "главный" виджет приложения. Когда пользователь закрывает "главный" виджет приложения (например, нажатием на кнопку "X" в заголовке окна), то программа завершает свою работу. Если в программе не назначить главный виджет, то она продолжит исполнение в фоновом режиме даже после того, как пользователь закроет окно.
В строке 8, метка делается видимой. Виджеты всегда создаются невидимыми, чтобы у программиста оставалась возможность настроить параметры отображения до того, как они станут видимы.
В строке 9 выполняется передача управления библиотеке Qt. С этого момента программа переходит в режим ожидания, когда она ничего не делает, а просто ждет действий пользователя, например, нажатие на клавишу или кнопку мыши.
Любое действие пользователя порождает событие (другими словами -- "сообщение"), в ответ на которое программа может вызвать одну или более функций. В этом смысле, приложения с графическим интерфейсом кардинально отличаются от обычных программ, с пакетной обработкой данных, которые приняв ввод от пользователя, они самостоятельно обрабатывают его, выдают результаты и завершают свою работу без дальнейшего участия человека.
Рисунок 1.1. Окно приложения в Windows XP
Теперь самое время проверить работу нашего приложения. Но прежде всего -- необходимо, чтобы у вас была установлена Qt 3.2 (или более поздняя версия), а переменная окружения PATH содержала корректный путь к каталогу bin. (В Windows настройка переменной PATH выполняется автоматически, в процессе установки библиотеки Qt)
Скопируйте текст программы в файл, с именем hello.cpp, в каталог hello.
Перейдите в этот каталог и дайте команду:
qmake -projectона создаст платформо-независимый файл проекта (hello.pro), а затем дайте следующую команду:
qmake hello.proЭта команда создаст Makefile, на основе файла проекта. Дайте команду make, чтобы скомпилировать программу и затем запустите ее, набрав в командной строке hello (в Windows) или ./hello (в Unix) или open hello.app (в Mac OS X). Если вы работаете в Windows и используете Microsoft Visual C++, то вместо команды make вы должны дать команду nmake. Как альтернативный вариант -- вы можете создать проект Visual Studio из файла hello.pro, запустив команду:
qmake -tp vc hello.proи затем скомпилировать программу в Visual Studio.
Рисунок 1.2. Метка с форматированным текстом.
А теперь немного развлечемся. Изменим внешний вид метки, добавив форматирование текста в стиле HTML. Для этого, замените строку
QLabel *label = new QLabel("Hello, Qt!", 0);на
QLabel *label = new QLabel("<h2 ><i>Hello</i> " "<font color=red>Qt!</font></h2>", 0);и пересоберите приложение.
Следующий пример показывает -- как организовать реакцию приложения на действия пользователя. Это приложение содержит кнопку, при нажатии на которую программа закрывается. Исходный текст очень похож на предыдущий пример, за исключением того, что теперь, в качестве главного виджета, вместо QLabel используется QPushButton, и добавлен код, который обслуживает факт ее нажатия.
Рисунок 1.3. Приложение Quit.
1 #include <qapplication.h> 2 #include <qpushbutton.h> 3 int main(int argc, char *argv[]) 4 { 5 QApplication app(argc, argv); 6 QPushButton *button = new QPushButton("Quit", 0); 7 QObject::connect(button, SIGNAL(clicked()), 8 &app, SLOT(quit())); 9 app.setMainWidget(button); 10 button->show(); 11 return app.exec(); 12 }Виджеты Qt имеют возможность посылать приложению сигналы, извещая его о том, что пользователь произвел какое-либо действие или о том, что виджет изменил свое состояние [3] . Например, экземпляры класса QPushButton посылают приложению сигнал clicked(), когда пользователь нажимает на кнопку. Сигнал может быть "подключен" к функции-обработчику (такие функции-обработчики в Qt называются слотами). Таким образом, когда виджет посылает сигнал, автоматически вызывается слот. В нашем примере мы подключили сигнал clicked(), от кнопки, к слоту quit(), экземпляра класса QApplication. Вызовы SIGNAL() и SLOT() -- это макроопределения, более подробно мы остановимся на них в следующей главе.
Теперь соберем приложение. Надеемся, что вы уже создали каталог quit и разместили в нем файл quit.cpp. Дайте команду qmake, для создания файла проекта, а затем второй раз -- для создания Makefile:
qmake -project qmake quit.proТеперь соберите приложение командой make и запустите его. Если вы щелкнете по кнопке "Quit" или нажмете на клавиатуре клавишу "Пробел", то приложение завершит свою работу.
В следующем примере мы покажем как можно использовать сигналы и слоты для синхронизации двух виджетов. Эта программа предлагает пользователю ввести свой возраст. Сделать это можно либо с помощью кнопок управления счетчиком, либо с помощью ползунка.
Рисунок 1.4. Приложение Age.
Приложение содержит три виджета: QSpinBox, QSlider и QHBox (область горизонтальной разметки). Главным виджетом приложения назначен QHBox. Компоненты QSpinBox и QSlider помещены внутрь QHBox и являются подчиненными, по отношению к нему.
Рисунок 1.5. Виджеты приложения Age.
1 #include <qapplication.h> 2 #include <qhbox.h> 3 #include <qslider.h> 4 #include <qspinbox.h> 5 int main(int argc, char *argv[]) 6 { 7 QApplication app(argc, argv); 8 QHBox *hbox = new QHBox(0); 9 hbox->setCaption("Enter Your Age"); 10 hbox->setMargin(6); 11 hbox->setSpacing(6); 12 QSpinBox *spinBox = new QSpinBox(hbox); 13 QSlider *slider = new QSlider(Qt::Horizontal, hbox); 14 spinBox->setRange(0, 130); 15 slider->setRange(0, 130); 16 QObject::connect(spinBox, SIGNAL(valueChanged(int)), 17 slider, SLOT(setValue(int))); 18 QObject::connect(slider, SIGNAL(valueChanged(int)), 19 spinBox, SLOT(setValue(int))); 20 spinBox->setValue(35); 21 app.setMainWidget(hbox); 22 hbox->show(); 23 return app.exec(); 24 }В строках с 8 по 11 создается и настраивается QHBox. [4] Чтобы вывести текст в заголовке окна, вызывается setCaption(). А затем устанавливается размер пустого пространства (6 пикселей) вокруг и между подчиненными виджетами.
В строках 12 и 13 создаются QSpinBox и QSlider, которым, в качестве владельца, назначается QHBox.
Не смотря на то, что мы явно не задали ни положение, ни размеры виджетов QSpinBox и QSlider, тем менее они очень аккуратно расположились внутри QHBox. Собственно для этого и предназначен QHBox. Он выполняет автоматическое размещение подчиненных виджетов, назначая им координаты размещения и размеры, в зависимости от их требований и собственных настроек. В Qt имеется много классов, подобных QHBox, которые избавляют нас от рутинной работы по ручной подгонке положения и размеров визуальных компонентов.
В строках 14 и 15 устанавливаются допустимые пределы изменения счетчика и ползунка. (Мы можем смело предположить, что возраст нашего пользователя едва ли превысит 130 лет.) Два вызова connect(), в строках с 16 по 19 синхронизируют ползунок и счетчик, благодаря чему они всегда будут отображать одно и то же значение. Всякий раз, когда значение одного из виджетов изменяется, он посылает сигнал valueChanged( int ), который поступает в слот setValue( int ) другого виджета.
В строке 20 устанавливается первоначальное значение (35) счетчика. Когда это происходит, счетчик посылает сигнал valueChanged(int), со значением входного аргумента, равным 35. Это число передается в слот setValue(int) виджета QSlider, который устанавливает значение этого виджета равным 35. После этого уже QSlider посылает сигнал valueChanged(int), поскольку его значение только что изменилось, вызывая таким образом слот setValue(int) виджета QSpinBox. Но на этот раз счетчик не посылает сигнал, поскольку его значение и так было равно 35. Таким образом предотвращается бесконечная рекурсия. Рисунок 1.6 иллюстрирует эту ситуацию.
Рисунок 1.6. Изменение одного значения вызывает изменение другого.
В строке 22 QHBox делается видимым (вместе со всеми подчиненными виджетами).
Подход к формированию интерфейса в Qt очень прост для понимания и чрезвычайно гибок. В общем случае, программист выбирает необходимые ему виджеты, размещает их внутри областей выравнивания (layouts), которые в свою очередь принимают на себя обязанности по размещению виджетов, и настраивает свойства виджетов. На заключительном этапе устанавливаются взаимосвязи виджетов, через механизм сигналов и слотов, которые обусловливают поведение пользовательского интерфейса.
Справочная система в Qt -- это пожалуй самый основной инструмент любого разработчика. Она описывает все классы и функции в этой библиотеке. (Документация к Qt 3.2 включает в себя описанее более 400 классов и 6000 функций.) В этой книге вы встретитесь с большим количеством классов и функций Qt, но далеко не со всеми. Поэтому совершенно необходимо, чтобы вы самостоятельно ознакомились со справочной системой Qt.
Стили виджетов |
|
---|---|
Скриншоты, которые мы до сих пор видели, были получены в Windows XP. Однако внешний вид виджетов изменяется, в зависимости от платформы, на которой запускается приложение. С другой стороны, Qt в состоянии эмулировать внешний вид любой из поддерживаемых платформ. |
|
Windows |
Motif |
MotifPlus |
CDE |
Platinum |
SGI |
Рисунок 1.7. Стили, поддерживаемые Qt на любой
платформе.
|
|
Пользователь может задать стиль отображения через
параметр командной строки -style. Например, чтобы
запустить приложение Age со стилем отображения
Platinum в ОС Unix, нужно дать команду:
./age -style=Platinum |
|
Windows XP |
Mac |
Рисунок 1.8. Платформо-зависимые стили.
|
|
В отличие от других, платформо-зависимые стили (Windows XP и Mac) доступны только на этих платформах, т.к. в этом случае отрисовка виджетов производится графическим ядром операционной системы. |
Документация хранится в каталоге doc\html в виде html-файлов. Для ее просмотра может использоваться любой web-браузер. Но Qt имеет свою утилиту просмотра документации -- Qt Assistant, которая предоставляет очень удобный способ навигации по справочнику, гораздо удобнее, чем этого можно добиться в web-браузере. Чтобы запустить утилиту -- выберите пункт Qt 3.2.x|Qt Assistant в меню "Пуск" операционной системы Windows или дайте команду assistant в Unix.
Рисунок 1.9. Внешний вид программы Qt Assistant.
Ссылки в разделе "API Reference" дают возможность навигации по классам различными способами. Так например, перейдя по ссылке "All Classes" вы получите список всех классов библиотеки. По ссылке "Main Classes" -- только самые основные классы. В качестве упражнения попробуйте найти описания классов и функций, использовавшихся в нашем приложении. Обратите внимание: наследуемые методы описываются в базовых классах, например, описание класса QPushButton не содержит метода show(), поскольку он наследуется от класса QWidget. На рисунке ниже приводится диаграмма наследования для классов, использованных в нашем приложении:
Рисунок 1.10. Дерево наследования интересующих нас классов.
Справочная документация для текущей версии Qt (и некоторых, более ранних версий) выкладывается в он-лайн по адресу: http://doc.trolltech.com/. Здесь же вы найдете отдельные статьи из ежеквартальника Qt Quarterly, который рассылается всем коммерческим пользователям.
|