Программирование на C++ с использованием библиотеки Qt4

         

Действие


(action).

При создании действия указывается родительский элемент и, при необходимости, пиктограмма и/или текстовая метка: QAction::QAction(QObject *parent) QAction::QAction(const QString& text, QObject *parent) QAction::QAction(const QIcon& icon, const QString& text, QObject *parent)

Метод QAction::setStatusTip(текст) определяет текст подсказки по данному действию, выводимую в строке состояния, а QAction::setShortcut(QKeySequence& shortcut) -- привязывает к действию некоторую комбинацию клавиш.

С каждым действием связывается функция-обработчик, для этого используется всё тот же метод connect, например: QAction *exitAction = new QAction(tr("В&ыход"), this); exitAction->setStatusTip(tr("Выход из программы")); exitAction->setShortcut(tr("Ctrl+Q")); connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));



Действия


Пользователь может влиять на процесс выполнения программы с помощью указателя и кнопок мыши, выбирая нужный пункт меню или кнопку на панели инструментов. Кроме того, в его распоряжении имеются клавиши со стрелками, а также различные клавиатурные комбинации. Все эти события объединены в библиотеке Qt под общим названием



Компилятора метаобъектов


moc, который автоматически формирует на языке C++ необходимый код (в папке проекта после компиляции можно найти файл moc_*.cpp).



Меню и строка состояния (файл examples-qt/02/02.h)


1 #include <QtGui>
2 3 class MainWindow : public QMainWindow { 4 Q_OBJECT 5 6 public: 7 MainWindow();
8 9 protected: 10 virtual void resizeEvent(QResizeEvent *event);
11 virtual void mouseMoveEvent(QMouseEvent *event);
12 virtual void closeEvent(QCloseEvent *event);
13 14 private slots: 15 void about();
16 17 private: 18 QAction *aboutAction; 19 QAction *exitAction; 20 QMenu *fileMenu; 21 QLabel *sb1; 22 QLabel *sb2; 23 QLabel *sb3; 24 25 bool askOnClose();
26 };

(1) Подключили заголовочный файл QtGui, в котором описаны все объекты, относящиеся к элементам графического интерфейса. Это проще, чем отдельно подключать QMainWindow, QLabel, QMenu и т.д. (3) Объявили новый класс MainWindow, использовав в качестве базового класс QMainWindow (наследника QObject). (4) Не забыли про обязательный макрос Q_OBJECT. (7) Конструктор без параметров. (10-12) Виртуальные методы, вызываемые автоматически при изменении размеров окна, при перемещении указателя мыши и при закрытии окна. (14-15) Описание слотов (функций-обработчиков). В данном случае здесь упомянута только функция, вызываемая при выборе пункта меню "Опрограмме" (т.к. все остальные обработчики -- это виртуальные функции или уже определённые методы базового класса). (17-23) Переменные-члены класса: два действия для пунктов меню, само меню и три текстовые метки для строки состояния. (25) Служебная функция, вызываемая при закрытии окна (просит подтверждения у пользователя).



Меню и строка состояния (файл examples-qt/02/02.cpp)


