doc/src/examples/basicdrawing.qdoc
branchRCL_3
changeset 8 3f74d0d4af4c
equal deleted inserted replaced
6:dee5afe5301f 8: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/basicdrawing
       
    44     \title Basic Drawing Example
       
    45 
       
    46     The Basic Drawing example shows how to display basic graphics
       
    47     primitives in a variety of styles using the QPainter class.
       
    48 
       
    49     QPainter performs low-level painting on widgets and other paint
       
    50     devices. The class can draw everything from simple lines to
       
    51     complex shapes like pies and chords. It can also draw aligned text
       
    52     and pixmaps. Normally, it draws in a "natural" coordinate system,
       
    53     but it can in addition do view and world transformation.
       
    54 
       
    55     \image basicdrawing-example.png
       
    56 
       
    57     The example provides a render area, displaying the currently
       
    58     active shape, and lets the user manipulate the rendered shape and
       
    59     its appearance using the QPainter parameters: The user can change
       
    60     the active shape (\gui Shape), and modify the QPainter's pen (\gui
       
    61     {Pen Width}, \gui {Pen Style}, \gui {Pen Cap}, \gui {Pen Join}),
       
    62     brush (\gui {Brush Style}) and render hints (\gui
       
    63     Antialiasing). In addition the user can rotate a shape (\gui
       
    64     Transformations); behind the scenes we use QPainter's ability to
       
    65     manipulate the coordinate system to perform the rotation.
       
    66 
       
    67     The Basic Drawing example consists of two classes:
       
    68 
       
    69     \list
       
    70     \o \c RenderArea is a custom widget that renders multiple
       
    71        copies of the currently active shape.
       
    72     \o \c Window is the application's main window displaying a
       
    73        \c RenderArea widget in addition to several parameter widgets.
       
    74     \endlist
       
    75 
       
    76     First we will review the \c Window class, then we will take a
       
    77     look at the \c RenderArea class.
       
    78 
       
    79     \section1 Window Class Definition
       
    80 
       
    81     The Window class inherits QWidget, and is the application's main
       
    82     window displaying a \c RenderArea widget in addition to several
       
    83     parameter widgets.
       
    84 
       
    85     \snippet examples/painting/basicdrawing/window.h 0
       
    86 
       
    87     We declare the various widgets, and three private slots updating
       
    88     the \c RenderArea widget: The \c shapeChanged() slot updates the
       
    89     \c RenderArea widget when the user changes the currently active
       
    90     shape. We call the \c penChanged() slot when either of the
       
    91     QPainter's pen parameters changes. And the \c brushChanged() slot
       
    92     updates the \c RenderArea widget when the user changes the
       
    93     painter's brush style.
       
    94 
       
    95     \section1 Window Class Implementation
       
    96 
       
    97     In the constructor we create and initialize the various widgets
       
    98     appearing in the main application window.
       
    99 
       
   100     \snippet examples/painting/basicdrawing/window.cpp 1
       
   101 
       
   102     First we create the \c RenderArea widget that will render the
       
   103     currently active shape. Then we create the \gui Shape combobox,
       
   104     and add the associated items (i.e. the different shapes a QPainter
       
   105     can draw).
       
   106 
       
   107     \snippet examples/painting/basicdrawing/window.cpp 2
       
   108 
       
   109     QPainter's pen is a QPen object; the QPen class defines how a
       
   110     painter should draw lines and outlines of shapes. A pen has
       
   111     several properties: Width, style, cap and join.
       
   112 
       
   113     A pen's width can be \e zero or greater, but the most common width
       
   114     is zero. Note that this doesn't mean 0 pixels, but implies that
       
   115     the shape is drawn as smoothly as possible although perhaps not
       
   116     mathematically correct.
       
   117 
       
   118     We create a QSpinBox for the \gui {Pen Width} parameter.
       
   119 
       
   120     \snippet examples/painting/basicdrawing/window.cpp 3
       
   121 
       
   122     The pen style defines the line type. The default style is solid
       
   123     (Qt::SolidLine). Setting the style to none (Qt::NoPen) tells the
       
   124     painter to not draw lines or outlines.  The pen cap defines how
       
   125     the end points of lines are drawn.  And the pen join defines how
       
   126     two lines join when multiple connected lines are drawn. The cap
       
   127     and join only apply to lines with a width of 1 pixel or greater.
       
   128 
       
   129     We create \l {QComboBox}es for each of the \gui {Pen Style}, \gui
       
   130     {Pen Cap} and \gui {Pen Join} parameters, and adds the associated
       
   131     items (i.e the values of the Qt::PenStyle, Qt::PenCapStyle and
       
   132     Qt::PenJoinStyle enums respectively).
       
   133 
       
   134     \snippet examples/painting/basicdrawing/window.cpp 4
       
   135 
       
   136     The QBrush class defines the fill pattern of shapes drawn by a
       
   137     QPainter. The default brush style is Qt::NoBrush. This style tells
       
   138     the painter to not fill shapes. The standard style for filling is
       
   139     Qt::SolidPattern.
       
   140 
       
   141     We create a QComboBox for the \gui {Brush Style} parameter, and add
       
   142     the associated items (i.e. the values of the Qt::BrushStyle enum).
       
   143 
       
   144     \snippet examples/painting/basicdrawing/window.cpp 5
       
   145     \snippet examples/painting/basicdrawing/window.cpp 6
       
   146 
       
   147     Antialiasing is a feature that "smoothes" the pixels to create
       
   148     more even and less jagged lines, and can be applied using
       
   149     QPainter's render hints. QPainter::RenderHints are used to specify
       
   150     flags to QPainter that may or may not be respected by any given
       
   151     engine.
       
   152 
       
   153     We simply create a QCheckBox for the \gui Antialiasing option.
       
   154 
       
   155     \snippet examples/painting/basicdrawing/window.cpp 7
       
   156 
       
   157     The \gui Transformations option implies a manipulation of the
       
   158     coordinate system that will appear as if the rendered shape is
       
   159     rotated in three dimensions.
       
   160 
       
   161     We use the QPainter::translate(), QPainter::rotate() and
       
   162     QPainter::scale() functions to implement this feature represented
       
   163     in the main application window by a simple QCheckBox.
       
   164 
       
   165     \snippet examples/painting/basicdrawing/window.cpp 8
       
   166 
       
   167     Then we connect the parameter widgets with their associated slots
       
   168     using the static QObject::connect() function, ensuring that the \c
       
   169     RenderArea widget is updated whenever the user changes the shape,
       
   170     or any of the other parameters.
       
   171 
       
   172     \snippet examples/painting/basicdrawing/window.cpp 9
       
   173     \snippet examples/painting/basicdrawing/window.cpp 10
       
   174 
       
   175     Finally, we add the various widgets to a layout, and call the \c
       
   176     shapeChanged(), \c penChanged(), and \c brushChanged() slots to
       
   177     initialize the application. We also turn on antialiasing.
       
   178 
       
   179     \snippet examples/painting/basicdrawing/window.cpp 11
       
   180 
       
   181     The \c shapeChanged() slot is called whenever the user changes the
       
   182     currently active shape.
       
   183 
       
   184     First we retrieve the shape the user has chosen using the
       
   185     QComboBox::itemData() function. This function returns the data for
       
   186     the given role in the given index in the combobox. We use
       
   187     QComboBox::currentIndex() to retrieve the index of the shape, and
       
   188     the role is defined by the Qt::ItemDataRole enum; \c IdRole is an
       
   189     alias for Qt::UserRole.
       
   190 
       
   191     Note that Qt::UserRole is only the first role that can be used for
       
   192     application-specific purposes. If you need to store different data
       
   193     in the same index, you can use different roles by simply
       
   194     incrementing the value of Qt::UserRole, for example: 'Qt::UserRole
       
   195     + 1' and 'Qt::UserRole + 2'. However, it is a good programming
       
   196     practice to give each role their own name: 'myFirstRole =
       
   197     Qt::UserRole + 1' and 'mySecondRole = Qt::UserRole + 2'. Even
       
   198     though we only need a single role in this particular example, we
       
   199     add the following line of code to the beginning of the \c
       
   200     window.cpp file.
       
   201 
       
   202     \snippet examples/painting/basicdrawing/window.cpp 0
       
   203 
       
   204     The QComboBox::itemData() function returns the data as a QVariant,
       
   205     so we need to cast the data to \c RenderArea::Shape. If there is
       
   206     no data for the given role, the function returns
       
   207     QVariant::Invalid.
       
   208 
       
   209     In the end we call the \c RenderArea::setShape() slot to update
       
   210     the \c RenderArea widget.
       
   211 
       
   212     \snippet examples/painting/basicdrawing/window.cpp 12
       
   213 
       
   214     We call the \c penChanged() slot whenever the user changes any of
       
   215     the pen parameters. Again we use the QComboBox::itemData()
       
   216     function to retrieve the parameters, and then we call the \c
       
   217     RenderArea::setPen() slot to update the \c RenderArea widget.
       
   218 
       
   219     \snippet examples/painting/basicdrawing/window.cpp 13
       
   220 
       
   221     The brushChanged() slot is called whenever the user changes the
       
   222     brush parameter which we retrieve using the QComboBox::itemData()
       
   223     function as before.
       
   224 
       
   225     \snippet examples/painting/basicdrawing/window.cpp 14
       
   226 
       
   227     If the brush parameter is a gradient fill, special actions are
       
   228     required.
       
   229 
       
   230     The QGradient class is used in combination with QBrush to specify
       
   231     gradient fills. Qt currently supports three types of gradient
       
   232     fills: linear, radial and conical. Each of these is represented by
       
   233     a subclass of QGradient: QLinearGradient, QRadialGradient and
       
   234     QConicalGradient.
       
   235 
       
   236     So if the brush style is Qt::LinearGradientPattern, we first
       
   237     create a QLinearGradient object with interpolation area between
       
   238     the coordinates passed as arguments to the constructor. The
       
   239     positions are specified using logical coordinates. Then we set the
       
   240     gradient's colors using the QGradient::setColorAt() function. The
       
   241     colors is defined using stop points which are composed by a
       
   242     position (between 0 and 1) and a QColor. The set of stop points
       
   243     describes how the gradient area should be filled. A gradient can
       
   244     have an arbitrary number of stop points.
       
   245 
       
   246     In the end we call \c RenderArea::setBrush() slot to update the \c
       
   247     RenderArea widget's brush with the QLinearGradient object.
       
   248 
       
   249     \snippet examples/painting/basicdrawing/window.cpp 15
       
   250 
       
   251     A similar pattern of actions, as the one used for QLinearGradient,
       
   252     is used in the cases of Qt::RadialGradientPattern and
       
   253     Qt::ConicalGradientPattern.
       
   254 
       
   255     The only difference is the arguments passed to the constructor:
       
   256     Regarding the QRadialGradient constructor the first argument is
       
   257     the center, and the second the radial gradient's radius. The third
       
   258     argument is optional, but can be used to define the focal point of
       
   259     the gradient inside the circle (the default focal point is the
       
   260     circle center).  Regarding the QConicalGradient constructor, the
       
   261     first argument specifies the center of the conical, and the second
       
   262     specifies the start angle of the interpolation.
       
   263 
       
   264     \snippet examples/painting/basicdrawing/window.cpp 16
       
   265 
       
   266     If the brush style is Qt::TexturePattern we create a QBrush from a
       
   267     QPixmap. Then we call \c RenderArea::setBrush() slot to update the
       
   268     \c RenderArea widget with the newly created brush.
       
   269 
       
   270     \snippet examples/painting/basicdrawing/window.cpp 17
       
   271 
       
   272     Otherwise we simply create a brush with the given style and a
       
   273     green color, and then call \c RenderArea::setBrush() slot to
       
   274     update the \c RenderArea widget with the newly created brush.
       
   275 
       
   276     \section1 RenderArea Class Definition
       
   277 
       
   278     The \c RenderArea class inherits QWidget, and renders multiple
       
   279     copies of the currently active shape using a QPainter.
       
   280 
       
   281     \snippet examples/painting/basicdrawing/renderarea.h 0
       
   282 
       
   283     First we define a public \c Shape enum to hold the different
       
   284     shapes that can be rendered by the widget (i.e the shapes that can
       
   285     be rendered by a QPainter). Then we reimplement the constructor as
       
   286     well as two of QWidget's public functions: \l
       
   287     {QWidget::minimumSizeHint()}{minimumSizeHint()} and \l
       
   288     {QWidget::sizeHint()}{sizeHint()}.
       
   289 
       
   290     We also reimplement the QWidget::paintEvent() function to be able
       
   291     to draw the currently active shape according to the specified
       
   292     parameters.
       
   293 
       
   294     We declare several private slots: The \c setShape() slot changes
       
   295     the \c RenderArea's shape, the \c setPen() and \c setBrush() slots
       
   296     modify the widget's pen and brush, and the \c setAntialiased() and
       
   297     \c setTransformed() slots modify the widget's respective
       
   298     properties.
       
   299 
       
   300     \section1 RenderArea Class Implementation
       
   301 
       
   302     In the constructor we initialize some of the widget's variables.
       
   303 
       
   304     \snippet examples/painting/basicdrawing/renderarea.cpp 0
       
   305 
       
   306     We set its shape to be a \gui Polygon, its antialiased property to
       
   307     be false and we load an image into the widget's pixmap
       
   308     variable. In the end we set the widget's background role, defining
       
   309     the brush from the widget's \l {QWidget::palette}{palette} that
       
   310     will be used to render the background. QPalette::Base is typically
       
   311     white.
       
   312 
       
   313     \snippet examples/painting/basicdrawing/renderarea.cpp 2
       
   314 
       
   315     The \c RenderArea inherits QWidget's \l
       
   316     {QWidget::sizeHint()}{sizeHint} property holding the recommended
       
   317     size for the widget. If the value of this property is an invalid
       
   318     size, no size is recommended.
       
   319 
       
   320     The default implementation of the QWidget::sizeHint() function
       
   321     returns an invalid size if there is no layout for the widget, and
       
   322     returns the layout's preferred size otherwise.
       
   323 
       
   324     Our reimplementation of the function returns a QSize with a 400
       
   325     pixels width and a 200 pixels height.
       
   326 
       
   327     \snippet examples/painting/basicdrawing/renderarea.cpp 1
       
   328 
       
   329     \c RenderArea also inherits QWidget's
       
   330     \l{QWidget::minimumSizeHint()}{minimumSizeHint} property holding
       
   331     the recommended minimum size for the widget. Again, if the value
       
   332     of this property is an invalid size, no size is recommended.
       
   333 
       
   334     The default implementation of QWidget::minimumSizeHint() returns
       
   335     an invalid size if there is no layout for the widget, and returns
       
   336     the layout's minimum size otherwise.
       
   337 
       
   338     Our reimplementation of the function returns a QSize with a 100
       
   339     pixels width and a 100 pixels height.
       
   340 
       
   341     \snippet examples/painting/basicdrawing/renderarea.cpp 3
       
   342     \codeline
       
   343     \snippet examples/painting/basicdrawing/renderarea.cpp 4
       
   344     \codeline
       
   345     \snippet examples/painting/basicdrawing/renderarea.cpp 5
       
   346 
       
   347     The public \c setShape(), \c setPen() and \c setBrush() slots are
       
   348     called whenever we want to modify a \c RenderArea widget's shape,
       
   349     pen or brush. We set the shape, pen or brush according to the
       
   350     slot parameter, and call QWidget::update() to make the changes
       
   351     visible in the \c RenderArea widget.
       
   352 
       
   353     The QWidget::update() slot does not cause an immediate
       
   354     repaint; instead it schedules a paint event for processing when Qt
       
   355     returns to the main event loop.
       
   356 
       
   357     \snippet examples/painting/basicdrawing/renderarea.cpp 6
       
   358     \codeline
       
   359     \snippet examples/painting/basicdrawing/renderarea.cpp 7
       
   360 
       
   361     With the \c setAntialiased() and \c setTransformed() slots we
       
   362     change the state of the properties according to the slot
       
   363     parameter, and call the QWidget::update() slot to make the changes
       
   364     visible in the \c RenderArea widget.
       
   365 
       
   366     \snippet examples/painting/basicdrawing/renderarea.cpp 8
       
   367 
       
   368     Then we reimplement the QWidget::paintEvent() function. The first
       
   369     thing we do is to create the graphical objects we will need to
       
   370     draw the various shapes.
       
   371 
       
   372     We create a vector of four \l {QPoint}s. We use this vector to
       
   373     render the \gui Points, \gui Polyline and \gui Polygon
       
   374     shapes. Then we create a QRect, defining a rectangle in the plane,
       
   375     which we use as the bounding rectangle for all the shapes excluding
       
   376     the \gui Path and the \gui Pixmap.
       
   377 
       
   378     We also create a QPainterPath. The QPainterPath class provides a
       
   379     container for painting operations, enabling graphical shapes to be
       
   380     constructed and reused. A painter path is an object composed of a
       
   381     number of graphical building blocks, such as rectangles, ellipses,
       
   382     lines, and curves. For more information about the QPainterPath
       
   383     class, see the \l {painting/painterpaths}{Painter Paths}
       
   384     example. In this example, we create a painter path composed of one
       
   385     straight line and a Bezier curve.
       
   386 
       
   387     In addition we define a start angle and an arc length that we will
       
   388     use when drawing the \gui Arc, \gui Chord and \gui Pie shapes.
       
   389 
       
   390     \snippet examples/painting/basicdrawing/renderarea.cpp 9
       
   391 
       
   392     We create a QPainter for the \c RenderArea widget, and set the
       
   393     painters pen and brush according to the \c RenderArea's pen and
       
   394     brush. If the \gui Antialiasing parameter option is checked, we
       
   395     also set the painter's render hints. QPainter::Antialiasing
       
   396     indicates that the engine should antialias edges of primitives if
       
   397     possible.
       
   398 
       
   399     \snippet examples/painting/basicdrawing/renderarea.cpp 10
       
   400 
       
   401     Finally, we render the multiple copies of the \c RenderArea's
       
   402     shape. The number of copies is depending on the size of the \c
       
   403     RenderArea widget, and we calculate their positions using two \c
       
   404     for loops and the widgets height and width.
       
   405 
       
   406     For each copy we first save the current painter state (pushes the
       
   407     state onto a stack). Then we translate the coordinate system,
       
   408     using the QPainter::translate() function, to the position
       
   409     determined by the variables of the \c for loops. If we omit this
       
   410     translation of the coordinate system all the copies of the shape
       
   411     will be rendered on top of each other in the top left cormer of
       
   412     the \c RenderArea widget.
       
   413 
       
   414     \snippet examples/painting/basicdrawing/renderarea.cpp 11
       
   415 
       
   416     If the \gui Transformations parameter option is checked, we do an
       
   417     additional translation of the coordinate system before we rotate
       
   418     the coordinate system 60 degrees clockwise using the
       
   419     QPainter::rotate() function and scale it down in size using the
       
   420     QPainter::scale() function. In the end we translate the coordinate
       
   421     system back to where it was before we rotated and scaled it.
       
   422 
       
   423     Now, when rendering the shape, it will appear as if it was rotated
       
   424     in three dimensions.
       
   425 
       
   426     \snippet examples/painting/basicdrawing/renderarea.cpp 12
       
   427 
       
   428     Next, we identify the \c RenderArea's shape, and render it using
       
   429     the associated QPainter drawing function:
       
   430 
       
   431     \list
       
   432         \o QPainter::drawLine(),
       
   433         \o QPainter::drawPoints(),
       
   434         \o QPainter::drawPolyline(),
       
   435         \o QPainter::drawPolygon(),
       
   436         \o QPainter::drawRect(),
       
   437         \o QPainter::drawRoundedRect(),
       
   438         \o QPainter::drawEllipse(),
       
   439         \o QPainter::drawArc(),
       
   440         \o QPainter::drawChord(),
       
   441         \o QPainter::drawPie(),
       
   442         \o QPainter::drawPath(),
       
   443         \o QPainter::drawText() or
       
   444         \o QPainter::drawPixmap()
       
   445     \endlist
       
   446 
       
   447     Before we started rendering, we saved the current painter state
       
   448     (pushes the state onto a stack). The rationale for this is that we
       
   449     calculate each shape copy's position relative to the same point in
       
   450     the coordinate system. When translating the coordinate system, we
       
   451     lose the knowledge of this point unless we save the current
       
   452     painter state \e before we start the translating process.
       
   453 
       
   454     \snippet examples/painting/basicdrawing/renderarea.cpp 13
       
   455 
       
   456     Then, when we are finished rendering a copy of the shape we can
       
   457     restore the original painter state, with its associated coordinate
       
   458     system, using the QPainter::restore() function. In this way we
       
   459     ensure that the next shape copy will be rendered in the correct
       
   460     position.
       
   461 
       
   462     We could translate the coordinate system back using
       
   463     QPainter::translate() instead of saving the painter state. But
       
   464     since we in addition to translating the coordinate system (when
       
   465     the \gui Transformation parameter option is checked) both rotate
       
   466     and scale the coordinate system, the easiest solution is to save
       
   467     the current painter state.
       
   468 */