Шаг 164.
Библиотека Qt.
Подкласс QMainWindow

    На этом шаге рассмотрим создание главных окон, а именно, познакомимся с подклассом 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 ожидается применение имени файла.

    На следующем шаге рассмотрим создание главного меню.




Предыдущий шаг Содержание Следующий шаг