1 #include <QtGui>
2 #include "02.h" 3 4 MainWindow::MainWindow() { 5 6 QTextCodec *codec = QTextCodec::codecForName("CP1251");
7 QTextCodec::setCodecForTr(codec);
8 9 aboutAction = new QAction(tr("&О программе"), this);
10 aboutAction->
setStatusTip(tr("Сведения о программе"));
11 connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
12 13 exitAction = new QAction(tr("В&ыход"), this);
14 exitAction->
setStatusTip(tr("Выход из программы"));
15 exitAction->
setShortcut(tr("Ctrl+Q"));
16 connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));
17 18 fileMenu = menuBar()->
addMenu(tr("&Файл"));
19 fileMenu->
addAction(aboutAction);
20 fileMenu->
addSeparator();
21 fileMenu->
addAction(exitAction);
22 23 sb1 = new QLabel(statusBar());
24 sb2 = new QLabel(statusBar());
25 sb3 = new QLabel(statusBar());
26 27 statusBar()->
setSizeGripEnabled(false);
28 statusBar()->
addWidget(sb1, 2);
29 statusBar()->
addWidget(sb2, 1);
30 statusBar()->
addWidget(sb3, 1);
31 32 sb1->
setText(tr("Привет!"));
33 34 setMouseTracking(true);
35 } 36 37 38 void MainWindow::resizeEvent(QResizeEvent *event) { 39 QSize sz = event->
size();
40 sb2->
setText( 41 QString( "(%1, %2)" ).arg( sz.width() ).arg( sz.height() ) );
42 } 43 44 void MainWindow::mouseMoveEvent(QMouseEvent *event) { 45 QPoint pos = event->
pos();
46 sb3->
setText( 47 QString( "%1, %2" ).arg( pos.x() ).arg( pos.y() ) );
48 } 49 50 void MainWindow::about() { 51 QMessageBox::about( 52 this, tr("О программе"), 53 tr("<h2>
Простое приложение Qt4</h2>
" 54 "<p>
Окно с меню и строкой состояния"));
55 } 56 57 bool MainWindow::askOnClose() { 58 int r = QMessageBox::question( 59 this, tr("Подтвердите"), 60 tr("Выйти из программы?"), 61 QMessageBox::Yes | QMessageBox::No, 62 QMessageBox::Yes, 63 QMessageBox::Cancel | QMessageBox::Escape);
64 return (r == QMessageBox::Yes);
65 } 66 67 void MainWindow::closeEvent(QCloseEvent *event) { 68 if (askOnClose()) { 69 event->
accept();
70 } else { 71 event->
ignore();
72 } 73 } 74 75 int main(int argc, char *argv[]) { 76 QApplication app(argc, argv);
77 MainWindow mainWin; 78 mainWin.show();
79 return app.exec();
80 }




(1-2) Подключили модуль QtGui и свой заголовочный файл. (4-35) Конструктор главного окна. (6-7) Определили кодек. (9-11) Создали действие "О программе", задали для него текст подсказки и связали с функцией about, реализованной ниже. (13-16) Создали действие "Выход", задали для него текст подсказки и клавиатурное сокращение, связали его с функцией close, выполняющей закрытие окна (эта функция определена в базовом классе). (18-21) Создали меню "Файл", состоящее из двух пунктов, с разделителем между ними. (23-25) Создали три текстовые метки, в качестве родительского элемента указали строку состояния. (27-30) Убрали из строки состояния маркер для изменения размеров окна (иначе правая текстовая метка не доходит до правого края окна, что выглядит не слишком эстетично) и разместили в строке три текстовые метки. Указали для первой коэффициент растяжимости, в два раза больший, чем для остальных. (32) Вывели в первое поле строки состояния приветствие. (34)Указали, что метод mouseMoveEvent будет вызываться при движении указателя мыши, даже если её кнопки не нажаты. (38-42) Виртуальный метод, выполняемый при изменении размеров окна. Узнаём новые размеры с помощью функции QResizeEvent::size() и выводим их во второе поле строки состояния. Для преобразования целых значений к типу QString используем метасимволы %1 и %2 в строке шаблона (41), а также функцию QString::arg, которая замещает их строковым представлением своего аргумента и возвращает результат типа QString. (44-48) Виртуальный метод, вызываемый при перемещении указателя мыши. Новые координаты указателя возвращает функция QMouseeEvent::pos(). Мы выводим их в третье поле строки состояния. (50-55) Функция about выполняется при выборе пункта меню Файл | О программе. Для вывода на экран информации используется метод about, определённый для класса QMessageBox. Обратите внимание, что для форматирования текста используется язык разметки HTML. (57-73) При закрытии окна программы (по команде меню Выход, нажатием комбинации клавиш Alt+F4 или с помощью крестика в верхнем правом углу окна) исполняется виртуальный метод closeEvent (67), в котором мы вызываем функцию askOnClose (57). Последняя выводит на экран запрос на подтверждение, используя метод question класса QMessageBox. Если пользователь отвечает утвердительно, то окно зарывается (69), иначе действие отменяется (71) и выполнение программы продолжается.

Чуть позже мы узнаем, как использовать программу


Меню


Горизонтальная панель меню QMenuBar создаётся автоматически, если мы обращаемся к ней для добавления хотя бы одного вертикального меню QMenu. Например: // Определяем действия: QAction *aboutAction = new QAction(tr("&О программе"), this); QAction *exitAction = new QAction(tr("В&ыход"), this);

// Создаём вертикальное меню и добавляем // его на автоматически созданную панель QMenuBar: QMenu *fileMenu = menuBar()->addMenu(tr("&Файл")); fileMenu->addAction(aboutAction); // Добавили действие 'О программе'. fileMenu->addSeparator(); // Разделитель пунктов меню. fileMenu->addAction(exitAction); // Добавили действие 'Выход'. Здесь мы создали меню "Файл" с двумя пунктами "Опрограмме" и "Выход" и горизонтальной полосой-разделителем между ними.



Наследники класса QObject и метакомпилятор


Любые пользовательские классы, разрабатываемые программистом, обычно являются наследниками базового класса QObject (или какого-нибудь из его потомков). Только в этом случае для них можно использовать механизм сигналов и слотов, а также некоторые другие возможности, реализованные в библиотеке Qt (в частности, информацию о типах во время выполнения программы и динамические свойства объектов). При этом необходимо соблюдать следующие правила:

в секции private при объявлении класса необходимо указать макрос Q_OBJECT объявления классов, содержащих макрос Q_OBJECT, обязательно должны располагаться в заголовочном файле *.h, а не в самой программе *.cpp.

Утилита qmake просматривает заголовочные файлы проекта, и если в описании какого-нибудь класса встречается макрос Q_OBJECT, то в make-файл вставляется вызов так называемого



Обработка событий с помощью виртуальных методов


Кроме механизма сигналов и слотов, в Qt используется также старый метод виртуальных функций. Так, например, базовый класс QWidget (элемент интерфейса, виджет) и все его многочисленные потомки имеют виртуальный метод mouseMoveEvent void QWidget::mouseMoveEvent ( QMouseEvent * event ) который вызывается при перемещении указателя мыши над данным элементом. Если требуется определить какую-либо реакцию на это событие, то достаточно в собственном классе переопределить метод mouseMoveEvent. Текущие координаты мыши в системе отсчёта данного виджета можно узнать с помощью методов QMouseEvent::x() и QMouseEvent::y(). Следует иметь в виду, что по умолчанию метод mouseMoveEvent вызывается, только если при перемещении указателя мыши удерживается любая из её кнопок. Чтобы это происходило независимо от состояния кнопок, надо для данного виджета вызвать метод setMouseTracking(true).

Аналогично можно обрабатывать событие изменения размеров любого элемента, только в этом случае для него придётся переопределить метод resizeEvent.



Пример приложения с меню и строкой состояния


В листингах 6 и 7 приведён текст небольшой программы, в которой иллюстрируются все описанные в данном разделе элементы: меню, строка состояния с несколькими текстовыми полями, обработка перемещения указателя мыши и изменения размеров окна с помощью виртуальных функций, а также определение собственного класса на основе QObject. На рис. показано, как выглядит окно программы в Windows и Linux.


Рис. Меню и строка состояния: внешний вид окна программы в системе Windows (верхний скриншот) и Linux (для двух различных тем рабочего стола). В строке состояния отображаются размеры окна и координаты указателя мыши



QtDesigner


для определения действий, создания меню и других элементов интерфейса.



Строка состояния


Строка состояния QStatusBar создаётся автоматически в нижней части главного окна приложения, если в программе хоть раз вызвается метод MainWindow::statusBar. При наведении указателя мыши на кнопку панели инструментов или пункт меню в строке состояния на время появляется текст подсказки, если этот текст определён для данной кнопки или данного пункта.

Указатель на экземпляр QStatusBar можно получить с помощью метода QMainWindow::statusBar(). Чтобы вывести в строке состояния произвольный текст (и затереть предыдущий), используется функция showMessage: void QStatusBar::showMessage( const QString &message, // Выводимая строка. int timeout = 0 ) // Кол-во миллисекунд. Если timeout>0, то сообщение автоматически исчезает через указанный промежуток времени, а на его место возвращается текст предыдущей надписи.

По умолчанию строка состояния представляется в виде одной панели, располагаемой по всей ширине родительского окна. Но её можно разбить по ширине на отдельные поля, если вставить в неё другие элементы, например, QLabel. Для этого предназначены методы addWidget, addPermanentWidget и insertWidget: void QStatusBar::addWidget ( QWidget *widget, // Вставляемый элемент. int stretch = 0 ) // Коэффициент растяжимости.

void QStatusBar::addPermanentWidget ( QWidget *widget, int stretch = 0 )

int QStatusBar::insertWidget ( int index, // Позиция. QWidget *widget, // Вставляемый элемент. int stretch = 0 ) // Коэффициент растяжимости.

Элементы, добавляемые с помощью метода addPermanentWidget, располагаются в правой части строки состояния и не затираются сообщениями, выводимыми с помощью showMessage.

В нижней правой части строки состояния по умолчанию отображается специальный маркер, который можно "зацепить" указателем мыши для изменения размеров окна. Его показ можно запретить, вызвав QStatusBar::setSizeGripEnabled(false). При этом возможность изменять размеры окна по-прежнему остаётся.