From d16c565ca6a55788435c52ad45647eda67854d80 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Tue, 18 Sep 2012 20:32:53 +0200 Subject: Move opengl/wid/net example docs to proper folders. Change-Id: I846439a9cf7ad965ed27a00f98dbc4ff97abe73b Reviewed-by: Jerome Pasion Reviewed-by: Martin Smith --- examples/widgets/doc/src/scribble.qdoc | 417 +++++++++++++++++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 examples/widgets/doc/src/scribble.qdoc (limited to 'examples/widgets/doc/src/scribble.qdoc') diff --git a/examples/widgets/doc/src/scribble.qdoc b/examples/widgets/doc/src/scribble.qdoc new file mode 100644 index 0000000000..5749b9ed07 --- /dev/null +++ b/examples/widgets/doc/src/scribble.qdoc @@ -0,0 +1,417 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms +** and conditions contained in a signed written agreement between you +** and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example widgets/scribble + \title Scribble Example + + The Scribble example shows how to reimplement some of QWidget's + event handlers to receive the events generated for the + application's widgets. + + We reimplement the mouse event handlers to implement drawing, the + paint event handler to update the application and the resize event + handler to optimize the application's appearance. In addition we + reimplement the close event handler to intercept the close events + before terminating the application. + + The example also demonstrates how to use QPainter to draw an image + in real time, as well as to repaint widgets. + + \image scribble-example.png Screenshot of the Scribble example + + With the Scribble application the users can draw an image. The + \uicontrol File menu gives the users the possibility to open and edit an + existing image file, save an image and exit the application. While + drawing, the \uicontrol Options menu allows the users to to choose the + pen color and pen width, as well as clear the screen. In addition + the \uicontrol Help menu provides the users with information about the + Scribble example in particular, and about Qt in general. + + The example consists of two classes: + + \list + \li \c ScribbleArea is a custom widget that displays a QImage and + allows to the user to draw on it. + \li \c MainWindow provides a menu above the \c ScribbleArea. + \endlist + + We will start by reviewing the \c ScribbleArea class. Then we will + review the \c MainWindow class, which uses \c ScribbleArea. + + \section1 ScribbleArea Class Definition + + \snippet widgets/scribble/scribblearea.h 0 + + The \c ScribbleArea class inherits from QWidget. We reimplement + the \c mousePressEvent(), \c mouseMoveEvent() and \c + mouseReleaseEvent() functions to implement the drawing. We + reimplement the \c paintEvent() function to update the scribble + area, and the \c resizeEvent() function to ensure that the QImage + on which we draw is at least as large as the widget at any time. + + We need several public functions: \c openImage() loads an image + from a file into the scribble area, allowing the user to edit the + image; \c save() writes the currently displayed image to file; \c + clearImage() slot clears the image displayed in the scribble + area. We need the private \c drawLineTo() function to actually do + the drawing, and \c resizeImage() to change the size of a + QImage. The \c print() slot handles printing. + + We also need the following private variables: + + \list + \li \c modified is \c true if there are unsaved + changes to the image displayed in the scribble area. + \li \c scribbling is \c true while the user is pressing + the left mouse button within the scribble area. + \li \c penWidth and \c penColor hold the currently + set width and color for the pen used in the application. + \li \c image stores the image drawn by the user. + \li \c lastPoint holds the position of the cursor at the last + mouse press or mouse move event. + \endlist + + \section1 ScribbleArea Class Implementation + + \snippet widgets/scribble/scribblearea.cpp 0 + + In the constructor, we set the Qt::WA_StaticContents + attribute for the widget, indicating that the widget contents are + rooted to the top-left corner and don't change when the widget is + resized. Qt uses this attribute to optimize paint events on + resizes. This is purely an optimization and should only be used + for widgets whose contents are static and rooted to the top-left + corner. + + \snippet widgets/scribble/scribblearea.cpp 1 + \snippet widgets/scribble/scribblearea.cpp 2 + + In the \c openImage() function, we load the given image. Then we + resize the loaded QImage to be at least as large as the widget in + both directions using the private \c resizeImage() function and + we set the \c image member variable to be the loaded image. At + the end, we call QWidget::update() to schedule a repaint. + + \snippet widgets/scribble/scribblearea.cpp 3 + \snippet widgets/scribble/scribblearea.cpp 4 + + The \c saveImage() function creates a QImage object that covers + only the visible section of the actual \c image and saves it using + QImage::save(). If the image is successfully saved, we set the + scribble area's \c modified variable to \c false, because there is + no unsaved data. + + \snippet widgets/scribble/scribblearea.cpp 5 + \snippet widgets/scribble/scribblearea.cpp 6 + \codeline + \snippet widgets/scribble/scribblearea.cpp 7 + \snippet widgets/scribble/scribblearea.cpp 8 + + The \c setPenColor() and \c setPenWidth() functions set the + current pen color and width. These values will be used for future + drawing operations. + + \snippet widgets/scribble/scribblearea.cpp 9 + \snippet widgets/scribble/scribblearea.cpp 10 + + The public \c clearImage() slot clears the image displayed in the + scribble area. We simply fill the entire image with white, which + corresponds to RGB value (255, 255, 255). As usual when we modify + the image, we set \c modified to \c true and schedule a repaint. + + \snippet widgets/scribble/scribblearea.cpp 11 + \snippet widgets/scribble/scribblearea.cpp 12 + + For mouse press and mouse release events, we use the + QMouseEvent::button() function to find out which button caused + the event. For mose move events, we use QMouseEvent::buttons() + to find which buttons are currently held down (as an OR-combination). + + If the users press the left mouse button, we store the position + of the mouse cursor in \c lastPoint. We also make a note that the + user is currently scribbling. (The \c scribbling variable is + necessary because we can't assume that a mouse move and mouse + release event is always preceded by a mouse press event on the + same widget.) + + If the user moves the mouse with the left button pressed down or + releases the button, we call the private \c drawLineTo() function + to draw. + + \snippet widgets/scribble/scribblearea.cpp 13 + \snippet widgets/scribble/scribblearea.cpp 14 + + In the reimplementation of the \l + {QWidget::paintEvent()}{paintEvent()} function, we simply create + a QPainter for the scribble area, and draw the image. + + At this point, you might wonder why we don't just draw directly + onto the widget instead of drawing in a QImage and copying the + QImage onto screen in \c paintEvent(). There are at least three + good reasons for this: + + \list + \li The window system requires us to be able to redraw the widget + \e{at any time}. For example, if the window is minimized and + restored, the window system might have forgotten the contents + of the widget and send us a paint event. In other words, we + can't rely on the window system to remember our image. + + \li Qt normally doesn't allow us to paint outside of \c + paintEvent(). In particular, we can't paint from the mouse + event handlers. (This behavior can be changed using the + Qt::WA_PaintOnScreen widget attribute, though.) + + \li If initialized properly, a QImage is guaranteed to use 8-bit + for each color channel (red, green, blue, and alpha), whereas + a QWidget might have a lower color depth, depending on the + monitor configuration. This means that if we load a 24-bit or + 32-bit image and paint it onto a QWidget, then copy the + QWidget into a QImage again, we might lose some information. + \endlist + + \snippet widgets/scribble/scribblearea.cpp 15 + \snippet widgets/scribble/scribblearea.cpp 16 + + When the user starts the Scribble application, a resize event is + generated and an image is created and displayed in the scribble + area. We make this initial image slightly larger than the + application's main window and scribble area, to avoid always + resizing the image when the user resizes the main window (which + would be very inefficient). But when the main window becomes + larger than this initial size, the image needs to be resized. + + \snippet widgets/scribble/scribblearea.cpp 17 + \snippet widgets/scribble/scribblearea.cpp 18 + + In \c drawLineTo(), we draw a line from the point where the mouse + was located when the last mouse press or mouse move occurred, we + set \c modified to true, we generate a repaint event, and we + update \c lastPoint so that next time \c drawLineTo() is called, + we continue drawing from where we left. + + We could call the \c update() function with no parameter, but as + an easy optimization we pass a QRect that specifies the rectangle + inside the scribble are needs updating, to avoid a complete + repaint of the widget. + + \snippet widgets/scribble/scribblearea.cpp 19 + \snippet widgets/scribble/scribblearea.cpp 20 + + QImage has no nice API for resizing an image. There's a + QImage::copy() function that could do the trick, but when used to + expand an image, it fills the new areas with black, whereas we + want white. + + So the trick is to create a brand new QImage with the right size, + to fill it with white, and to draw the old image onto it using + QPainter. The new image is given the QImage::Format_RGB32 + format, which means that each pixel is stored as 0xffRRGGBB + (where RR, GG, and BB are the red, green and blue + color channels, ff is the hexadecimal value 255). + + Printing is handled by the \c print() slot: + + \snippet widgets/scribble/scribblearea.cpp 21 + + We construct a high resolution QPrinter object for the required + output format, using a QPrintDialog to ask the user to specify a + page size and indicate how the output should be formatted on the page. + + If the dialog is accepted, we perform the task of printing to the paint + device: + + \snippet widgets/scribble/scribblearea.cpp 22 + + Printing an image to a file in this way is simply a matter of + painting onto the QPrinter. We scale the image to fit within the + available space on the page before painting it onto the paint + device. + + \section1 MainWindow Class Definition + + \snippet widgets/scribble/mainwindow.h 0 + + The \c MainWindow class inherits from QMainWindow. We reimplement + the \l{QWidget::closeEvent()}{closeEvent()} handler from QWidget. + The \c open(), \c save(), \c penColor() and \c penWidth() + slots correspond to menu entries. In addition we create four + private functions. + + We use the boolean \c maybeSave() function to check if there are + any unsaved changes. If there are unsaved changes, we give the + user the opportunity to save these changes. The function returns + \c false if the user clicks \uicontrol Cancel. We use the \c saveFile() + function to let the user save the image currently displayed in + the scribble area. + + \section1 MainWindow Class Implementation + + \snippet widgets/scribble/mainwindow.cpp 0 + + In the constructor, we create a scribble area which we make the + central widget of the \c MainWindow widget. Then we create the + associated actions and menus. + + \snippet widgets/scribble/mainwindow.cpp 1 + \snippet widgets/scribble/mainwindow.cpp 2 + + Close events are sent to widgets that the users want to close, + usually by clicking \uicontrol{File|Exit} or by clicking the \uicontrol X + title bar button. By reimplementing the event handler, we can + intercept attempts to close the application. + + In this example, we use the close event to ask the user to save + any unsaved changes. The logic for that is located in the \c + maybeSave() function. If \c maybeSave() returns true, there are + no modifications or the users successfully saved them, and we + accept the event. The application can then terminate normally. If + \c maybeSave() returns false, the user clicked \uicontrol Cancel, so we + "ignore" the event, leaving the application unaffected by it. + + \snippet widgets/scribble/mainwindow.cpp 3 + \snippet widgets/scribble/mainwindow.cpp 4 + + In the \c open() slot we first give the user the opportunity to + save any modifications to the currently displayed image, before a + new image is loaded into the scribble area. Then we ask the user + to choose a file and we load the file in the \c ScribbleArea. + + \snippet widgets/scribble/mainwindow.cpp 5 + \snippet widgets/scribble/mainwindow.cpp 6 + + The \c save() slot is called when the users choose the \uicontrol {Save + As} menu entry, and then choose an entry from the format menu. The + first thing we need to do is to find out which action sent the + signal using QObject::sender(). This function returns the sender + as a QObject pointer. Since we know that the sender is an action + object, we can safely cast the QObject. We could have used a + C-style cast or a C++ \c static_cast<>(), but as a defensive + programming technique we use a qobject_cast(). The advantage is + that if the object has the wrong type, a null pointer is + returned. Crashes due to null pointers are much easier to diagnose + than crashes due to unsafe casts. + + Once we have the action, we extract the chosen format using + QAction::data(). (When the actions are created, we use + QAction::setData() to set our own custom data attached to the + action, as a QVariant. More on this when we review \c + createActions().) + + Now that we know the format, we call the private \c saveFile() + function to save the currently displayed image. + + \snippet widgets/scribble/mainwindow.cpp 7 + \snippet widgets/scribble/mainwindow.cpp 8 + + We use the \c penColor() slot to retrieve a new color from the + user with a QColorDialog. If the user chooses a new color, we + make it the scribble area's color. + + \snippet widgets/scribble/mainwindow.cpp 9 + \snippet widgets/scribble/mainwindow.cpp 10 + + To retrieve a new pen width in the \c penWidth() slot, we use + QInputDialog. The QInputDialog class provides a simple + convenience dialog to get a single value from the user. We use + the static QInputDialog::getInt() function, which combines a + QLabel and a QSpinBox. The QSpinBox is initialized with the + scribble area's pen width, allows a range from 1 to 50, a step of + 1 (meaning that the up and down arrow increment or decrement the + value by 1). + + The boolean \c ok variable will be set to \c true if the user + clicked \uicontrol OK and to \c false if the user pressed \uicontrol Cancel. + + \snippet widgets/scribble/mainwindow.cpp 11 + \snippet widgets/scribble/mainwindow.cpp 12 + + We implement the \c about() slot to create a message box + describing what the example is designed to show. + + \snippet widgets/scribble/mainwindow.cpp 13 + \snippet widgets/scribble/mainwindow.cpp 14 + + In the \c createAction() function we create the actions + representing the menu entries and connect them to the appropriate + slots. In particular we create the actions found in the \uicontrol + {Save As} sub-menu. We use QImageWriter::supportedImageFormats() + to get a list of the supported formats (as a QList). + + Then we iterate through the list, creating an action for each + format. We call QAction::setData() with the file format, so we + can retrieve it later as QAction::data(). We could also have + deduced the file format from the action's text, by truncating the + "...", but that would have been inelegant. + + \snippet widgets/scribble/mainwindow.cpp 15 + \snippet widgets/scribble/mainwindow.cpp 16 + + In the \c createMenu() function, we add the previously created + format actions to the \c saveAsMenu. Then we add the rest of the + actions as well as the \c saveAsMenu sub-menu to the \uicontrol File, + \uicontrol Options and \uicontrol Help menus. + + The QMenu class provides a menu widget for use in menu bars, + context menus, and other popup menus. The QMenuBar class provides + a horizontal menu bar with a list of pull-down \l{QMenu}s. At the + end we put the \uicontrol File and \uicontrol Options menus in the \c + {MainWindow}'s menu bar, which we retrieve using the + QMainWindow::menuBar() function. + + \snippet widgets/scribble/mainwindow.cpp 17 + \snippet widgets/scribble/mainwindow.cpp 18 + + In \c mayBeSave(), we check if there are any unsaved changes. If + there are any, we use QMessageBox to give the user a warning that + the image has been modified and the opportunity to save the + modifications. + + As with QColorDialog and QFileDialog, the easiest way to create a + QMessageBox is to use its static functions. QMessageBox provides + a range of different messages arranged along two axes: severity + (question, information, warning and critical) and complexity (the + number of necessary response buttons). Here we use the \c + warning() function sice the message is rather important. + + If the user chooses to save, we call the private \c saveFile() + function. For simplicitly, we use PNG as the file format; the + user can always press \uicontrol Cancel and save the file using another + format. + + The \c maybeSave() function returns \c false if the user clicks + \uicontrol Cancel; otherwise it returns \c true. + + \snippet widgets/scribble/mainwindow.cpp 19 + \snippet widgets/scribble/mainwindow.cpp 20 + + In \c saveFile(), we pop up a file dialog with a file name + suggestion. The static QFileDialog::getSaveFileName() function + returns a file name selected by the user. The file does not have + to exist. +*/ -- cgit v1.2.3