Создание подкласса QMainWindow
Создание подкласса QMainWindow
Главное окно приложения создается в виде подкласса QMainWindow. Многие из представленных в главе 2 методов также подходят для построения главных окон, поскольку оба класса QDialog и QMainWindow являются наследниками QWidget.
Главные окна можно создавать при помощи Qt Designer, но в данной главе мы продемонстрируем, как это все делается при непосредственном программировании. Если вы предпочитаете пользоваться визуальными средствами проектирования, то необходимую информацию вы сможете найти в главе «Creating a Main Window Application» (Создание приложения на основе класса главного окна) в онлайновом руководстве по Qt Designer.
Исходный код программы главного окна приложения Электронная таблица содержится в двух файлах: mainwindow.h и mainwindow.cpp. Сначала приведем заголовочный файл:
01 #ifndef MAINWINDOW_H
02 #define MAINWINDOW_H
03 #include <QMainWindow>
04 class QAction;
05 class QLabel;
06 class FindDialog;
07 class Spreadsheet;
08 class MainWindow : public QMainWindow
09 {
10 Q_OBJECT
11 public:
12 MainWindow();
13 protected:
14 void closeEvent(QCloseEvent *event);
Мы определяем класс MainWindow как подкласс QMainWindow. Он содержит макрос Q_OBJECT, поскольку имеет собственные сигналы и слоты.
Функция closeEvent() определена в QWidget как виртуальная функция; она автоматически вызывается при закрытии окна пользователем. Она переопределяется в MainWindow для того, чтобы можно было задать пользователю стандартный вопрос относительно возможности сохранения изменений («Do you want to save your changes?») и чтобы сохранить на диске пользовательские настройки.
15 private slots:
16 void newFile();
17 void open();
18 bool save();
19 bool saveAs();
20 void find();
21 void goToCell();
22 void sort();
23 void about();
Некоторые функции меню, как, например, File | New (Файл | Создать) или Help | About (Помощь | О программе), реализованы в MainWindow в виде закрытых слотов. Большинство слотов возвращают значение типа void, однако save() и saveAs() возвращают значение типа bool. Возвращаемое значение игнорируется при выполнении слота в ответ на сигнал, но при вызове слота в качестве функции мы может воспользоваться возвращаемым значением, как это мы можем делать при вызове любой обычной функции С++.
24 void openRecentFile();
25 void updateStatusBar();
26 void spreadsheetModified();
27 private:
28 void createActions();
29 void createMenus();
30 void createContextMenu();
31 void createToolBars();
32 void createStatusBar();
33 void readSettings();
34 void writeSettings();
35 bool okToContinue();
36 bool loadFile(const QString &fileName);
37 bool saveFile(const QString &fileName);
38 void setCurrentFile(const QString &fileName);
39 void updateRecentFileActions();
40 QString strippedName(const QString &fullFileName);
Для поддержки пользовательского интерфейса главному окну потребуется еще несколько закрытых слотов и закрытых функций.
41 Spreadsheet *spreadsheet;
42 FindDialog *findDialog;
43 QLabel *locationLabel;
44 QLabel *formulaLabel;
45 QStringList recentFiles;
46 QString curFile;
47 enum { MaxRecentFiles = 5 };
48 QAction *recentFileActions[MaxRecentFiles];
49 QAction *separatorAction;
50 QMenu *fileMenu;
51 QMenu *editMenu;
…
52 QToolBar *fileToolBar;
53 QToolBar *editToolBar;
54 QAction *newAction;
55 QAction *openAction;
…
56 QAction *aboutQtAction;
57 };
58 #endif
Кроме этих закрытых слотов и закрытых функций в подклассе MainWindow имеется также много закрытых переменных. По мере их использования мы будем объяснять их назначение.
Теперь мы кратко рассмотрим реализацию этого подкласса:
01 #include <QtGui>
02 #include "finddialog.h"
03 #include "gotocelldialog.h"
04 #include "mainwindow.h"
05 #include "sortdialog.h"
06 #include "spreadsheet.h"
Мы включаем заголовочный файл <QtGui>, который содержит определения всех классов Qt, используемых нашим подклассом. Мы также включаем некоторые пользовательские заголовочные файлы из главы 2, а именно finddialog.h, gotocelldialog.h и sortdialog.h.
07 MainWindow::MainWindow()
08 {
09 spreadsheet = new Spreadsheet;
10 setCentralWidget(spreadsheet);
11 createActions();
12 createMenus();
13 createContextMenu();
14 createToolBars();
15 createStatusBar();
16 readSettings();
17 findDialog = 0;
18 setWindowIcon(QIcon(":/images/icon.png"));
19 setCurrentFile("");
20 }
В конструкторе мы начинаем создание виджета Электронная таблица Spreadsheet и определяем его в качестве центрального виджета главного окна. Центральный виджет занимает среднюю часть главного окна (см. рис. 3.2). Класс Spreadsheet является подклассом QTableWidget, который обладает некоторыми возможностями электронной таблицы: например, он поддерживает формулы электронной таблицы. Реализацию этого класса мы рассмотрим в главе 4.
Рис. 3.2. Области главного окна QMainWindow.
Мы вызываем закрытые функции createActions(), createMenus(), createContextMenu(), createToolBars() и createStatusBar() для построения остальной части главного окна. Мы также вызываем закрытую функцию readSettings() для чтения настроек, сохраненных в приложении.
Мы инициализируем указатель findDialog в нулевое значение, а при первом вызове MainWindow::find() мы создадим объект FindDialog. B конце конструктора в качестве пиктограммы окна мы задаем PNG—файл: icon.png. Qt поддерживает многие форматы графических файлов, включая BMP, GIF[4], JPEG, PNG, PNM, XBM и XPM. Функция QWidget::setWindowIcon() устанавливает пиктограмму в левый верхний угол окна. К сожалению, не существует независимого от платформы способа установки пиктограммы приложения, отображаемого на рабочем столе компьютера. Описание этой процедуры для различных платформ можно найти в сети Интернет по адресу http://doc.trolltech.com/4.1/appicon.html.
В приложениях с графическим пользовательским интерфейсом обычно используется много изображений. Существует много различных методов, предназначенных для работы приложения с изображениями. Наиболее распространенными являются:
• хранение изображений в файлах и загрузка их во время выполнения приложения;
• включение файлов XPM в исходный код программы; это возможно, поскольку файлы XPM являются совместимыми с файлами исходного кода С++);
• использование механизма определения ресурсов, предусмотренного в Qt.
Мы используем здесь механизм определения ресурсов, поскольку он более удобен, чем загрузка файлов во время выполнения приложения, и он работает со всеми поддерживаемыми форматами графических файлов. Мы храним изображения в подкаталоге images исходного дерева.
Для применения системы ресурсов Qt мы должны создать файл ресурсов и добавить в файл .pro строку, которая задает этот файл ресурсов. В нашем примере мы назвали файл ресурсов spreadsheet.qrc, поэтому в файл .pro мы добавляем следующую строку:
RESOURCES = spreadsheet.qrc
Сам файл ресурсов имеет простой XML—формат. Ниже показан фрагмент из используемого нами файла ресурсов:
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>images/icon.png</file>
…
<file>images/gotocell.png</file>
</qresource>
</RCC>
Файлы ресурсов после компиляции входят в состав исполняемого модуля приложения, поэтому они не могут теряться. При ссылке на ресурсы мы используемпрефикс пути :/ (двоеточие и слеш), и именно поэтому пиктограмма задается как :/images/icon.png. Ресурсами могут быть любые файлы (не только изображения), и мы можем их использовать в большинстве случаев, когда в Qt ожидается применение имени файла. Они более подробно рассматриваются в гл. 12.