На этом шаге рассмотрим создание главных окон, а именно, познакомимся с подклассом QMainWindow.
Изучив следующие шаги, вы научитесь создавать главные окна при помощи средств разработки Qt, будете способны построить законченный графический пользовательский интерфейс приложения, который имеет меню, панели инструментов и строку состояния и все необходимые приложению диалоговые окна.
Главное окно приложения обеспечивает каркас для построения пользовательского интерфейса приложения. Этот и следующие шаги будет строиться на основе главного окна приложения Электронная таблица, показанного на рис. 1. В приложении Электронная таблица используются созданные ранее диалоговые окна поиска, перехода к ячейке и сортировки.
Рис.1. Приложение Электронная таблица
Главное окно приложения создается в виде подкласса QMainWindow. Многие из методов, представленных в предыдущих шагах, также подходят для построения главных окон, поскольку оба класса, QDialog и QMainWindow, являются потомками QWidget.
Главные окна можно создавать при помощи Qt Designer, но мы рассмотрим, как это все делается при непосредственном программировании.
Исходный код программы главного окна приложения Электронная таблица содержится в двух файлах: mainwindow.h и mainwindow.cpp. Сначала приведем заголовочный файл.
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> class QAction; class QLabel; class FindDialog; class Spreadsheet; //определяем класс MainWindow как подкласс QMainWindow class MainWindow : public QMainWindow { //содержит макрос Q_OBJECT, поскольку имеет собственные сигналы и слоты Q_OBJECT public: MainWindow(); protected: /*Функция closeEvent() определена в QWidget как виртуальная функция; она автоматически вызывается при закрытии окна пользователем. Она переопределяется в MainWindow для того, чтобы можно было задать пользователю стандартный вопрос относительно возможности сохранения изменений ("Сохранить изменеия в файле?") и чтобы сохранить на диске пользовательские настройки*/ void closeEvent(QCloseEvent *event); private slots: /*Некоторые функции меню, как, например, File/New (Файл/Новый) или Help/About (Помощь/О программе), реализованы в MainWindow в виде закрытых слотов. Большинство слотов возвращают значение типа void, однако save() и saveAs() возвращают значение типа bool. Возвращаемое значение игнорируется при выполнении слота в ответ на сигнал, но при вызове слота в качестве функции мы можем воспользоваться возвращаемым значением, как это мы можем делать при вызове любой обычной функции C++*/ void newFile(); void open(); bool save(); bool saveAs(); void find(); void goToCell(); void sort(); void about(); void openRecentFile(); void updateStatusBar(); void spreadsheetModified(); private: /*Для поддержки пользовательского интерфейса главному окну потребуется еще несколько закрытых слотов и закрытых функций*/ void createActions(); void createMenus(); void createContextMenu(); void createToolBars(); void createStatusBar(); void readSettings(); void writeSettings(); bool okToContinue(); bool loadFile(const QString &fileName); bool saveFile(const QString &fileName); void setCurrentFile(const QString &fileName); void updateRecentFileActions(); QString strippedName(const QString &fullFileName); /*Кроме этих закрытых слотов и закрытых функций в подклассе MainWindow имеется также много закрытых переменных. По мере их использования мы будем объяснять их назначение*/ Spreadsheet *spreadsheet; FindDialog *findDialog; QLabel *locationLabel; QLabel *formulaLabel; QStringList recentFiles; QString curFile; enum { MaxRecentFiles = 5 }; QAction * recentFileActions[MaxRecentFiles]; QAction *separatorAction; //определение пунктов меню QMenu *fileMenu; QMenu *editMenu; QMenu *selectSubMenu; QMenu *toolsMenu; QMenu *optionsMenu; QMenu *helpMenu; //определение панелей инструментов QToolBar *fileToolBar; QToolBar *editToolBar; //определение команд меню QAction *newAction; QAction *openAction; QAction *saveAction; QAction *saveAsAction; QAction *exitAction; QAction *cutAction; QAction *copyAction; QAction *pasteAction; QAction *deleteAction; QAction *selectRowAction; QAction *selectColumnAction; QAction *selectAllAction; QAction *findAction; QAction *goToCellAction; QAction *recalculateAction; QAction *sortAction; QAction *showGridAction; QAction *autoRecalcAction; QAction *aboutAction; QAction *aboutQtAction; }; #endif
Теперь кратко рассмотрим реализацию этого подкласса.
/*включаем заголовочные файлы <QtGui> и <QtWidgets>, которые содержит определения всех классов Qt, используемых нашим подклассом. Также включаем некоторые пользовательские заголовочные файлы из предыдущих шагов, а именно finddialog.h, gotocelldialog. h и sortdialog.h*/ #include <QtGui> #include <QtWidgets> #include "finddialog.h" #include "gotocelldialog.h" #include "mainwindow.h" #include "sortdialog.h" #include "spreadsheet.h" MainWindow::MainWindow() { /*В конструкторе начинаем создание виджета электронная таблица Spreadsheet. Класс Spreadsheet является подклассом QTableWidget, который обладает некоторыми возможностями электронной таблицы; например, он поддерживает формулы электронной таблицы*/ spreadsheet = new Spreadsheet; /*определяем его в качестве центрального виджета главного окна. Центральный виджет занимает среднюю часть главного окна (см. рис. 2).*/ setCent ralWidget(spreadsheet); /*вызываем закрытые функции сreateАсtions(),createMenus(), createContextMenu(), createToolBars() и createStatusBar() для построения остальной части главного окна*/ createActions(); createMenus(); createContextMenu(); createToolBars(); createStatusBar(); /*вызываем закрытую функцию readSettings() для чтения настроек, сохраненных в приложении*/ readSettings(); /*инициализируем указатель findDialog в нулевое значение, а при первом вызове MainWindow::find() создадим объект FindDialog*/ findDialog = 0; /*в качестве пиктограммы окна мы задаем PNG-файл: icon. png. Qt поддерживает многие форматы графических файлов, включая BMP, GIF, JPEG, PNG, PNM, SVG, TIFF, XBM и ХРМ. Функция QWidget::setWindowIcon() устанавливает пиктограмму в левый верхний угол окна. К сожалению, не существует независимого от платформы способа установки пиктограммы приложения, отображаемого на рабочем столе компьютера*/ setWindowIcon(QIcon(":/images/icon.png")); setCurrentFile(""); }
Рис.2. Области главного окна QMainWindow
В приложениях с графическим пользовательским интерфейсом обычно используется много изображений. Существует много различных методов, предназначенных для работы приложения с изображениями. Наиболее распространенными являются следующие:
Будем использовать механизм определения ресурсов, поскольку он более удобен, чем загрузка файлов во время выполнения приложения, и он работает со всеми поддерживаемыми форматами файлов. Мы храним изображения в подкаталоге images исходного дерева.
Для применения системы ресурсов Qt мы должны создать файл ресурсов и добавить в файл .pro строку, которая задает этот файл ресурсов. В нашем примере мы назвали файл ресурсов spreadsheet.qrc, поэтому в файл .pro мы добавляем следующую строку:
RESOURCES = spreadsheet.qrc
Сам файл ресурсов имеет простой XML-формат, показанный ниже:
<RCC> <qresource> <file>images/icon.png</file> <file>images/new.png</file> <file>images/open.png</file> <file>images/save.png</file> <file>images/cut.png</file> <file>images/copy.png</file> <file>images/paste.png</file> <file>images/find.png</file> <file>images/gotocell.png</file> </qresource> </RCC>
Файлы ресурсов после компиляции входят в состав исполняемого модуля приложения, поэтому они не могут теряться. При ссылке на ресурсы мы используем префикс пути :/ (двоеточие и слеш), и именно поэтому пиктограмма задается как :/images/icon.png. Ресурсами могут быть любые файлы (не только изображения), и мы можем их использовать в большинстве случаев, когда в Qt ожидается применение имени файла.
На следующем шаге рассмотрим создание главного меню.