| 1 | /****************************************************************************
|
|---|
| 2 | **
|
|---|
| 3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|---|
| 4 | ** Contact: Qt Software Information (qt-info@nokia.com)
|
|---|
| 5 | **
|
|---|
| 6 | ** This file is part of the documentation of the Qt Toolkit.
|
|---|
| 7 | **
|
|---|
| 8 | ** $QT_BEGIN_LICENSE:LGPL$
|
|---|
| 9 | ** Commercial Usage
|
|---|
| 10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
|---|
| 11 | ** accordance with the Qt Commercial License Agreement provided with the
|
|---|
| 12 | ** Software or, alternatively, in accordance with the terms contained in
|
|---|
| 13 | ** a written agreement between you and Nokia.
|
|---|
| 14 | **
|
|---|
| 15 | ** GNU Lesser General Public License Usage
|
|---|
| 16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
|---|
| 17 | ** General Public License version 2.1 as published by the Free Software
|
|---|
| 18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
|---|
| 19 | ** packaging of this file. Please review the following information to
|
|---|
| 20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
|---|
| 21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|---|
| 22 | **
|
|---|
| 23 | ** In addition, as a special exception, Nokia gives you certain
|
|---|
| 24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
|---|
| 25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
|---|
| 26 | ** package.
|
|---|
| 27 | **
|
|---|
| 28 | ** GNU General Public License Usage
|
|---|
| 29 | ** Alternatively, this file may be used under the terms of the GNU
|
|---|
| 30 | ** General Public License version 3.0 as published by the Free Software
|
|---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
|---|
| 32 | ** packaging of this file. Please review the following information to
|
|---|
| 33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
|---|
| 34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
|---|
| 35 | **
|
|---|
| 36 | ** If you are unsure which license is appropriate for your use, please
|
|---|
| 37 | ** contact the sales department at qt-sales@nokia.com.
|
|---|
| 38 | ** $QT_END_LICENSE$
|
|---|
| 39 | **
|
|---|
| 40 | ****************************************************************************/
|
|---|
| 41 |
|
|---|
| 42 | /*!
|
|---|
| 43 | \example widgets/scribble
|
|---|
| 44 | \title Scribble Example
|
|---|
| 45 |
|
|---|
| 46 | The Scribble example shows how to reimplement some of QWidget's
|
|---|
| 47 | event handlers to receive the events generated for the
|
|---|
| 48 | application's widgets.
|
|---|
| 49 |
|
|---|
| 50 | We reimplement the mouse event handlers to implement drawing, the
|
|---|
| 51 | paint event handler to update the application and the resize event
|
|---|
| 52 | handler to optimize the application's appearance. In addition we
|
|---|
| 53 | reimplement the close event handler to intercept the close events
|
|---|
| 54 | before terminating the application.
|
|---|
| 55 |
|
|---|
| 56 | The example also demonstrates how to use QPainter to draw an image
|
|---|
| 57 | in real time, as well as to repaint widgets.
|
|---|
| 58 |
|
|---|
| 59 | \image scribble-example.png Screenshot of the Scribble example
|
|---|
| 60 |
|
|---|
| 61 | With the Scribble application the users can draw an image. The
|
|---|
| 62 | \gui File menu gives the users the possibility to open and edit an
|
|---|
| 63 | existing image file, save an image and exit the application. While
|
|---|
| 64 | drawing, the \gui Options menu allows the users to to choose the
|
|---|
| 65 | pen color and pen width, as well as clear the screen. In addition
|
|---|
| 66 | the \gui Help menu provides the users with information about the
|
|---|
| 67 | Scribble example in particular, and about Qt in general.
|
|---|
| 68 |
|
|---|
| 69 | The example consists of two classes:
|
|---|
| 70 |
|
|---|
| 71 | \list
|
|---|
| 72 | \o \c ScribbleArea is a custom widget that displays a QImage and
|
|---|
| 73 | allows to the user to draw on it.
|
|---|
| 74 | \o \c MainWindow provides a menu above the \c ScribbleArea.
|
|---|
| 75 | \endlist
|
|---|
| 76 |
|
|---|
| 77 | We will start by reviewing the \c ScribbleArea class, which
|
|---|
| 78 | contains the interesting, then we will take a look at the \c
|
|---|
| 79 | MainWindow class that uses it.
|
|---|
| 80 |
|
|---|
| 81 | \section1 ScribbleArea Class Definition
|
|---|
| 82 |
|
|---|
| 83 | \snippet examples/widgets/scribble/scribblearea.h 0
|
|---|
| 84 |
|
|---|
| 85 | The \c ScribbleArea class inherits from QWidget. We reimplement
|
|---|
| 86 | the \c mousePressEvent(), \c mouseMoveEvent() and \c
|
|---|
| 87 | mouseReleaseEvent() functions to implement the drawing. We
|
|---|
| 88 | reimplement the \c paintEvent() function to update the scribble
|
|---|
| 89 | area, and the \c resizeEvent() function to ensure that the QImage
|
|---|
| 90 | on which we draw is at least as large as the widget at any time.
|
|---|
| 91 |
|
|---|
| 92 | We need several public functions: \c openImage() loads an image
|
|---|
| 93 | from a file into the scribble area, allowing the user to edit the
|
|---|
| 94 | image; \c save() writes the currently displayed image to file; \c
|
|---|
| 95 | clearImage() slot clears the image displayed in the scribble
|
|---|
| 96 | area. We need the private \c drawLineTo() function to actually do
|
|---|
| 97 | the drawing, and \c resizeImage() to change the size of a
|
|---|
| 98 | QImage. The \c print() slot handles printing.
|
|---|
| 99 |
|
|---|
| 100 | We also need the following private variables:
|
|---|
| 101 |
|
|---|
| 102 | \list
|
|---|
| 103 | \o \c modified is \c true if there are unsaved
|
|---|
| 104 | changes to the image displayed in the scribble area.
|
|---|
| 105 | \o \c scribbling is \c true while the user is pressing
|
|---|
| 106 | the left mouse button within the scribble area.
|
|---|
| 107 | \o \c penWidth and \c penColor hold the currently
|
|---|
| 108 | set width and color for the pen used in the application.
|
|---|
| 109 | \o \c image stores the image drawn by the user.
|
|---|
| 110 | \o \c lastPoint holds the position of the cursor at the last
|
|---|
| 111 | mouse press or mouse move event.
|
|---|
| 112 | \endlist
|
|---|
| 113 |
|
|---|
| 114 | \section1 ScribbleArea Class Implementation
|
|---|
| 115 |
|
|---|
| 116 | \snippet examples/widgets/scribble/scribblearea.cpp 0
|
|---|
| 117 |
|
|---|
| 118 | In the constructor, we set the Qt::WA_StaticContents
|
|---|
| 119 | attribute for the widget, indicating that the widget contents are
|
|---|
| 120 | rooted to the top-left corner and don't change when the widget is
|
|---|
| 121 | resized. Qt uses this attribute to optimize paint events on
|
|---|
| 122 | resizes. This is purely an optimization and should only be used
|
|---|
| 123 | for widgets whose contents are static and rooted to the top-left
|
|---|
| 124 | corner.
|
|---|
| 125 |
|
|---|
| 126 | \snippet examples/widgets/scribble/scribblearea.cpp 1
|
|---|
| 127 | \snippet examples/widgets/scribble/scribblearea.cpp 2
|
|---|
| 128 |
|
|---|
| 129 | In the \c openImage() function, we load the given image. Then we
|
|---|
| 130 | resize the loaded QImage to be at least as large as the widget in
|
|---|
| 131 | both directions using the private \c resizeImage() function and
|
|---|
| 132 | we set the \c image member variable to be the loaded image. At
|
|---|
| 133 | the end, we call QWidget::update() to schedule a repaint.
|
|---|
| 134 |
|
|---|
| 135 | \snippet examples/widgets/scribble/scribblearea.cpp 3
|
|---|
| 136 | \snippet examples/widgets/scribble/scribblearea.cpp 4
|
|---|
| 137 |
|
|---|
| 138 | The \c saveImage() function creates a QImage object that covers
|
|---|
| 139 | only the visible section of the actual \c image and saves it using
|
|---|
| 140 | QImage::save(). If the image is successfully saved, we set the
|
|---|
| 141 | scribble area's \c modified variable to \c false, because there is
|
|---|
| 142 | no unsaved data.
|
|---|
| 143 |
|
|---|
| 144 | \snippet examples/widgets/scribble/scribblearea.cpp 5
|
|---|
| 145 | \snippet examples/widgets/scribble/scribblearea.cpp 6
|
|---|
| 146 | \codeline
|
|---|
| 147 | \snippet examples/widgets/scribble/scribblearea.cpp 7
|
|---|
| 148 | \snippet examples/widgets/scribble/scribblearea.cpp 8
|
|---|
| 149 |
|
|---|
| 150 | The \c setPenColor() and \c setPenWidth() functions set the
|
|---|
| 151 | current pen color and width. These values will be used for future
|
|---|
| 152 | drawing operations.
|
|---|
| 153 |
|
|---|
| 154 | \snippet examples/widgets/scribble/scribblearea.cpp 9
|
|---|
| 155 | \snippet examples/widgets/scribble/scribblearea.cpp 10
|
|---|
| 156 |
|
|---|
| 157 | The public \c clearImage() slot clears the image displayed in the
|
|---|
| 158 | scribble area. We simply fill the entire image with white, which
|
|---|
| 159 | corresponds to RGB value (255, 255, 255). As usual when we modify
|
|---|
| 160 | the image, we set \c modified to \c true and schedule a repaint.
|
|---|
| 161 |
|
|---|
| 162 | \snippet examples/widgets/scribble/scribblearea.cpp 11
|
|---|
| 163 | \snippet examples/widgets/scribble/scribblearea.cpp 12
|
|---|
| 164 |
|
|---|
| 165 | For mouse press and mouse release events, we use the
|
|---|
| 166 | QMouseEvent::button() function to find out which button caused
|
|---|
| 167 | the event. For mose move events, we use QMouseEvent::buttons()
|
|---|
| 168 | to find which buttons are currently held down (as an OR-combination).
|
|---|
| 169 |
|
|---|
| 170 | If the users press the left mouse button, we store the position
|
|---|
| 171 | of the mouse cursor in \c lastPoint. We also make a note that the
|
|---|
| 172 | user is currently scribbling. (The \c scribbling variable is
|
|---|
| 173 | necessary because we can't assume that a mouse move and mouse
|
|---|
| 174 | release event is always preceded by a mouse press event on the
|
|---|
| 175 | same widget.)
|
|---|
| 176 |
|
|---|
| 177 | If the user moves the mouse with the left button pressed down or
|
|---|
| 178 | releases the button, we call the private \c drawLineTo() function
|
|---|
| 179 | to draw.
|
|---|
| 180 |
|
|---|
| 181 | \snippet examples/widgets/scribble/scribblearea.cpp 13
|
|---|
| 182 | \snippet examples/widgets/scribble/scribblearea.cpp 14
|
|---|
| 183 |
|
|---|
| 184 | In the reimplementation of the \l
|
|---|
| 185 | {QWidget::paintEvent()}{paintEvent()} function, we simply create
|
|---|
| 186 | a QPainter for the scribble area, and draw the image.
|
|---|
| 187 |
|
|---|
| 188 | At this point, you might wonder why we don't just draw directly
|
|---|
| 189 | onto the widget instead of drawing in a QImage and copying the
|
|---|
| 190 | QImage onto screen in \c paintEvent(). There are at least three
|
|---|
| 191 | good reasons for this:
|
|---|
| 192 |
|
|---|
| 193 | \list
|
|---|
| 194 | \o The window system requires us to be able to redraw the widget
|
|---|
| 195 | \e{at any time}. For example, if the window is minimized and
|
|---|
| 196 | restored, the window system might have forgotten the contents
|
|---|
| 197 | of the widget and send us a paint event. In other words, we
|
|---|
| 198 | can't rely on the window system to remember our image.
|
|---|
| 199 |
|
|---|
| 200 | \o Qt normally doesn't allow us to paint outside of \c
|
|---|
| 201 | paintEvent(). In particular, we can't paint from the mouse
|
|---|
| 202 | event handlers. (This behavior can be changed using the
|
|---|
| 203 | Qt::WA_PaintOnScreen widget attribute, though.)
|
|---|
| 204 |
|
|---|
| 205 | \o If initialized properly, a QImage is guaranteed to use 8-bit
|
|---|
| 206 | for each color channel (red, green, blue, and alpha), whereas
|
|---|
| 207 | a QWidget might have a lower color depth, depending on the
|
|---|
| 208 | monitor configuration. This means that if we load a 24-bit or
|
|---|
| 209 | 32-bit image and paint it onto a QWidget, then copy the
|
|---|
| 210 | QWidget into a QImage again, we might lose some information.
|
|---|
| 211 | \endlist
|
|---|
| 212 |
|
|---|
| 213 | \snippet examples/widgets/scribble/scribblearea.cpp 15
|
|---|
| 214 | \snippet examples/widgets/scribble/scribblearea.cpp 16
|
|---|
| 215 |
|
|---|
| 216 | When the user starts the Scribble application, a resize event is
|
|---|
| 217 | generated and an image is created and displayed in the scribble
|
|---|
| 218 | area. We make this initial image slightly larger than the
|
|---|
| 219 | application's main window and scribble area, to avoid always
|
|---|
| 220 | resizing the image when the user resizes the main window (which
|
|---|
| 221 | would be very inefficient). But when the main window becomes
|
|---|
| 222 | larger than this initial size, the image needs to be resized.
|
|---|
| 223 |
|
|---|
| 224 | \snippet examples/widgets/scribble/scribblearea.cpp 17
|
|---|
| 225 | \snippet examples/widgets/scribble/scribblearea.cpp 18
|
|---|
| 226 |
|
|---|
| 227 | In \c drawLineTo(), we draw a line from the point where the mouse
|
|---|
| 228 | was located when the last mouse press or mouse move occurred, we
|
|---|
| 229 | set \c modified to true, we generate a repaint event, and we
|
|---|
| 230 | update \c lastPoint so that next time \c drawLineTo() is called,
|
|---|
| 231 | we continue drawing from where we left.
|
|---|
| 232 |
|
|---|
| 233 | We could call the \c update() function with no parameter, but as
|
|---|
| 234 | an easy optimization we pass a QRect that specifies the rectangle
|
|---|
| 235 | inside the scribble are needs updating, to avoid a complete
|
|---|
| 236 | repaint of the widget.
|
|---|
| 237 |
|
|---|
| 238 | \snippet examples/widgets/scribble/scribblearea.cpp 19
|
|---|
| 239 | \snippet examples/widgets/scribble/scribblearea.cpp 20
|
|---|
| 240 |
|
|---|
| 241 | QImage has no nice API for resizing an image. There's a
|
|---|
| 242 | QImage::copy() function that could do the trick, but when used to
|
|---|
| 243 | expand an image, it fills the new areas with black, whereas we
|
|---|
| 244 | want white.
|
|---|
| 245 |
|
|---|
| 246 | So the trick is to create a brand new QImage with the right size,
|
|---|
| 247 | to fill it with white, and to draw the old image onto it using
|
|---|
| 248 | QPainter. The new image is given the QImage::Format_RGB32
|
|---|
| 249 | format, which means that each pixel is stored as 0xffRRGGBB
|
|---|
| 250 | (where RR, GG, and BB are the red, green and blue
|
|---|
| 251 | color channels, ff is the hexadecimal value 255).
|
|---|
| 252 |
|
|---|
| 253 | Printing is handled by the \c print() slot:
|
|---|
| 254 |
|
|---|
| 255 | \snippet examples/widgets/scribble/scribblearea.cpp 21
|
|---|
| 256 |
|
|---|
| 257 | We construct a high resolution QPrinter object for the required
|
|---|
| 258 | output format, using a QPrintDialog to ask the user to specify a
|
|---|
| 259 | page size and indicate how the output should be formatted on the page.
|
|---|
| 260 |
|
|---|
| 261 | If the dialog is accepted, we perform the task of printing to the paint
|
|---|
| 262 | device:
|
|---|
| 263 |
|
|---|
| 264 | \snippet examples/widgets/scribble/scribblearea.cpp 22
|
|---|
| 265 |
|
|---|
| 266 | Printing an image to a file in this way is simply a matter of
|
|---|
| 267 | painting onto the QPrinter. We scale the image to fit within the
|
|---|
| 268 | available space on the page before painting it onto the paint
|
|---|
| 269 | device.
|
|---|
| 270 |
|
|---|
| 271 | \section1 MainWindow Class Definition
|
|---|
| 272 |
|
|---|
| 273 | \snippet examples/widgets/scribble/mainwindow.h 0
|
|---|
| 274 |
|
|---|
| 275 | The \c MainWindow class inherits from QMainWindow. We reimplement
|
|---|
| 276 | the \l{QWidget::closeEvent()}{closeEvent()} handler from QWidget.
|
|---|
| 277 | The \c open(), \c save(), \c penColor() and \c penWidth()
|
|---|
| 278 | slots correspond to menu entries. In addition we create four
|
|---|
| 279 | private functions.
|
|---|
| 280 |
|
|---|
| 281 | We use the boolean \c maybeSave() function to check if there are
|
|---|
| 282 | any unsaved changes. If there are unsaved changes, we give the
|
|---|
| 283 | user the opportunity to save these changes. The function returns
|
|---|
| 284 | \c false if the user clicks \gui Cancel. We use the \c saveFile()
|
|---|
| 285 | function to let the user save the image currently displayed in
|
|---|
| 286 | the scribble area.
|
|---|
| 287 |
|
|---|
| 288 | \section1 MainWindow Class Implementation
|
|---|
| 289 |
|
|---|
| 290 | \snippet examples/widgets/scribble/mainwindow.cpp 0
|
|---|
| 291 |
|
|---|
| 292 | In the constructor, we create a scribble area which we make the
|
|---|
| 293 | central widget of the \c MainWindow widget. Then we create the
|
|---|
| 294 | associated actions and menus.
|
|---|
| 295 |
|
|---|
| 296 | \snippet examples/widgets/scribble/mainwindow.cpp 1
|
|---|
| 297 | \snippet examples/widgets/scribble/mainwindow.cpp 2
|
|---|
| 298 |
|
|---|
| 299 | Close events are sent to widgets that the users want to close,
|
|---|
| 300 | usually by clicking \gui{File|Exit} or by clicking the \gui X
|
|---|
| 301 | title bar button. By reimplementing the event handler, we can
|
|---|
| 302 | intercept attempts to close the application.
|
|---|
| 303 |
|
|---|
| 304 | In this example, we use the close event to ask the user to save
|
|---|
| 305 | any unsaved changes. The logic for that is located in the \c
|
|---|
| 306 | maybeSave() function. If \c maybeSave() returns true, there are
|
|---|
| 307 | no modifications or the users successfully saved them, and we
|
|---|
| 308 | accept the event. The application can then terminate normally. If
|
|---|
| 309 | \c maybeSave() returns false, the user clicked \gui Cancel, so we
|
|---|
| 310 | "ignore" the event, leaving the application unaffected by it.
|
|---|
| 311 |
|
|---|
| 312 | \snippet examples/widgets/scribble/mainwindow.cpp 3
|
|---|
| 313 | \snippet examples/widgets/scribble/mainwindow.cpp 4
|
|---|
| 314 |
|
|---|
| 315 | In the \c open() slot we first give the user the opportunity to
|
|---|
| 316 | save any modifications to the currently displayed image, before a
|
|---|
| 317 | new image is loaded into the scribble area. Then we ask the user
|
|---|
| 318 | to choose a file and we load the file in the \c ScribbleArea.
|
|---|
| 319 |
|
|---|
| 320 | \snippet examples/widgets/scribble/mainwindow.cpp 5
|
|---|
| 321 | \snippet examples/widgets/scribble/mainwindow.cpp 6
|
|---|
| 322 |
|
|---|
| 323 | The \c save() slot is called when the users choose the \gui {Save
|
|---|
| 324 | As} menu entry, and then choose an entry from the format menu. The
|
|---|
| 325 | first thing we need to do is to find out which action sent the
|
|---|
| 326 | signal using QObject::sender(). This function returns the sender
|
|---|
| 327 | as a QObject pointer. Since we know that the sender is an action
|
|---|
| 328 | object, we can safely cast the QObject. We could have used a
|
|---|
| 329 | C-style cast or a C++ \c static_cast<>(), but as a defensive
|
|---|
| 330 | programming technique we use a qobject_cast(). The advantage is
|
|---|
| 331 | that if the object has the wrong type, a null pointer is
|
|---|
| 332 | returned. Crashes due to null pointers are much easier to diagnose
|
|---|
| 333 | than crashes due to unsafe casts.
|
|---|
| 334 |
|
|---|
| 335 | Once we have the action, we extract the chosen format using
|
|---|
| 336 | QAction::data(). (When the actions are created, we use
|
|---|
| 337 | QAction::setData() to set our own custom data attached to the
|
|---|
| 338 | action, as a QVariant. More on this when we review \c
|
|---|
| 339 | createActions().)
|
|---|
| 340 |
|
|---|
| 341 | Now that we know the format, we call the private \c saveFile()
|
|---|
| 342 | function to save the currently displayed image.
|
|---|
| 343 |
|
|---|
| 344 | \snippet examples/widgets/scribble/mainwindow.cpp 7
|
|---|
| 345 | \snippet examples/widgets/scribble/mainwindow.cpp 8
|
|---|
| 346 |
|
|---|
| 347 | We use the \c penColor() slot to retrieve a new color from the
|
|---|
| 348 | user with a QColorDialog. If the user chooses a new color, we
|
|---|
| 349 | make it the scribble area's color.
|
|---|
| 350 |
|
|---|
| 351 | \snippet examples/widgets/scribble/mainwindow.cpp 9
|
|---|
| 352 | \snippet examples/widgets/scribble/mainwindow.cpp 10
|
|---|
| 353 |
|
|---|
| 354 | To retrieve a new pen width in the \c penWidth() slot, we use
|
|---|
| 355 | QInputDialog. The QInputDialog class provides a simple
|
|---|
| 356 | convenience dialog to get a single value from the user. We use
|
|---|
| 357 | the static QInputDialog::getInteger() function, which combines a
|
|---|
| 358 | QLabel and a QSpinBox. The QSpinBox is initialized with the
|
|---|
| 359 | scribble area's pen width, allows a range from 1 to 50, a step of
|
|---|
| 360 | 1 (meaning that the up and down arrow increment or decrement the
|
|---|
| 361 | value by 1).
|
|---|
| 362 |
|
|---|
| 363 | The boolean \c ok variable will be set to \c true if the user
|
|---|
| 364 | clicked \gui OK and to \c false if the user pressed \gui Cancel.
|
|---|
| 365 |
|
|---|
| 366 | \snippet examples/widgets/scribble/mainwindow.cpp 11
|
|---|
| 367 | \snippet examples/widgets/scribble/mainwindow.cpp 12
|
|---|
| 368 |
|
|---|
| 369 | We implement the \c about() slot to create a message box
|
|---|
| 370 | describing what the example is designed to show.
|
|---|
| 371 |
|
|---|
| 372 | \snippet examples/widgets/scribble/mainwindow.cpp 13
|
|---|
| 373 | \snippet examples/widgets/scribble/mainwindow.cpp 14
|
|---|
| 374 |
|
|---|
| 375 | In the \c createAction() function we create the actions
|
|---|
| 376 | representing the menu entries and connect them to the appropiate
|
|---|
| 377 | slots. In particular we create the actions found in the \gui
|
|---|
| 378 | {Save As} sub-menu. We use QImageWriter::supportedImageFormats()
|
|---|
| 379 | to get a list of the supported formats (as a QList<QByteArray>).
|
|---|
| 380 |
|
|---|
| 381 | Then we iterate through the list, creating an action for each
|
|---|
| 382 | format. We call QAction::setData() with the file format, so we
|
|---|
| 383 | can retrieve it later as QAction::data(). We could also have
|
|---|
| 384 | deduced the file format from the action's text, by truncating the
|
|---|
| 385 | "...", but that would have been inelegant.
|
|---|
| 386 |
|
|---|
| 387 | \snippet examples/widgets/scribble/mainwindow.cpp 15
|
|---|
| 388 | \snippet examples/widgets/scribble/mainwindow.cpp 16
|
|---|
| 389 |
|
|---|
| 390 | In the \c createMenu() function, we add the previously created
|
|---|
| 391 | format actions to the \c saveAsMenu. Then we add the rest of the
|
|---|
| 392 | actions as well as the \c saveAsMenu sub-menu to the \gui File,
|
|---|
| 393 | \gui Options and \gui Help menus.
|
|---|
| 394 |
|
|---|
| 395 | The QMenu class provides a menu widget for use in menu bars,
|
|---|
| 396 | context menus, and other popup menus. The QMenuBar class provides
|
|---|
| 397 | a horizontal menu bar with a list of pull-down \l{QMenu}s. At the
|
|---|
| 398 | end we put the \gui File and \gui Options menus in the \c
|
|---|
| 399 | {MainWindow}'s menu bar, which we retrieve using the
|
|---|
| 400 | QMainWindow::menuBar() function.
|
|---|
| 401 |
|
|---|
| 402 | \snippet examples/widgets/scribble/mainwindow.cpp 17
|
|---|
| 403 | \snippet examples/widgets/scribble/mainwindow.cpp 18
|
|---|
| 404 |
|
|---|
| 405 | In \c mayBeSave(), we check if there are any unsaved changes. If
|
|---|
| 406 | there are any, we use QMessageBox to give the user a warning that
|
|---|
| 407 | the image has been modified and the opportunity to save the
|
|---|
| 408 | modifications.
|
|---|
| 409 |
|
|---|
| 410 | As with QColorDialog and QFileDialog, the easiest way to create a
|
|---|
| 411 | QMessageBox is to use its static functions. QMessageBox provides
|
|---|
| 412 | a range of different messages arranged along two axes: severity
|
|---|
| 413 | (question, information, warning and critical) and complexity (the
|
|---|
| 414 | number of necessary response buttons). Here we use the \c
|
|---|
| 415 | warning() function sice the message is rather important.
|
|---|
| 416 |
|
|---|
| 417 | If the user chooses to save, we call the private \c saveFile()
|
|---|
| 418 | function. For simplicitly, we use PNG as the file format; the
|
|---|
| 419 | user can always press \gui Cancel and save the file using another
|
|---|
| 420 | format.
|
|---|
| 421 |
|
|---|
| 422 | The \c maybeSave() function returns \c false if the user clicks
|
|---|
| 423 | \gui Cancel; otherwise it returns \c true.
|
|---|
| 424 |
|
|---|
| 425 | \snippet examples/widgets/scribble/mainwindow.cpp 19
|
|---|
| 426 | \snippet examples/widgets/scribble/mainwindow.cpp 20
|
|---|
| 427 |
|
|---|
| 428 | In \c saveFile(), we pop up a file dialog with a file name
|
|---|
| 429 | suggestion. The static QFileDialog::getSaveFileName() function
|
|---|
| 430 | returns a file name selected by the user. The file does not have
|
|---|
| 431 | to exist.
|
|---|
| 432 | */
|
|---|