1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
6 ** This file is part of the documentation of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:FDL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
17 ** GNU Free Documentation License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Free
19 ** Documentation License version 1.3 as published by the Free Software
20 ** Foundation and appearing in the file included in the packaging of
21 ** this file. Please review the following information to ensure
22 ** the GNU Free Documentation License version 1.3 requirements
23 ** will be met: http://www.gnu.org/copyleft/fdl.html.
26 ****************************************************************************/
29 \example opengl/2dpainting
30 \title 2D Painting Example
32 \brief The 2D Painting example shows how QPainter and QGLWidget can be used
33 together to display accelerated 2D graphics on supported hardware.
35 \image 2dpainting-example.png
37 The QPainter class is used to draw 2D graphics primitives onto
38 paint devices provided by QPaintDevice subclasses, such as QWidget
41 Since QGLWidget is a subclass of QWidget, it is possible
42 to reimplement its \l{QWidget::paintEvent()}{paintEvent()} and use
43 QPainter to draw on the device, just as you would with a QWidget.
44 The only difference is that the painting operations will be accelerated
45 in hardware if it is supported by your system's OpenGL drivers.
47 In this example, we perform the same painting operations on a
48 QWidget and a QGLWidget. The QWidget is shown with anti-aliasing
49 enabled, and the QGLWidget will also use anti-aliasing if the
50 required extensions are supported by your system's OpenGL driver.
54 To be able to compare the results of painting onto a QGLWidget subclass
55 with native drawing in a QWidget subclass, we want to show both kinds
56 of widget side by side. To do this, we derive subclasses of QWidget and
57 QGLWidget, using a separate \c Helper class to perform the same painting
58 operations for each, and lay them out in a top-level widget, itself
59 provided a the \c Window class.
61 \section1 Helper Class Definition
63 In this example, the painting operations are performed by a helper class.
64 We do this because we want the same painting operations to be performed
65 for both our QWidget subclass and the QGLWidget subclass.
67 The \c Helper class is minimal:
69 \snippet examples/opengl/2dpainting/helper.h 0
71 Apart from the constructor, it only provides a \c paint() function to paint
72 using a painter supplied by one of our widget subclasses.
74 \section1 Helper Class Implementation
76 The constructor of the class sets up the resources it needs to paint
77 content onto a widget:
79 \snippet examples/opengl/2dpainting/helper.cpp 0
81 The actual painting is performed in the \c paint() function. This takes
82 a QPainter that has already been set up to paint onto a paint device
83 (either a QWidget or a QGLWidget), a QPaintEvent that provides information
84 about the region to be painted, and a measure of the elapsed time (in
85 milliseconds) since the paint device was last updated.
87 \snippet examples/opengl/2dpainting/helper.cpp 1
89 We begin painting by filling in the region contained in the paint event
90 before translating the origin of the coordinate system so that the rest
91 of the painting operations will be displaced towards the center of the
94 We draw a spiral pattern of circles, using the elapsed time specified to
95 animate them so that they appear to move outward and around the coordinate
98 \snippet examples/opengl/2dpainting/helper.cpp 2
100 Since the coordinate system is rotated many times during
101 this process, we \l{QPainter::save()}{save()} the QPainter's state
102 beforehand and \l{QPainter::restore()}{restore()} it afterwards.
104 \snippet examples/opengl/2dpainting/helper.cpp 3
106 We draw some text at the origin to complete the effect.
108 \section1 Widget Class Definition
110 The \c Widget class provides a basic custom widget that we use to
111 display the simple animation painted by the \c Helper class.
113 \snippet examples/opengl/2dpainting/widget.h 0
115 Apart from the constructor, it only contains a
116 \l{QWidget::paintEvent()}{paintEvent()} function, that lets us draw
117 customized content, and a slot that is used to animate its contents.
118 One member variable keeps track of the \c Helper that the widget uses
119 to paint its contents, and the other records the elapsed time since
122 \section1 Widget Class Implementation
124 The constructor only initializes the member variables, storing the
125 \c Helper object supplied and calling the base class's constructor,
126 and enforces a fixed size for the widget:
128 \snippet examples/opengl/2dpainting/widget.cpp 0
130 The \c animate() slot is called whenever a timer, which we define later, times
133 \snippet examples/opengl/2dpainting/widget.cpp 1
135 Here, we determine the interval that has elapsed since the timer last
136 timed out, and we add it to any existing value before repainting the
137 widget. Since the animation used in the \c Helper class loops every second,
138 we can use the modulo operator to ensure that the \c elapsed variable is
139 always less than 1000.
141 Since the \c Helper class does all of the actual painting, we only have
142 to implement a paint event that sets up a QPainter for the widget and calls
143 the helper's \c paint() function:
145 \snippet examples/opengl/2dpainting/widget.cpp 2
147 \section1 GLWidget Class Definition
149 The \c GLWidget class definition is basically the same as the \c Widget
150 class except that it is derived from QGLWidget.
152 \snippet examples/opengl/2dpainting/glwidget.h 0
154 Again, the member variables record the \c Helper used to paint the
155 widget and the elapsed time since the previous update.
157 \section1 GLWidget Class Implementation
159 The constructor differs a little from the \c Widget class's constructor:
161 \snippet examples/opengl/2dpainting/glwidget.cpp 0
163 As well as initializing the \c elapsed member variable and storing the
164 \c Helper object used to paint the widget, the base class's constructor
165 is called with the format that specifies the \l QGL::SampleBuffers flag.
166 This enables anti-aliasing if it is supported by your system's OpenGL
169 The \c animate() slot is exactly the same as that provided by the \c Widget
172 \snippet examples/opengl/2dpainting/glwidget.cpp 1
174 The \c paintEvent() is almost the same as that found in the \c Widget class:
176 \snippet examples/opengl/2dpainting/glwidget.cpp 2
178 Since anti-aliasing will be enabled if available, we only need to set up
179 a QPainter on the widget and call the helper's \c paint() function to display
180 the widget's contents.
182 \section1 Window Class Definition
184 The \c Window class has a basic, minimal definition:
186 \snippet examples/opengl/2dpainting/window.h 0
188 It contains a single \c Helper object that will be shared between all
191 \section1 Window Class Implementation
193 The constructor does all the work, creating a widget of each type and
194 inserting them with labels into a layout:
196 \snippet examples/opengl/2dpainting/window.cpp 0
198 A timer with a 50 millisecond time out is constructed for animation purposes,
199 and connected to the \c animate() slots of the \c Widget and \c GLWidget objects.
200 Once started, the widgets should be updated at around 20 frames per second.
202 \section1 Running the Example
204 The example shows the same painting operations performed at the same time
205 in a \c Widget and a \c GLWidget. The quality and speed of rendering in the
206 \c GLWidget depends on the level of support for multisampling and hardware
207 acceleration that your system's OpenGL driver provides. If support for either
208 of these is lacking, the driver may fall back on a software renderer that
209 may trade quality for speed.