Subclassing QMainWindow

An application's main window is created by subclassing QMainWindow. Many of the techniques we saw in Chapter 2 for creating dialogs are also relevant for creating main windows, since both QDialog and QMainWindow inherit from QWidget.

Main windows can be created using Qt Designer, but in this chapter we will use code to demonstrate how it's done. If you prefer the more visual approach, see the "Creating a Main Window Application" chapter in Qt Designer's manual.

The source code for the Spreadsheet application's main window is spread across mainwindow.h and mainwindow.cpp. Let's start with the header file:

#ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include class QAction; class QLabel; class FindDialog; class Spreadsheet; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0, const char *name = 0); protected: void closeEvent(QCloseEvent *event); void contextMenuEvent(QContextMenuEvent *event);

We define the class MainWindow as a subclass of QMainWindow. It contains the Q_OBJECT macro because it provides its own signals and slots.

The closeEvent() function is a virtual function in QWidget that is automatically called when the user closes the window. It is reimplemented in MainWindow so that we can ask the user the standard question "Do you want to save your changes?" and to save user preferences to disk.

Similarly, the contextMenuEvent() function is called when the user right-clicks a widget or presses a platform-specific Menu key. It is reimplemented in MainWindow to pop up a context menu.

private slots: void newFile(); void open(); bool save(); bool saveAs(); void find(); void goToCell(); void sort(); void about();

Some menu options, like File|New and Help|About, are implemented as private slots in MainWindow. Most slots have void as their return value, but save() and saveAs() return a bool. The return value is ignored when a slot is executed in response to a signal, but when we call a slot as a function the return value is available to us just as it is when we call any ordinary C++ function.

void updateCellIndicators() void spreadsheetModified(); void openRecentFile(int param); private: void createActions(); void createMenus(); void createToolBars(); void createStatusBar(); void readSettings(); void writeSettings(); bool maybeSave(); void loadFile(const QString &fileName); void saveFile(const QString &fileName); void setCurrentFile(const QString &fileName); void updateRecentFileItems(); QString strippedName(const QString &fullFileName);

The main window needs some more private slots and several private functions to support the user interface.

Spreadsheet *spreadsheet; FindDialog *findDialog; QLabel *locationLabel; QLabel *formulaLabel; QLabel *modLabel; QStringList recentFiles; QString curFile; QString fileFilters; bool modified; enum { MaxRecentFiles = 5 }; int recentFileIds[MaxRecentFiles]; QPopupMenu *fileMenu; QPopupMenu *editMenu; QPopupMenu *selectSubMenu; QPopupMenu *toolsMenu; QPopupMenu *optionsMenu; QPopupMenu *helpMenu; QToolBar *fileToolBar; QToolBar *editToolBar; QAction *newAct; QAction *openAct; QAction *saveAct; ... QAction *aboutAct; QAction *aboutQtAct; }; #endif

In addition to its private slots and private functions, MainWindow also has lots of private variables. All of these will be explained as we use them.

We will now review the implementation:

#include #include #include #include #include #include #include #include #include #include #include #include "cell.h" #include "finddialog.h" #include "gotocelldialog.h" #include "mainwindow.h" #include "sortdialog.h" #include "spreadsheet.h"

We include the header files for the Qt classes used in our subclass, and also some custom header files, notably finddialog.h, gotocelldialog.h, and sortdialog.h from Chapter 2.

MainWindow::MainWindow(QWidget *parent, const char *name) : QMainWindow(parent, name) { spreadsheet = new Spreadsheet(this); setCentralWidget(spreadsheet); createActions(); createMenus(); createToolBars(); createStatusBar(); readSettings(); setCaption(tr("Spreadsheet")); setIcon(QPixmap::fromMimeSource("icon.png")); findDialog = 0; fileFilters = tr("Spreadsheet files (*.sp)"); modified = false; }

In the constructor, we begin by creating a Spreadsheet widget and setting it to be the main window's central widget. The central widget occupies the area between the toolbars and the status bar. The Spreadsheet class is a QTable subclass with some spreadsheet capabilities, such as support for spreadsheet formulas. We will implement it in Chapter 4.

Figure 3.2. QMainWindow's constituent widgets

Then we call the private functions createActions(), createMenus(), create-ToolBars(), and createStatusBar() to create the rest of the main window. We also call the private function readSettings() to read the application's stored settings.

We set the window's icon to icon.png, a PNG file. Qt supports many image formats, including BMP, GIF,[*] JPEG, MNG, PNG, PNM, XBM, and XPM. Calling QWidget::setIcon() sets the icon shown in the top-left corner of the window. Unfortunately, there is no platform-independent way of setting the application icon that appears on the desktop. The procedure is explained at http://doc.trolltech.com/3.2/appicon.html.

[*] If you are in a country that recognizes software patents and where Unisys holds a patent on LZW decompression, Unisys may require you to license the technology to use GIF. Because of this, GIF support is disabled in Qt by default. We believe that this patent will have expired worldwide by the end of 2004.

GUI applications generally use many images, with some images being used in several different contexts. Qt has a variety of methods for providing images to the application. The most common are:

Here we use the "image collection" approach because it is easier and more efficient than loading files at run-time, and it works with any supported file format. The images are stored in the source tree in a subdirectory called images. By adding the entry

IMAGES = images/icon.png images/new.png images/open.png ... images/find.png images/gotocell.png

to the application's .pro file, we tell uic to generate a C++ source code file that contains the data for all the specified images. The data is then compiled into the application's executable and can be retrieved using QPixmap::fromMime-Source(). This has the advantage that icons and other images cannot get lost; they are always in the executable.

If you use Qt Designer to create your main windows as well as your dialogs, you can also use it to handle your .pro file and to visually add images to the image collection.

Категории