doc/src/examples/painterpaths.qdoc
branchRCL_3
changeset 7 3f74d0d4af4c
equal deleted inserted replaced
6:dee5afe5301f 7:3f74d0d4af4c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 painting/painterpaths
       
    44     \title Painter Paths Example
       
    45 
       
    46     The Painter Paths example shows how painter paths can be used to
       
    47     build complex shapes for rendering.
       
    48 
       
    49     \image painterpaths-example.png
       
    50 
       
    51     The QPainterPath class provides a container for painting
       
    52     operations, enabling graphical shapes to be constructed and
       
    53     reused.
       
    54 
       
    55     A painter path is an object composed of a number of graphical
       
    56     building blocks (such as rectangles, ellipses, lines, and curves),
       
    57     and can be used for filling, outlining, and clipping. The main
       
    58     advantage of painter paths over normal drawing operations is that
       
    59     complex shapes only need to be created once, but they can be drawn
       
    60     many times using only calls to QPainter::drawPath().
       
    61 
       
    62     The example consists of two classes:
       
    63 
       
    64     \list
       
    65         \o The \c RenderArea class which is a custom widget displaying
       
    66            a single painter path.
       
    67         \o The \c Window class which is the applications main window
       
    68            displaying several \c RenderArea widgets, and allowing the user
       
    69            to manipulate the painter paths' filling, pen, color
       
    70            and rotation angle.
       
    71     \endlist
       
    72 
       
    73     First we will review the \c Window class, then we will take a look
       
    74     at the \c RenderArea class.
       
    75 
       
    76     \section1 Window Class Definition
       
    77 
       
    78     The \c Window class inherits QWidget, and is the applications main
       
    79     window displaying several \c RenderArea widgets, and allowing the
       
    80     user to manipulate the painter paths' filling, pen, color and
       
    81     rotation angle.
       
    82 
       
    83     \snippet examples/painting/painterpaths/window.h 0
       
    84 
       
    85     We declare three private slots to respond to user input regarding
       
    86     filling and color: \c fillRuleChanged(), \c fillGradientChanged()
       
    87     and \c penColorChanged().
       
    88 
       
    89     When the user changes the pen width and the rotation angle, the
       
    90     new value is passed directly on to the \c RenderArea widgets using
       
    91     the QSpinBox::valueChanged() signal. The reason why we must
       
    92     implement slots to update the filling and color, is that QComboBox
       
    93     doesn't provide a similar signal passing the new value as
       
    94     argument; so we need to retrieve the new value, or values, before
       
    95     we can update the \c RenderArea widgets.
       
    96 
       
    97     \snippet examples/painting/painterpaths/window.h 1
       
    98 
       
    99     We also declare a couple of private convenience functions: \c
       
   100     populateWithColors() populates a given QComboBox with items
       
   101     corresponding to the color names Qt knows about, and \c
       
   102     currentItemData() returns the current item for a given QComboBox.
       
   103 
       
   104     \snippet examples/painting/painterpaths/window.h 2
       
   105 
       
   106     Then we declare the various components of the main window
       
   107     widget. We also declare a convenience constant specifying the
       
   108     number of \c RenderArea widgets.
       
   109 
       
   110     \section1 Window Class Implementation
       
   111 
       
   112     In the implementation of the \c Window class we first declare the
       
   113     constant \c Pi with six significant figures:
       
   114 
       
   115     \snippet examples/painting/painterpaths/window.cpp 0
       
   116 
       
   117     In the constructor, we then define the various painter paths and
       
   118     create corresponding \c RenderArea widgets which will render the
       
   119     graphical shapes:
       
   120 
       
   121     \snippet examples/painting/painterpaths/window.cpp 1
       
   122 
       
   123     We construct a rectangle with sharp corners using the
       
   124     QPainterPath::moveTo() and QPainterPath::lineTo()
       
   125     functions.
       
   126 
       
   127     QPainterPath::moveTo() moves the current point to the point passed
       
   128     as argument. A painter path is an object composed of a number of
       
   129     graphical building blocks, i.e. subpaths. Moving the current point
       
   130     will also start a new subpath (implicitly closing the previously
       
   131     current path when the new one is started). The
       
   132     QPainterPath::lineTo() function adds a straight line from the
       
   133     current point to the given end point. After the line is drawn, the
       
   134     current point is updated to be at the end point of the line.
       
   135 
       
   136     We first move the current point starting a new subpath, and we
       
   137     draw three of the rectangle's sides. Then we call the
       
   138     QPainterPath::closeSubpath() function which draws a line to the
       
   139     beginning of the current subpath. A new subpath is automatically
       
   140     begun when the current subpath is closed. The current point of the
       
   141     new path is (0, 0). We could also have called
       
   142     QPainterPath::lineTo() to draw the last line as well, and then
       
   143     explicitly start a new subpath using the QPainterPath::moveTo()
       
   144     function.
       
   145 
       
   146     QPainterPath also provide the QPainterPath::addRect() convenience
       
   147     function, which adds a given rectangle to the path as a closed
       
   148     subpath. The rectangle is added as a clockwise set of lines. The
       
   149     painter path's current position after the rect has been added is
       
   150     at the top-left corner of the rectangle.
       
   151 
       
   152     \snippet examples/painting/painterpaths/window.cpp 2
       
   153 
       
   154     Then we construct a rectangle with rounded corners. As before, we
       
   155     use the QPainterPath::moveTo() and QPainterPath::lineTo()
       
   156     functions to draw the rectangle's sides. To create the rounded
       
   157     corners we use the QPainterPath::arcTo() function.
       
   158 
       
   159     QPainterPath::arcTo() creates an arc that occupies the given
       
   160     rectangle (specified by a QRect or the rectangle's coordinates),
       
   161     beginning at the given start angle and extending the given degrees
       
   162     counter-clockwise. Angles are specified in degrees. Clockwise arcs
       
   163     can be specified using negative angles.  The function connects the
       
   164     current point to the starting point of the arc if they are not
       
   165     already connected.
       
   166 
       
   167     \snippet examples/painting/painterpaths/window.cpp 3
       
   168 
       
   169     We also use the QPainterPath::arcTo() function to construct the
       
   170     ellipse path. First we move the current point starting a new
       
   171     path. Then we call QPainterPath::arcTo() with starting angle 0.0
       
   172     and 360.0 degrees as the last argument, creating an ellipse.
       
   173 
       
   174     Again, QPainterPath provides a convenience function (
       
   175     QPainterPath::addEllipse()) which creates an ellipse within a
       
   176     given bounding rectangle and adds it to the painter path. If the
       
   177     current subpath is closed, a new subpath is started. The ellipse
       
   178     is composed of a clockwise curve, starting and finishing at zero
       
   179     degrees (the 3 o'clock position).
       
   180 
       
   181     \snippet examples/painting/painterpaths/window.cpp 4
       
   182 
       
   183     When constructing the pie chart path we continue to use a
       
   184     combination of the mentioned functions: First we move the current
       
   185     point, starting a new subpath. Then we create a line from the
       
   186     center of the chart to the arc, and the arc itself. When we close
       
   187     the subpath, we implicitly construct the last line back to the
       
   188     center of the chart.
       
   189 
       
   190     \snippet examples/painting/painterpaths/window.cpp 5
       
   191 
       
   192     Constructing a polygon is equivalent to constructing a rectangle.
       
   193 
       
   194     QPainterPath also provide the QPainterPath::addPolygon()
       
   195     convenience function which adds the given polygon to the path as a
       
   196     new subpath. Current position after the polygon has been added is
       
   197     the last point in polygon.
       
   198 
       
   199     \snippet examples/painting/painterpaths/window.cpp 6
       
   200 
       
   201     Then we create a path consisting of a group of subpaths: First we
       
   202     move the current point, and create a circle using the
       
   203     QPainterPath::arcTo() function with starting angle 0.0, and 360
       
   204     degrees as the last argument, as we did when we created the
       
   205     ellipse path. Then we move the current point again, starting a
       
   206     new subpath, and construct three sides of a square using the
       
   207     QPainterPath::lineTo() function.
       
   208 
       
   209     Now, when we call the QPainterPath::closeSubpath() fucntion the
       
   210     last side is created. Remember that the
       
   211     QPainterPath::closeSubpath() function draws a line to the
       
   212     beginning of the \e current subpath, i.e the square.
       
   213 
       
   214     QPainterPath provide a convenience function,
       
   215     QPainterPath::addPath() which adds a given path to the path that
       
   216     calls the function.
       
   217 
       
   218     \snippet examples/painting/painterpaths/window.cpp 7
       
   219 
       
   220     When creating the text path, we first create the font. Then we set
       
   221     the font's style strategy which tells the font matching algorithm
       
   222     what type of fonts should be used to find an appropriate default
       
   223     family. QFont::ForceOutline forces the use of outline fonts.
       
   224 
       
   225     To construct the text, we use the QPainterPath::addText() function
       
   226     which adds the given text to the path as a set of closed subpaths
       
   227     created from the supplied font. The subpaths are positioned so
       
   228     that the left end of the text's baseline lies at the specified
       
   229     point.
       
   230 
       
   231     \snippet examples/painting/painterpaths/window.cpp 8
       
   232 
       
   233     To create the Bezier path, we use the QPainterPath::cubicTo()
       
   234     function which adds a Bezier curve between the current point and
       
   235     the given end point with the given control point.  After the curve
       
   236     is added, the current point is updated to be at the end point of
       
   237     the curve.
       
   238 
       
   239     In this case we omit to close the subpath so that we only have a
       
   240     simple curve. But there is still a logical line from the curve's
       
   241     endpoint back to the beginning of the subpath; it becomes visible
       
   242     when filling the path as can be seen in the applications main
       
   243     window.
       
   244 
       
   245     \snippet examples/painting/painterpaths/window.cpp 9
       
   246 
       
   247     The final path that we construct shows that you can use
       
   248     QPainterPath to construct rather complex shapes using only the
       
   249     previous mentioned QPainterPath::moveTo(), QPainterPath::lineTo()
       
   250     and QPainterPath::closeSubpath() functions.
       
   251 
       
   252     \snippet examples/painting/painterpaths/window.cpp 10
       
   253 
       
   254     Now that we have created all the painter paths that we need, we
       
   255     create a corresponding \c RenderArea widget for each. In the end,
       
   256     we make sure that the number of render areas is correct using the
       
   257     Q_ASSERT() macro.
       
   258 
       
   259     \snippet examples/painting/painterpaths/window.cpp 11
       
   260 
       
   261     Then we create the widgets associated with the painter paths' fill
       
   262     rule.
       
   263 
       
   264     There are two available fill rules in Qt: The Qt::OddEvenFill rule
       
   265     determine whether a point is inside the shape by drawing a
       
   266     horizontal line from the point to a location outside the shape,
       
   267     and count the number of intersections. If the number of
       
   268     intersections is an odd number, the point is inside the
       
   269     shape. This rule is the default.
       
   270 
       
   271     The Qt::WindingFill rule determine whether a point is inside the
       
   272     shape by drawing a horizontal line from the point to a location
       
   273     outside the shape. Then it determines whether the direction of the
       
   274     line at each intersection point is up or down. The winding number
       
   275     is determined by summing the direction of each intersection. If
       
   276     the number is non zero, the point is inside the shape.
       
   277 
       
   278     The Qt::WindingFill rule can in most cases be considered as the
       
   279     intersection of closed shapes.
       
   280 
       
   281     \snippet examples/painting/painterpaths/window.cpp 12
       
   282 
       
   283     We also create the other widgets associated with the filling, the
       
   284     pen and the rotation angle.
       
   285 
       
   286     \snippet examples/painting/painterpaths/window.cpp 16
       
   287 
       
   288     We connect the comboboxes \l {QComboBox::activated()}{activated()}
       
   289     signals to the associated slots in the \c Window class, while we
       
   290     connect the spin boxes \l
       
   291     {QSpinBox::valueChanged()}{valueChanged()} signal directly to the
       
   292     \c RenderArea widget's respective slots.
       
   293 
       
   294     \snippet examples/painting/painterpaths/window.cpp 17
       
   295 
       
   296     We add the \c RenderArea widgets to a separate layout which we
       
   297     then add to the main layout along with the rest of the widgets.
       
   298 
       
   299     \snippet examples/painting/painterpaths/window.cpp 18
       
   300 
       
   301     Finally, we initialize the \c RenderArea widgets by calling the \c
       
   302     fillRuleChanged(), \c fillGradientChanged() and \c
       
   303     penColorChanged() slots, and we set the inital pen width and
       
   304     window title.
       
   305 
       
   306     \snippet examples/painting/painterpaths/window.cpp 19
       
   307     \codeline
       
   308     \snippet examples/painting/painterpaths/window.cpp 20
       
   309     \codeline
       
   310     \snippet examples/painting/painterpaths/window.cpp 21
       
   311 
       
   312     The private slots are implemented to retrieve the new value, or
       
   313     values, from the associated comboboxes and update the RenderArea
       
   314     widgets.
       
   315 
       
   316     First we determine the new value, or values, using the private \c
       
   317     currentItemData() function and the qvariant_cast() template
       
   318     function. Then we call the associated slot for each of the \c
       
   319     RenderArea widgets to update the painter paths.
       
   320 
       
   321     \snippet examples/painting/painterpaths/window.cpp 22
       
   322 
       
   323     The \c populateWithColors() function populates the given combobox
       
   324     with items corresponding to the color names Qt knows about
       
   325     provided by the static QColor::colorNames() function.
       
   326 
       
   327     \snippet examples/painting/painterpaths/window.cpp 23
       
   328 
       
   329     The \c currentItemData() function simply return the current item
       
   330     of the given combobox.
       
   331 
       
   332     \section1 RenderArea Class Definition
       
   333 
       
   334     The \c RenderArea class inherits QWidget, and is a custom widget
       
   335     displaying a single painter path.
       
   336 
       
   337     \snippet examples/painting/painterpaths/renderarea.h 0
       
   338 
       
   339     We declare several public slots updating the \c RenderArea
       
   340     widget's associated painter path. In addition we reimplement the
       
   341     QWidget::minimumSizeHint() and QWidget::sizeHint() functions to
       
   342     give the \c RenderArea widget a reasonable size within our
       
   343     application, and we reimplement the QWidget::paintEvent() event
       
   344     handler to draw its painter path.
       
   345 
       
   346     \snippet examples/painting/painterpaths/renderarea.h 1
       
   347 
       
   348     Each instance of the \c RenderArea class has a QPainterPath, a
       
   349     couple of fill colors, a pen width, a pen color and a rotation
       
   350     angle.
       
   351 
       
   352     \section1 RenderArea Class Implementation
       
   353 
       
   354     The constructor takes a QPainterPath as argument (in addition to
       
   355     the optional QWidget parent):
       
   356 
       
   357     \snippet examples/painting/painterpaths/renderarea.cpp 0
       
   358 
       
   359     In the constructor we initialize the \c RenderArea widget with the
       
   360     QPainterPath parameter as well as initializing the pen width and
       
   361     rotation angle. We also set the widgets \l
       
   362     {QWidget::backgroundRole()}{background role}; QPalette::Base is
       
   363     typically white.
       
   364 
       
   365     \snippet examples/painting/painterpaths/renderarea.cpp 1
       
   366     \codeline
       
   367     \snippet examples/painting/painterpaths/renderarea.cpp 2
       
   368 
       
   369     Then we reimplement the QWidget::minimumSizeHint() and
       
   370     QWidget::sizeHint() functions to give the \c RenderArea widget a
       
   371     reasonable size within our application.
       
   372 
       
   373     \snippet examples/painting/painterpaths/renderarea.cpp 3
       
   374     \codeline
       
   375     \snippet examples/painting/painterpaths/renderarea.cpp 4
       
   376     \codeline
       
   377     \snippet examples/painting/painterpaths/renderarea.cpp 5
       
   378     \codeline
       
   379     \snippet examples/painting/painterpaths/renderarea.cpp 6
       
   380     \codeline
       
   381     \snippet examples/painting/painterpaths/renderarea.cpp 7
       
   382 
       
   383     The various public slots updates the \c RenderArea widget's
       
   384     painter path by setting the associated property and make a call to
       
   385     the QWidget::update() function, forcing a repaint of the widget
       
   386     with the new rendering preferences.
       
   387 
       
   388     The QWidget::update() slot does not cause an immediate repaint;
       
   389     instead it schedules a paint event for processing when Qt returns
       
   390     to the main event loop.
       
   391 
       
   392     \snippet examples/painting/painterpaths/renderarea.cpp 8
       
   393 
       
   394     A paint event is a request to repaint all or parts of the
       
   395     widget. The paintEvent() function is an event handler that can be
       
   396     reimplemented to receive the widget's paint events. We reimplement
       
   397     the event handler to render the \c RenderArea widget's painter
       
   398     path.
       
   399 
       
   400     First, we create a QPainter for the \c RenderArea instance, and
       
   401     set the painter's render hints. The QPainter::RenderHints are used
       
   402     to specify flags to QPainter that may, or may not, be respected by
       
   403     any given engine. QPainter::Antialiasing indicates that the engine
       
   404     should anti-alias the edges of primitives if possible, i.e. put
       
   405     additional pixels around the original ones to smooth the edges.
       
   406 
       
   407     \snippet examples/painting/painterpaths/renderarea.cpp 9
       
   408 
       
   409     Then we scale the QPainter's coordinate system to ensure that the
       
   410     painter path is rendered in the right size, i.e that it grows with
       
   411     the \c RenderArea widget when the application is resized. When we
       
   412     constructed the various painter paths, they were all rnedered
       
   413     within a square with a 100 pixel width wich is equivalent to \c
       
   414     RenderArea::sizeHint(). The QPainter::scale() function scales the
       
   415     coordinate system by the \c RenderArea widget's \e current width
       
   416     and height divided by 100.
       
   417 
       
   418     Now, when we are sure that the painter path has the right size, we
       
   419     can translate the coordinate system to make the painter path
       
   420     rotate around the \c RenderArea widget's center. After we have
       
   421     performed the rotation, we must remember to translate the
       
   422     coordinate system back again.
       
   423 
       
   424     \snippet examples/painting/painterpaths/renderarea.cpp 10
       
   425 
       
   426     Then we set the QPainter's pen with the instance's rendering
       
   427     preferences. We create a QLinearGradient and set its colors
       
   428     corresponding to the \c RenderArea widget's fill colors. Finally,
       
   429     we set the QPainter's brush (the gradient is automatically
       
   430     converted into a QBrush), and draw the \c RenderArea widget's
       
   431     painter path using the QPainter::drawPath() function.
       
   432 */