0
|
1 |
/****************************************************************************
|
|
2 |
**
|
|
3 |
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
4 |
** All rights reserved.
|
|
5 |
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
6 |
**
|
|
7 |
** This file is part of the documentation of the Qt Toolkit.
|
|
8 |
**
|
|
9 |
** $QT_BEGIN_LICENSE:LGPL$
|
|
10 |
** No Commercial Usage
|
|
11 |
** This file contains pre-release code and may not be distributed.
|
|
12 |
** You may use this file in accordance with the terms and conditions
|
|
13 |
** contained in the Technology Preview License Agreement accompanying
|
|
14 |
** this package.
|
|
15 |
**
|
|
16 |
** GNU Lesser General Public License Usage
|
|
17 |
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
18 |
** General Public License version 2.1 as published by the Free Software
|
|
19 |
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
20 |
** packaging of this file. Please review the following information to
|
|
21 |
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
22 |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
23 |
**
|
|
24 |
** In addition, as a special exception, Nokia gives you certain additional
|
|
25 |
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
26 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
27 |
**
|
|
28 |
** If you have questions regarding the use of this file, please contact
|
|
29 |
** Nokia at qt-info@nokia.com.
|
|
30 |
**
|
|
31 |
**
|
|
32 |
**
|
|
33 |
**
|
|
34 |
**
|
|
35 |
**
|
|
36 |
**
|
|
37 |
**
|
|
38 |
** $QT_END_LICENSE$
|
|
39 |
**
|
|
40 |
****************************************************************************/
|
|
41 |
|
|
42 |
/*!
|
|
43 |
\example mainwindows/application
|
|
44 |
\title Application Example
|
|
45 |
|
|
46 |
The Application example shows how to implement a standard GUI
|
|
47 |
application with menus, toolbars, and a status bar. The example
|
|
48 |
itself is a simple text editor program built around QPlainTextEdit.
|
|
49 |
|
|
50 |
\image application.png Screenshot of the Application example
|
|
51 |
|
|
52 |
Nearly all of the code for the Application example is in the \c
|
|
53 |
MainWindow class, which inherits QMainWindow. QMainWindow
|
|
54 |
provides the framework for windows that have menus, toolbars,
|
|
55 |
dock windows, and a status bar. The application provides
|
|
56 |
\menu{File}, \menu{Edit}, and \menu{Help} entries in the menu
|
|
57 |
bar, with the following popup menus:
|
|
58 |
|
|
59 |
\image application-menus.png The Application example's menu system
|
|
60 |
|
|
61 |
The status bar at the bottom of the main window shows a
|
|
62 |
description of the menu item or toolbar button under the cursor.
|
|
63 |
|
|
64 |
To keep the example simple, recently opened files aren't shown in
|
|
65 |
the \menu{File} menu, even though this feature is desired in 90%
|
|
66 |
of applications. The \l{mainwindows/recentfiles}{Recent Files}
|
|
67 |
example shows how to implement this. Furthermore, this example
|
|
68 |
can only load one file at a time. The \l{mainwindows/sdi}{SDI}
|
|
69 |
and \l{mainwindows/mdi}{MDI} examples shows how to lift these
|
|
70 |
restrictions.
|
|
71 |
|
|
72 |
\section1 MainWindow Class Definition
|
|
73 |
|
|
74 |
Here's the class definition:
|
|
75 |
|
|
76 |
\snippet examples/mainwindows/application/mainwindow.h 0
|
|
77 |
|
|
78 |
The public API is restricted to the constructor. In the \c
|
|
79 |
protected section, we reimplement QWidget::closeEvent() to detect
|
|
80 |
when the user attempts to close the window, and warn the user
|
|
81 |
about unsaved changes. In the \c{private slots} section, we
|
|
82 |
declare slots that correspond to menu entries, as well as a
|
|
83 |
mysterious \c documentWasModified() slot. Finally, in the \c
|
|
84 |
private section of the class, we have various members that will
|
|
85 |
be explained in due time.
|
|
86 |
|
|
87 |
\section1 MainWindow Class Implementation
|
|
88 |
|
|
89 |
\snippet examples/mainwindows/application/mainwindow.cpp 0
|
|
90 |
|
|
91 |
We start by including \c <QtGui>, a header file that contains the
|
|
92 |
definition of all classes in the \l QtCore and \l QtGui
|
|
93 |
libraries. This saves us from the trouble of having to include
|
|
94 |
every class individually. We also include \c mainwindow.h.
|
|
95 |
|
|
96 |
You might wonder why we don't include \c <QtGui> in \c
|
|
97 |
mainwindow.h and be done with it. The reason is that including
|
|
98 |
such a large header from another header file can rapidly degrade
|
|
99 |
performances. Here, it wouldn't do any harm, but it's still
|
|
100 |
generally a good idea to include only the header files that are
|
|
101 |
strictly necessary from another header file.
|
|
102 |
|
|
103 |
\snippet examples/mainwindows/application/mainwindow.cpp 1
|
|
104 |
\snippet examples/mainwindows/application/mainwindow.cpp 2
|
|
105 |
|
|
106 |
In the constructor, we start by creating a QPlainTextEdit widget as a
|
|
107 |
child of the main window (the \c this object). Then we call
|
|
108 |
QMainWindow::setCentralWidget() to tell that this is going to be
|
|
109 |
the widget that occupies the central area of the main window,
|
|
110 |
between the toolbars and the status bar.
|
|
111 |
|
|
112 |
Then we call \c createActions(), \c createMenus(), \c
|
|
113 |
createToolBars(), and \c createStatusBar(), four private
|
|
114 |
functions that set up the user interface. After that, we call \c
|
|
115 |
readSettings() to restore the user's preferences.
|
|
116 |
|
|
117 |
We establish a signal-slot connection between the QPlainTextEdit's
|
|
118 |
document object and our \c documentWasModified() slot. Whenever
|
|
119 |
the user modifies the text in the QPlainTextEdit, we want to update
|
|
120 |
the title bar to show that the file was modified.
|
|
121 |
|
|
122 |
At the end, we set the window title using the private
|
|
123 |
\c setCurrentFile() function. We'll come back to this later.
|
|
124 |
|
|
125 |
\target close event handler
|
|
126 |
\snippet examples/mainwindows/application/mainwindow.cpp 3
|
|
127 |
\snippet examples/mainwindows/application/mainwindow.cpp 4
|
|
128 |
|
|
129 |
When the user attempts to close the window, we call the private
|
|
130 |
function \c maybeSave() to give the user the possibility to save
|
|
131 |
pending changes. The function returns true if the user wants the
|
|
132 |
application to close; otherwise, it returns false. In the first
|
|
133 |
case, we save the user's preferences to disk and accept the close
|
|
134 |
event; in the second case, we ignore the close event, meaning
|
|
135 |
that the application will stay up and running as if nothing
|
|
136 |
happened.
|
|
137 |
|
|
138 |
\snippet examples/mainwindows/application/mainwindow.cpp 5
|
|
139 |
\snippet examples/mainwindows/application/mainwindow.cpp 6
|
|
140 |
|
|
141 |
The \c newFile() slot is invoked when the user selects
|
|
142 |
\menu{File|New} from the menu. We call \c maybeSave() to save any
|
|
143 |
pending changes and if the user accepts to go on, we clear the
|
|
144 |
QPlainTextEdit and call the private function \c setCurrentFile() to
|
|
145 |
update the window title and clear the
|
|
146 |
\l{QWidget::windowModified}{windowModified} flag.
|
|
147 |
|
|
148 |
\snippet examples/mainwindows/application/mainwindow.cpp 7
|
|
149 |
\snippet examples/mainwindows/application/mainwindow.cpp 8
|
|
150 |
|
|
151 |
The \c open() slot is invoked when the user clicks
|
|
152 |
\menu{File|Open}. We pop up a QFileDialog asking the user to
|
|
153 |
choose a file. If the user chooses a file (i.e., \c fileName is
|
|
154 |
not an empty string), we call the private function \c loadFile()
|
|
155 |
to actually load the file.
|
|
156 |
|
|
157 |
\snippet examples/mainwindows/application/mainwindow.cpp 9
|
|
158 |
\snippet examples/mainwindows/application/mainwindow.cpp 10
|
|
159 |
|
|
160 |
The \c save() slot is invoked when the user clicks
|
|
161 |
\menu{File|Save}. If the user hasn't provided a name for the file
|
|
162 |
yet, we call \c saveAs(); otherwise, we call the private function
|
|
163 |
\c saveFile() to actually save the file.
|
|
164 |
|
|
165 |
\snippet examples/mainwindows/application/mainwindow.cpp 11
|
|
166 |
\snippet examples/mainwindows/application/mainwindow.cpp 12
|
|
167 |
|
|
168 |
In \c saveAs(), we start by popping up a QFileDialog asking the
|
|
169 |
user to provide a name. If the user clicks \gui{Cancel}, the
|
|
170 |
returned file name is empty, and we do nothing.
|
|
171 |
|
|
172 |
\snippet examples/mainwindows/application/mainwindow.cpp 13
|
|
173 |
\snippet examples/mainwindows/application/mainwindow.cpp 14
|
|
174 |
|
|
175 |
The application's About box is done using one statement, using
|
|
176 |
the QMessageBox::about() static function and relying on its
|
|
177 |
support for an HTML subset.
|
|
178 |
|
|
179 |
The \l{QObject::tr()}{tr()} call around the literal string marks
|
|
180 |
the string for translation. It is a good habit to call
|
|
181 |
\l{QObject::tr()}{tr()} on all user-visible strings, in case you
|
|
182 |
later decide to translate your application to other languages.
|
|
183 |
The \l{Internationalization with Qt} overview convers
|
|
184 |
\l{QObject::tr()}{tr()} in more detail.
|
|
185 |
|
|
186 |
\snippet examples/mainwindows/application/mainwindow.cpp 15
|
|
187 |
\snippet examples/mainwindows/application/mainwindow.cpp 16
|
|
188 |
|
|
189 |
The \c documentWasModified() slot is invoked each time the text
|
|
190 |
in the QPlainTextEdit changes because of user edits. We call
|
|
191 |
QWidget::setWindowModified() to make the title bar show that the
|
|
192 |
file was modified. How this is done varies on each platform.
|
|
193 |
|
|
194 |
\snippet examples/mainwindows/application/mainwindow.cpp 17
|
|
195 |
\snippet examples/mainwindows/application/mainwindow.cpp 18
|
|
196 |
\dots
|
|
197 |
\snippet examples/mainwindows/application/mainwindow.cpp 22
|
|
198 |
|
|
199 |
The \c createActions() private function, which is called from the
|
|
200 |
\c MainWindow constructor, creates \l{QAction}s. The code is very
|
|
201 |
repetitive, so we show only the actions corresponding to
|
|
202 |
\menu{File|New}, \menu{File|Open}, and \menu{Help|About Qt}.
|
|
203 |
|
|
204 |
A QAction is an object that represents one user action, such as
|
|
205 |
saving a file or invoking a dialog. An action can be put in a
|
|
206 |
QMenu or a QToolBar, or both, or in any other widget that
|
|
207 |
reimplements QWidget::actionEvent().
|
|
208 |
|
|
209 |
An action has a text that is shown in the menu, an icon, a
|
|
210 |
shortcut key, a tooltip, a status tip (shown in the status bar),
|
|
211 |
a "What's This?" text, and more. It emits a
|
|
212 |
\l{QAction::triggered()}{triggered()} signal whenever the user
|
|
213 |
invokes the action (e.g., by clicking the associated menu item or
|
|
214 |
toolbar button). We connect this signal to a slot that performs
|
|
215 |
the actual action.
|
|
216 |
|
|
217 |
The code above contains one more idiom that must be explained.
|
|
218 |
For some of the actions, we specify an icon as a QIcon to the
|
|
219 |
QAction constructor. The QIcon constructor takes the file name
|
|
220 |
of an image that it tries to load. Here, the file name starts
|
|
221 |
with \c{:}. Such file names aren't ordinary file names, but
|
|
222 |
rather path in the executable's stored resources. We'll come back
|
|
223 |
to this when we review the \c application.qrc file that's part of
|
|
224 |
the project.
|
|
225 |
|
|
226 |
\snippet examples/mainwindows/application/mainwindow.cpp 23
|
|
227 |
\snippet examples/mainwindows/application/mainwindow.cpp 24
|
|
228 |
|
|
229 |
The \gui{Edit|Cut} and \gui{Edit|Copy} actions must be available
|
|
230 |
only when the QPlainTextEdit contains selected text. We disable them
|
|
231 |
by default and connect the QPlainTextEdit::copyAvailable() signal to
|
|
232 |
the QAction::setEnabled() slot, ensuring that the actions are
|
|
233 |
disabled when the text editor has no selection.
|
|
234 |
|
|
235 |
\snippet examples/mainwindows/application/mainwindow.cpp 25
|
|
236 |
\snippet examples/mainwindows/application/mainwindow.cpp 27
|
|
237 |
|
|
238 |
Creating actions isn't sufficient to make them available to the
|
|
239 |
user; we must also add them to the menu system. This is what \c
|
|
240 |
createMenus() does. We create a \menu{File}, an \menu{Edit}, and
|
|
241 |
a \menu{Help} menu. QMainWindow::menuBar() lets us access the
|
|
242 |
window's menu bar widget. We don't have to worry about creating
|
|
243 |
the menu bar ourselves; the first time we call this function, the
|
|
244 |
QMenuBar is created.
|
|
245 |
|
|
246 |
Just before we create the \menu{Help} menu, we call
|
|
247 |
QMenuBar::addSeparator(). This has no effect for most widget
|
|
248 |
styles (e.g., Windows and Mac OS X styles), but for Motif-based
|
|
249 |
styles this makes sure that \menu{Help} is pushed to the right
|
|
250 |
side of the menu bar. Try running the application with various
|
|
251 |
styles and see the results:
|
|
252 |
|
|
253 |
\snippet doc/src/snippets/code/doc_src_examples_application.qdoc 0
|
|
254 |
|
|
255 |
Let's now review the toolbars:
|
|
256 |
|
|
257 |
\snippet examples/mainwindows/application/mainwindow.cpp 30
|
|
258 |
|
|
259 |
Creating toolbars is very similar to creating menus. The same
|
|
260 |
actions that we put in the menus can be reused in the toolbars.
|
|
261 |
|
|
262 |
\snippet examples/mainwindows/application/mainwindow.cpp 32
|
|
263 |
\snippet examples/mainwindows/application/mainwindow.cpp 33
|
|
264 |
|
|
265 |
QMainWindow::statusBar() returns a pointer to the main window's
|
|
266 |
QStatusBar widget. Like with \l{QMainWindow::menuBar()}, the
|
|
267 |
widget is automatically created the first time the function is
|
|
268 |
called.
|
|
269 |
|
|
270 |
\snippet examples/mainwindows/application/mainwindow.cpp 34
|
|
271 |
\snippet examples/mainwindows/application/mainwindow.cpp 36
|
|
272 |
|
|
273 |
The \c readSettings() function is called from the constructor to
|
|
274 |
load the user's preferences and other application settings. The
|
|
275 |
QSettings class provides a high-level interface for storing
|
|
276 |
settings permanently on disk. On Windows, it uses the (in)famous
|
|
277 |
Windows registry; on Mac OS X, it uses the native XML-based
|
|
278 |
CFPreferences API; on Unix/X11, it uses text files.
|
|
279 |
|
|
280 |
The QSettings constructor takes arguments that identify your
|
|
281 |
company and the name of the product. This ensures that the
|
|
282 |
settings for different applications are kept separately.
|
|
283 |
|
|
284 |
We use QSettings::value() to extract the value of the "pos" and
|
|
285 |
"size" settings. The second argument to QSettings::value() is
|
|
286 |
optional and specifies a default value for the setting if there
|
|
287 |
exists none. This value is used the first time the application is
|
|
288 |
run.
|
|
289 |
|
|
290 |
When restoring the position and size of a window, it's important
|
|
291 |
to call QWidget::resize() before QWidget::move(). The reason why
|
|
292 |
is given in the \l{Window Geometry} overview.
|
|
293 |
|
|
294 |
\snippet examples/mainwindows/application/mainwindow.cpp 37
|
|
295 |
\snippet examples/mainwindows/application/mainwindow.cpp 39
|
|
296 |
|
|
297 |
The \c writeSettings() function is called from \c closeEvent().
|
|
298 |
Writing settings is similar to reading them, except simpler. The
|
|
299 |
arguments to the QSettings constructor must be the same as in \c
|
|
300 |
readSettings().
|
|
301 |
|
|
302 |
\snippet examples/mainwindows/application/mainwindow.cpp 40
|
|
303 |
\snippet examples/mainwindows/application/mainwindow.cpp 41
|
|
304 |
|
|
305 |
The \c maybeSave() function is called to save pending changes. If
|
|
306 |
there are pending changes, it pops up a QMessageBox giving the
|
|
307 |
user to save the document. The options are QMessageBox::Yes,
|
|
308 |
QMessageBox::No, and QMessageBox::Cancel. The \gui{Yes} button is
|
|
309 |
made the default button (the button that is invoked when the user
|
|
310 |
presses \key{Return}) using the QMessageBox::Default flag; the
|
|
311 |
\gui{Cancel} button is made the escape button (the button that is
|
|
312 |
invoked when the user presses \key{Esc}) using the
|
|
313 |
QMessageBox::Escape flag.
|
|
314 |
|
|
315 |
The \c maybeSave() function returns \c true in all cases, except
|
|
316 |
when the user clicks \gui{Cancel}. The caller must check the
|
|
317 |
return value and stop whatever it was doing if the return value
|
|
318 |
is \c false.
|
|
319 |
|
|
320 |
\snippet examples/mainwindows/application/mainwindow.cpp 42
|
|
321 |
\snippet examples/mainwindows/application/mainwindow.cpp 43
|
|
322 |
|
|
323 |
In \c loadFile(), we use QFile and QTextStream to read in the
|
|
324 |
data. The QFile object provides access to the bytes stored in a
|
|
325 |
file.
|
|
326 |
|
|
327 |
We start by opening the file in read-only mode. The QFile::Text
|
|
328 |
flag indicates that the file is a text file, not a binary file.
|
|
329 |
On Unix and Mac OS X, this makes no difference, but on Windows,
|
|
330 |
it ensures that the "\\r\\n" end-of-line sequence is converted to
|
|
331 |
"\\n" when reading.
|
|
332 |
|
|
333 |
If we successfully opened the file, we use a QTextStream object
|
|
334 |
to read in the data. QTextStream automatically converts the 8-bit
|
|
335 |
data into a Unicode QString and supports various encodings. If no
|
|
336 |
encoding is specified, QTextStream assumes the file is written
|
|
337 |
using the system's default 8-bit encoding (for example, Latin-1;
|
|
338 |
see QTextCodec::codecForLocale() for details).
|
|
339 |
|
|
340 |
Since the call to QTextStream::readAll() might take some time, we
|
|
341 |
set the cursor to be Qt::WaitCursor for the entire application
|
|
342 |
while it goes on.
|
|
343 |
|
|
344 |
At the end, we call the private \c setCurrentFile() function,
|
|
345 |
which we'll cover in a moment, and we display the string "File
|
|
346 |
loaded" in the status bar for 2 seconds (2000 milliseconds).
|
|
347 |
|
|
348 |
\snippet examples/mainwindows/application/mainwindow.cpp 44
|
|
349 |
\snippet examples/mainwindows/application/mainwindow.cpp 45
|
|
350 |
|
|
351 |
Saving a file is very similar to loading one. Here, the
|
|
352 |
QFile::Text flag ensures that on Windows, "\\n" is converted into
|
|
353 |
"\\r\\n" to conform to the Windows convension.
|
|
354 |
|
|
355 |
\snippet examples/mainwindows/application/mainwindow.cpp 46
|
|
356 |
\snippet examples/mainwindows/application/mainwindow.cpp 47
|
|
357 |
|
|
358 |
The \c setCurrentFile() function is called to reset the state of
|
|
359 |
a few variables when a file is loaded or saved, or when the user
|
|
360 |
starts editing a new file (in which case \c fileName is empty).
|
|
361 |
We update the \c curFile variable, clear the
|
|
362 |
QTextDocument::modified flag and the associated \c
|
|
363 |
QWidget:windowModified flag, and update the window title to
|
|
364 |
contain the new file name (or \c untitled.txt).
|
|
365 |
|
|
366 |
The \c strippedName() function call around \c curFile in the
|
|
367 |
QWidget::setWindowTitle() call shortens the file name to exclude
|
|
368 |
the path. Here's the function:
|
|
369 |
|
|
370 |
\snippet examples/mainwindows/application/mainwindow.cpp 48
|
|
371 |
\snippet examples/mainwindows/application/mainwindow.cpp 49
|
|
372 |
|
|
373 |
\section1 The main() Function
|
|
374 |
|
|
375 |
The \c main() function for this application is typical of
|
|
376 |
applications that contain one main window:
|
|
377 |
|
|
378 |
\snippet examples/mainwindows/application/main.cpp 0
|
|
379 |
|
|
380 |
\section1 The Resource File
|
|
381 |
|
|
382 |
As you will probably recall, for some of the actions, we
|
|
383 |
specified icons with file names starting with \c{:} and mentioned
|
|
384 |
that such file names aren't ordinary file names, but path in the
|
|
385 |
executable's stored resources. These resources are compiled
|
|
386 |
|
|
387 |
The resources associated with an application are specified in a
|
|
388 |
\c .qrc file, an XML-based file format that lists files on the
|
|
389 |
disk. Here's the \c application.qrc file that's used by the
|
|
390 |
Application example:
|
|
391 |
|
|
392 |
\quotefile mainwindows/application/application.qrc
|
|
393 |
|
|
394 |
The \c .png files listed in the \c application.qrc file are files
|
|
395 |
that are part of the Application example's source tree. Paths are
|
|
396 |
relative to the directory where the \c application.qrc file is
|
|
397 |
located (the \c mainwindows/application directory).
|
|
398 |
|
|
399 |
The resource file must be mentioned in the \c application.pro
|
|
400 |
file so that \c qmake knows about it:
|
|
401 |
|
|
402 |
\snippet examples/mainwindows/application/application.pro 0
|
|
403 |
|
|
404 |
\c qmake will produce make rules to generate a file called \c
|
|
405 |
qrc_application.cpp that is linked into the application. This
|
|
406 |
file contains all the data for the images and other resources as
|
|
407 |
static C++ arrays of compressed binary data. See
|
|
408 |
\l{resources.html}{The Qt Resource System} for more information
|
|
409 |
about resources.
|
|
410 |
*/
|