Next Previous Table of Contents
Норвежская компания Troll Tech ( http://www.troll.no) предоставляет так называемый GUI инструментарий (toolkit), именуемый Qt. GUI означает "Графический Пользовательский Интерфейс" ("Graphical User Interface"), поэтому базирующиеся на Qt приложения представляются кнопками, окнами и т.п. Такие приложения осуществляют взаимодействие с пользователем, представляя в визуальной форме выполняемые функции. Этот инструментарий необходим для разработки графических приложений, которые используют X-Window интерфейс в Unix системах, потому что X не содержит предопределенного пользовательского интерфейса. И хотя другие наборы инструментов также позволяют создавать пользовательский интерфейс, Qt предоставляет некоторые технические возможности, которые делают разработку приложений очень простой. Кроме того, Qt инструментарий также доступен для Microsoft Windows систем, что позволяет разработчикам выпускать приложения для обеих платформ.
Команда KDE ( http://www.kde.org) объединилась вместе с целью сделать Unix системы более дружественными для пользователя, и решила использовать набор инструментов Qt для разработки оконного менеджера для X-Window, плюс различных приложений, включенных в дистрибутив KDE. K Desktop Environment, таким образом, включает оконный менеджер kwm, менеджер файлов kfm и панель задач kpanel как главные компоненты, а также массу первоклассных утилит и приложений. После выхода KDE множество разработчиков обратили свои взоры к новой графической среде и к тому, что она предлагала. Библиотеки KDE предоставляют все необходимые методы и классы, которые делают процесс разработки приложений с их помощью однотипным и согласованным, и положение пользователя резко улучшается, так как он теперь должен разбираться только в специфике использования данного приложения, а не обучаться общим использования очередного варианта пользовательского интерфейса. Кроме того, KDE программы интегрируются в рабочую среду и предоставляют возможность взаимодействовать с менеджером файлов, используя drag'n drop, предоставляют возможность управления сеансами (session management) и многое другое, если разработчик реализовал все возможности, предоставляемые библиотеками KDE.
И Qt инструментарий, и библиотеки KDE реализованы с использованием языка программирования C++; поэтому большинство приложений, которые используют эти библиотеки, также написаны на C++. В последующих главах мы бегло ознакомимся с библиотеками, чтобы увидеть, что за инструмент нам предлагается и как вообще создаются Qt и KDE приложения.
Как уже говорилось, Qt библиотека - это инструментарий, который предоставляет графические элементы, используемые для создания GUI приложений, и который необходим при разработке программ для X-Window. Кроме того, Qt предоставляет:
Знание Qt классов очень необходимо, даже если вы хотите разрабатывать только KDE-приложения. Чтобы получить первое представление о том, как GUI-приложения конструируются и компилируются, мы рассмотрим простую, основанную исключительно на использовании Qt программу; затем мы расширим ее до KDE-приложения.
Как правило, программа на C++ должна содержать функцию main()
, которая является стартовой точкой для выполнения приложения.
Так как мы хотим, чтобы наше приложение отображалось в графическом окне и предоставляло возможность взаимодействия с пользователем, первое, что мы должны знать, - как оно может показать себя
пользователю. Посмотрим, например, на первую программу, включенную в учебник, поставляемый как часть Qt Online Reference Documentation,
и объясним основные шаги выполнения.
Итак, почему и как появляется окно приложения:
#include <qapplication.h>
#include <qpushbutton.h>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QPushButton hello( "Hello world!" );
hello.resize( 100, 30 );
a.setMainWidget( &hello );
hello.show();
return a.exec();
}
Это приложение просто рисует окно, содержащее кнопку с надписью "Hello world". Как и для всех основанных на Qt приложений, вы первым делом
создаете экземпляр (instance) класса QApplication
, представленный переменной a
.
Затем программа создает экземпляр класса QPushButton
, называемый hello
, это будет кнопка.
Конструктор hello
получает строку в качестве параметра, которая представляет собой содержимое элемента, отображаемое как текст на кнопке.
Потом вызывается метод resize()
кнопки hello
. Это изменяет размер элемента по умолчанию (в данном случае
QPushButton), который при создании имел длину 100 пикселей и высоту 30 пикселей. Наконец, метод setMainWidget()
вызывается для объекта a
и метод show()
- для объекта hello
. QApplication
выполняет вызов a.exec()
,
входя в главный цикл событий (main event loop) и ожидая, когда он должен будет вернуть значение integer операционной системе, сигнализируя,
что приложение завершилось.
А сейчас мы кратко рассмотрим справочную документацию по Qt библиотеке.
Для того, чтобы сделать это, запустите KDevelop и выберите "Qt-library" из
"Help"-меню на панели меню. Средство просмотра документации откроет и покажет вам стартовую страницу справочного руководства Qt.
Это первое место, где необходимо искать информацию о Qt, его классах и доступных функциях. Кроме того, приведенная выше программа входит первой
в секцию "tutorials". Чтобы добраться к тем классам, которые мы хотим посмотреть,
QApplication
и QPushButton
, выберите
"Alphabetical Class List" и найдите соответствующие имена. Следуйте по любому из линков, чтобы посмотреть документацию
по соответствующему классу.
Для QApplication
вы увидите конструктор и все другие методы, которые есть в данном классе.
Если вы нажмете на линк какого-либо метода, вы получите более детальную информацию об использовании этого метода,
которая бывает очень полезна, если вы не можете определить, как правильно использовать метод, или хотите увидеть пример.
Это также относится к документации по библиотекам KDE, которые используют похожую структуру; вот и почти все,
что вы должны знать о просмотре документации по классам с помощью браузера.
Просматривая QApplication
, вы найдете все его методы, используемые в нашем примере:
QApplication()
,setMainWidget()
метод иexec()
метод.Пояснения, почему мы используем эти методы, очень простые:
QApplication
с помощью вызова конструктора, после этого мы можем использовать GUI элементы, предоставляемые Qt,a
,a
класса QApplication
.Второй объект нашей программы - кнопка (pushbutton), экземпляр класса QPushButton
. Из двух конструкторов, предоставляемых
для создания объекта, мы выбрали второй: он принимает в качестве аргумента текст, который будет отображаться как метка на кнопке; в данном случае это строка
"Hello world!". Затем мы вызвали метод resize()
для изменения размеров кнопки в соответствии с размерами ее содержимого - кнопка должна быть больше, чтобы весь текст был видимым.
А как насчет метода show()
? Сейчас вы видите, что, как и большинство других элементов, QPushButton
основывается на одиночном наследовании (single-inheritance).
Документация говорит, что QPushButton
унаследована от QButton
.
Перейдем по линку на описание класса QButton
. Это откроет множество других методов,
которые унаследованы QPushButton, мы воспользуемся ими позже для объяснения механизма сигнал/слот. В любом случае, метод show()
не присутствует в списке, следовательно, это должен быть метод, передаваемый по наследству. Класс, от которого унаследован QButton
,
QWidget
. Перейдя опять по ссылке, вы увидите целую связку методов, которые реализованы в классе QWidget
, включая
метод show()
. Теперь мы можем понять, что было сделано в примере с кнопкой:
QPushButton
, используя второй конструктор для установки текста на кнопке,QApplication
a
,show()
, унаследованный от QWidget
.После вызова метода exec()
приложение становится видимым для пользователя, отображая окно с кнопкой "Hello world!".
Таким образом, GUI программа кое в чем отличается от процедурного приложения. Основное здесь в том, что приложение входит
в так называемый "главный цикл событий" ("main event loop"). Это означает, что Qt приложение должно войти в главный цикл событий, чтобы начать обработку событий, потом программа ждет от пользователя действия и затем реагирует на него.
Следующий раздел коротко описывает,
что это значит для программиста и какие средства представляет Qt для обработки пользовательских событий.
(Для уже опытных пользователей: Кнопка не имеет родителя, он не указан в конструкторе, поэтому она - единственный элемент верхнего уровня и
работает в локальном цикле событий, и не нуждается во входе в глобальный цикл событий, см. документацию по классу QWidget
и
"The KDE Library Reference Guide")
Подведение итогов:
Приложения Qt всегда создают экземпляр класса QApplication
. Это обеспечивает нам возможность создавать окна, которые
графически представляют программу пользователю и обеспечивают взаимодействие с ним. Содержимое окна называется Главный элемент ("Main Widget"). Это означает
что все графические элементы базируются на классе QWidget
, и могут быть любыми элементами, удовлетворяющими нужды приложения
в части связи с пользователем. Поэтому все пользовательские элементы, которые необходимо сделать видимыми, должны быть унаследованы от QWidget
.
После прочтения последнего раздела вы должны уже знать:
А сейчас мы вдохнем в приложение "жизнь", научив его обрабатывать пользовательские события. Обычно пользователь имеет два средства для взаимодействия с программой: мышь и клавиатуру. В обеих случаях, графический пользовательский интерфейс должен иметь методы для регистрации действия и методы, которые делают что-то, реагируя на это действие.
Оконная система, таким образом, передает все сгенерированные пользователем события соответствующему приложению. QApplication затем передает их активному окну
как QEvent
и элементы сами решают, что с ними делать. Элемент получает событие и выполняет
QWidget::event(QEvent*)
, который решает, какое событие произошло и как реагировать; event()
, следовательно,
является главным обработчиком событий. Затем функция event()
проводит событие через так называемый фильтр событий, который определяет, что случилось и что делать
с событием. Если ни один фильтр не распознал событие, вызывается специальный обработчик событий.
Таким образом, мы должны различать:
a) События клавиатуры -- клавиши TAB и Shift-TAB :
изменяет фокус ввода с клавиатуры с текущего элемента на следующий элемент в порядке изменения фокусов. Фокус может быть установлен для элемента
вызовом setFocusPolicy
()
. Изменение фокуса обрабатывается следующими обработчиками событий: :
virtual void focusInEvent
( QFocusEvent * )
virtual void focusOutEvent
( QFocusEvent * )
b) другой ввод с клавиатуры:
virtual void keyPressEvent
( QKeyEvent * )
virtual void keyReleaseEvent
( QKeyEvent * )
c) перемещение мыши:
virtual void mouseMoveEvent ( QMouseEvent * )
virtual void enterEvent ( QEvent * )
virtual void leaveEvent ( QEvent * )
d) нажатие кнопок мыши:
virtual void mousePressEvent ( QMouseEvent * )
virtual void mouseReleaseEvent ( QMouseEvent * )
virtual void mouseDoubleClickEvent ( QMouseEvent * )
e) события окна, содержащего элемент:
virtual void moveEvent ( QMoveEvent * )
virtual void resizeEvent ( QResizeEvent * )
virtual void closeEvent ( QCloseEvent * )
Заметьте, что все функции событий virtual и protected; таким образом, вы можете переопределить события, которые вам нужны в ваших элементах,
и указать, как ваш элемент должен на них реагировать. QWidget
также содержит несколько других виртуальных методов, которые могут быть полезны в ваших программах;
это, в общем-то, все, что вам сейчас необходимо знать о QWidget
.
Сейчас мы подошли к наиболее яркому преимуществу Qt инструментария: механизм сигнал/слот. Этот механизм предлагает очень удобное и полезное
решение для реализации взаимодействия объектов, которое обычно выполняется с помощью callback
функций для различных X-Window наборов элементов.
Реализация с помощью callback
функций требует очень строгого программирования и иногда превращает задачу построения пользовательского интерфейса в очень сложную
(как об этом говорится в документации Qt и как это объяснено в книге K.Dalheimer Programming with Qt).
Troll Tech изобрела новую систему, в которой объекты могут испускать (emit) сигналы,
которые могут быть соединены (connected) с методами, объявленными как слоты (slot).
Для программиста на C++ необходимо знать несколько простых вещей об этом механизме:
Q_OBJECT
в начале (без ";");
и этот класс должен быть унаследован от QObject
.emit
, например, emit signal(parameters);
из любой функции-члена класса, который поддерживает механизм сигнал/слот,signals:
,slot
, например,
public slots:
внутри объявления класса,moc
должен быть запущен для обработки файла заголовка для подстановки макросов и выдачи файла с реализацией
(в которой не требуется разбираться). Выходной файл moc
компилируется обычным компилятором C++.QObject
- использовать класс QSignal
- см. справочное руководство
для получения дополнительной информации и примеров использования. В дальнейшем материале мы предполагаем, что используется наследование от QObject
.
Используя этот механизм, ваш класс может посылать сигналы и предоставлять слоты для присоединения к ним сигналов. Используя сигналы, вы не должны заботиться о том, кто их получает - вы должны испустить сигнал и любой слот, который вы соединили с этим сигналом, сможет прореагировать на появление сигнала. Кроме того, слоты могут использоваться как обычные методы при реализации программы.
Теперь, для того, чтобы соединить сигнал и слот, вы должны использовать метод connect()
, который предоставляет QObject
, или, где это возможно,
специальные методы, которые предоставляют объекты для установки соединения с определенными сигналами.
Чтобы объяснить, как организовать межобъектное взаимодействие, вернемся к нашему первому примеру и добавим в него простое соединение:
#include <qapplication.h>
#include <qpushbutton.h>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QPushButton hello( "Hello world!" );
hello.resize( 100, 30 );
a.setMainWidget( &hello );
connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));
hello.show();
return a.exec();
}
Как видно, единственное изменение, оживляющее кнопку, - использование метода connect()
:
connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));
. Вот и все, что мы добавили.
Что это значит? В классе QObject
метод connect()
объявляется так:
bool connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * member )
Это значит, что вы должны предоставить экземпляру QObject указатель на источник сигнала, имея в виду, что он должен уметь испускать этот сигнал, первым параметром; затем вы должны указать сигнал, для которого устанавливается соединение. Следующие два параметра - объект-получатель, который предоставляет слот, и фукнкция-член, которая и есть слот, выполняемый при получении сигнала.
Используя сигналы и слоты, объекты вашей программы могут взаимодействовать между собой проще, без точного определения типа объекта-получателя сигнала. Вы изучите подробнее использование этого механизма позднее в этой книге. Более подробная информация о механизме Сигнал/Слот также может быть найдена в "The KDE Library Reference Guide" и в Qt online-документации.
На момент написания книги KDevelop использует KDE 1.1, поэтому мы здесь рассмотрим библиотеки KDE этого релиза. Основные библиотеки KDE, которые вы будете использовать при разработке приложений KDE, следующие:
Кроме того, для специальных целей KDE предоставляет следующие библиотеки:
Теперь давайте посмотрим, что необходимо сделать, чтобы превратить наше Qt приложение в KDE приложение.
Сейчас вы увидите, что создание KDE приложения не на много сложнее, чем приложения для Qt. Для использования возможностей KDE вы просто должны включить в программу другие классы, и все будет сделано. Например, рассмотрим измененную версию примера программы Qt, приведенного выше:
#include <kapp.h>
#include <qpushbutton.h>
int main( int argc, char **argv )
{
KApplication a( argc, argv );
QPushButton hello( "Hello world!" );
hello.resize( 100, 30 );
a.setTopWidget( &hello );
connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));
hello.show();
return a.exec();
}
Как видно, в первую очередь мы изменили QApplication
на KApplication
. Далее, мы использовали вместо метода
setMainWidget()
метод setTopWidget
, который вызывает KApplication
для установки главного элемента (main widget). Вот и все! Ваше первое KDE
приложение готово - вы только должны сообщить компилятору путь к файлам KDE, упомянутым в командах "#include", и линкеру - линковать с ключом -lkdecore.
Теперь, когда вы знаете, что в общем делает функция main(), как приложения становятся видимыми и как организовать взаимодействие пользователя и объектов программы, мы переходим к следующей главе, где мы сделаем наше первое приложение с помощью KDevelop - там вы сможете также протестировать все вышеупомянутое и посмотреть результат.
Сейчас вам будет полезно посмотреть дополнительно справочное руководство по Qt, особенно в части QApplication
,
QWidget
и QObject
, документацию по библиотеке KDE-Core для класса KApplication
.
Справочник "KDE Library Reference" содержит полное описание вызова
конструкторов QApplication
и KApplication
, включая обработку аргументов командной строки.
Next Previous Table of Contents