diff -r 41300fa6a67c -r f7bc934e204c doc/src/examples/painterpaths.qdoc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/src/examples/painterpaths.qdoc Wed Mar 31 11:06:36 2010 +0300 @@ -0,0 +1,432 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example painting/painterpaths + \title Painter Paths Example + + The Painter Paths example shows how painter paths can be used to + build complex shapes for rendering. + + \image painterpaths-example.png + + The QPainterPath class provides a container for painting + operations, enabling graphical shapes to be constructed and + reused. + + A painter path is an object composed of a number of graphical + building blocks (such as rectangles, ellipses, lines, and curves), + and can be used for filling, outlining, and clipping. The main + advantage of painter paths over normal drawing operations is that + complex shapes only need to be created once, but they can be drawn + many times using only calls to QPainter::drawPath(). + + The example consists of two classes: + + \list + \o The \c RenderArea class which is a custom widget displaying + a single painter path. + \o The \c Window class which is the applications main window + displaying several \c RenderArea widgets, and allowing the user + to manipulate the painter paths' filling, pen, color + and rotation angle. + \endlist + + First we will review the \c Window class, then we will take a look + at the \c RenderArea class. + + \section1 Window Class Definition + + The \c Window class inherits QWidget, and is the applications main + window displaying several \c RenderArea widgets, and allowing the + user to manipulate the painter paths' filling, pen, color and + rotation angle. + + \snippet examples/painting/painterpaths/window.h 0 + + We declare three private slots to respond to user input regarding + filling and color: \c fillRuleChanged(), \c fillGradientChanged() + and \c penColorChanged(). + + When the user changes the pen width and the rotation angle, the + new value is passed directly on to the \c RenderArea widgets using + the QSpinBox::valueChanged() signal. The reason why we must + implement slots to update the filling and color, is that QComboBox + doesn't provide a similar signal passing the new value as + argument; so we need to retrieve the new value, or values, before + we can update the \c RenderArea widgets. + + \snippet examples/painting/painterpaths/window.h 1 + + We also declare a couple of private convenience functions: \c + populateWithColors() populates a given QComboBox with items + corresponding to the color names Qt knows about, and \c + currentItemData() returns the current item for a given QComboBox. + + \snippet examples/painting/painterpaths/window.h 2 + + Then we declare the various components of the main window + widget. We also declare a convenience constant specifying the + number of \c RenderArea widgets. + + \section1 Window Class Implementation + + In the implementation of the \c Window class we first declare the + constant \c Pi with six significant figures: + + \snippet examples/painting/painterpaths/window.cpp 0 + + In the constructor, we then define the various painter paths and + create corresponding \c RenderArea widgets which will render the + graphical shapes: + + \snippet examples/painting/painterpaths/window.cpp 1 + + We construct a rectangle with sharp corners using the + QPainterPath::moveTo() and QPainterPath::lineTo() + functions. + + QPainterPath::moveTo() moves the current point to the point passed + as argument. A painter path is an object composed of a number of + graphical building blocks, i.e. subpaths. Moving the current point + will also start a new subpath (implicitly closing the previously + current path when the new one is started). The + QPainterPath::lineTo() function adds a straight line from the + current point to the given end point. After the line is drawn, the + current point is updated to be at the end point of the line. + + We first move the current point starting a new subpath, and we + draw three of the rectangle's sides. Then we call the + QPainterPath::closeSubpath() function which draws a line to the + beginning of the current subpath. A new subpath is automatically + begun when the current subpath is closed. The current point of the + new path is (0, 0). We could also have called + QPainterPath::lineTo() to draw the last line as well, and then + explicitly start a new subpath using the QPainterPath::moveTo() + function. + + QPainterPath also provide the QPainterPath::addRect() convenience + function, which adds a given rectangle to the path as a closed + subpath. The rectangle is added as a clockwise set of lines. The + painter path's current position after the rect has been added is + at the top-left corner of the rectangle. + + \snippet examples/painting/painterpaths/window.cpp 2 + + Then we construct a rectangle with rounded corners. As before, we + use the QPainterPath::moveTo() and QPainterPath::lineTo() + functions to draw the rectangle's sides. To create the rounded + corners we use the QPainterPath::arcTo() function. + + QPainterPath::arcTo() creates an arc that occupies the given + rectangle (specified by a QRect or the rectangle's coordinates), + beginning at the given start angle and extending the given degrees + counter-clockwise. Angles are specified in degrees. Clockwise arcs + can be specified using negative angles. The function connects the + current point to the starting point of the arc if they are not + already connected. + + \snippet examples/painting/painterpaths/window.cpp 3 + + We also use the QPainterPath::arcTo() function to construct the + ellipse path. First we move the current point starting a new + path. Then we call QPainterPath::arcTo() with starting angle 0.0 + and 360.0 degrees as the last argument, creating an ellipse. + + Again, QPainterPath provides a convenience function ( + QPainterPath::addEllipse()) which creates an ellipse within a + given bounding rectangle and adds it to the painter path. If the + current subpath is closed, a new subpath is started. The ellipse + is composed of a clockwise curve, starting and finishing at zero + degrees (the 3 o'clock position). + + \snippet examples/painting/painterpaths/window.cpp 4 + + When constructing the pie chart path we continue to use a + combination of the mentioned functions: First we move the current + point, starting a new subpath. Then we create a line from the + center of the chart to the arc, and the arc itself. When we close + the subpath, we implicitly construct the last line back to the + center of the chart. + + \snippet examples/painting/painterpaths/window.cpp 5 + + Constructing a polygon is equivalent to constructing a rectangle. + + QPainterPath also provide the QPainterPath::addPolygon() + convenience function which adds the given polygon to the path as a + new subpath. Current position after the polygon has been added is + the last point in polygon. + + \snippet examples/painting/painterpaths/window.cpp 6 + + Then we create a path consisting of a group of subpaths: First we + move the current point, and create a circle using the + QPainterPath::arcTo() function with starting angle 0.0, and 360 + degrees as the last argument, as we did when we created the + ellipse path. Then we move the current point again, starting a + new subpath, and construct three sides of a square using the + QPainterPath::lineTo() function. + + Now, when we call the QPainterPath::closeSubpath() fucntion the + last side is created. Remember that the + QPainterPath::closeSubpath() function draws a line to the + beginning of the \e current subpath, i.e the square. + + QPainterPath provide a convenience function, + QPainterPath::addPath() which adds a given path to the path that + calls the function. + + \snippet examples/painting/painterpaths/window.cpp 7 + + When creating the text path, we first create the font. Then we set + the font's style strategy which tells the font matching algorithm + what type of fonts should be used to find an appropriate default + family. QFont::ForceOutline forces the use of outline fonts. + + To construct the text, we use the QPainterPath::addText() function + which adds the given text to the path as a set of closed subpaths + created from the supplied font. The subpaths are positioned so + that the left end of the text's baseline lies at the specified + point. + + \snippet examples/painting/painterpaths/window.cpp 8 + + To create the Bezier path, we use the QPainterPath::cubicTo() + function which adds a Bezier curve between the current point and + the given end point with the given control point. After the curve + is added, the current point is updated to be at the end point of + the curve. + + In this case we omit to close the subpath so that we only have a + simple curve. But there is still a logical line from the curve's + endpoint back to the beginning of the subpath; it becomes visible + when filling the path as can be seen in the applications main + window. + + \snippet examples/painting/painterpaths/window.cpp 9 + + The final path that we construct shows that you can use + QPainterPath to construct rather complex shapes using only the + previous mentioned QPainterPath::moveTo(), QPainterPath::lineTo() + and QPainterPath::closeSubpath() functions. + + \snippet examples/painting/painterpaths/window.cpp 10 + + Now that we have created all the painter paths that we need, we + create a corresponding \c RenderArea widget for each. In the end, + we make sure that the number of render areas is correct using the + Q_ASSERT() macro. + + \snippet examples/painting/painterpaths/window.cpp 11 + + Then we create the widgets associated with the painter paths' fill + rule. + + There are two available fill rules in Qt: The Qt::OddEvenFill rule + determine whether a point is inside the shape by drawing a + horizontal line from the point to a location outside the shape, + and count the number of intersections. If the number of + intersections is an odd number, the point is inside the + shape. This rule is the default. + + The Qt::WindingFill rule determine whether a point is inside the + shape by drawing a horizontal line from the point to a location + outside the shape. Then it determines whether the direction of the + line at each intersection point is up or down. The winding number + is determined by summing the direction of each intersection. If + the number is non zero, the point is inside the shape. + + The Qt::WindingFill rule can in most cases be considered as the + intersection of closed shapes. + + \snippet examples/painting/painterpaths/window.cpp 12 + + We also create the other widgets associated with the filling, the + pen and the rotation angle. + + \snippet examples/painting/painterpaths/window.cpp 16 + + We connect the comboboxes \l {QComboBox::activated()}{activated()} + signals to the associated slots in the \c Window class, while we + connect the spin boxes \l + {QSpinBox::valueChanged()}{valueChanged()} signal directly to the + \c RenderArea widget's respective slots. + + \snippet examples/painting/painterpaths/window.cpp 17 + + We add the \c RenderArea widgets to a separate layout which we + then add to the main layout along with the rest of the widgets. + + \snippet examples/painting/painterpaths/window.cpp 18 + + Finally, we initialize the \c RenderArea widgets by calling the \c + fillRuleChanged(), \c fillGradientChanged() and \c + penColorChanged() slots, and we set the inital pen width and + window title. + + \snippet examples/painting/painterpaths/window.cpp 19 + \codeline + \snippet examples/painting/painterpaths/window.cpp 20 + \codeline + \snippet examples/painting/painterpaths/window.cpp 21 + + The private slots are implemented to retrieve the new value, or + values, from the associated comboboxes and update the RenderArea + widgets. + + First we determine the new value, or values, using the private \c + currentItemData() function and the qvariant_cast() template + function. Then we call the associated slot for each of the \c + RenderArea widgets to update the painter paths. + + \snippet examples/painting/painterpaths/window.cpp 22 + + The \c populateWithColors() function populates the given combobox + with items corresponding to the color names Qt knows about + provided by the static QColor::colorNames() function. + + \snippet examples/painting/painterpaths/window.cpp 23 + + The \c currentItemData() function simply return the current item + of the given combobox. + + \section1 RenderArea Class Definition + + The \c RenderArea class inherits QWidget, and is a custom widget + displaying a single painter path. + + \snippet examples/painting/painterpaths/renderarea.h 0 + + We declare several public slots updating the \c RenderArea + widget's associated painter path. In addition we reimplement the + QWidget::minimumSizeHint() and QWidget::sizeHint() functions to + give the \c RenderArea widget a reasonable size within our + application, and we reimplement the QWidget::paintEvent() event + handler to draw its painter path. + + \snippet examples/painting/painterpaths/renderarea.h 1 + + Each instance of the \c RenderArea class has a QPainterPath, a + couple of fill colors, a pen width, a pen color and a rotation + angle. + + \section1 RenderArea Class Implementation + + The constructor takes a QPainterPath as argument (in addition to + the optional QWidget parent): + + \snippet examples/painting/painterpaths/renderarea.cpp 0 + + In the constructor we initialize the \c RenderArea widget with the + QPainterPath parameter as well as initializing the pen width and + rotation angle. We also set the widgets \l + {QWidget::backgroundRole()}{background role}; QPalette::Base is + typically white. + + \snippet examples/painting/painterpaths/renderarea.cpp 1 + \codeline + \snippet examples/painting/painterpaths/renderarea.cpp 2 + + Then we reimplement the QWidget::minimumSizeHint() and + QWidget::sizeHint() functions to give the \c RenderArea widget a + reasonable size within our application. + + \snippet examples/painting/painterpaths/renderarea.cpp 3 + \codeline + \snippet examples/painting/painterpaths/renderarea.cpp 4 + \codeline + \snippet examples/painting/painterpaths/renderarea.cpp 5 + \codeline + \snippet examples/painting/painterpaths/renderarea.cpp 6 + \codeline + \snippet examples/painting/painterpaths/renderarea.cpp 7 + + The various public slots updates the \c RenderArea widget's + painter path by setting the associated property and make a call to + the QWidget::update() function, forcing a repaint of the widget + with the new rendering preferences. + + The QWidget::update() slot does not cause an immediate repaint; + instead it schedules a paint event for processing when Qt returns + to the main event loop. + + \snippet examples/painting/painterpaths/renderarea.cpp 8 + + A paint event is a request to repaint all or parts of the + widget. The paintEvent() function is an event handler that can be + reimplemented to receive the widget's paint events. We reimplement + the event handler to render the \c RenderArea widget's painter + path. + + First, we create a QPainter for the \c RenderArea instance, and + set the painter's render hints. The QPainter::RenderHints are used + to specify flags to QPainter that may, or may not, be respected by + any given engine. QPainter::Antialiasing indicates that the engine + should anti-alias the edges of primitives if possible, i.e. put + additional pixels around the original ones to smooth the edges. + + \snippet examples/painting/painterpaths/renderarea.cpp 9 + + Then we scale the QPainter's coordinate system to ensure that the + painter path is rendered in the right size, i.e that it grows with + the \c RenderArea widget when the application is resized. When we + constructed the various painter paths, they were all rnedered + within a square with a 100 pixel width wich is equivalent to \c + RenderArea::sizeHint(). The QPainter::scale() function scales the + coordinate system by the \c RenderArea widget's \e current width + and height divided by 100. + + Now, when we are sure that the painter path has the right size, we + can translate the coordinate system to make the painter path + rotate around the \c RenderArea widget's center. After we have + performed the rotation, we must remember to translate the + coordinate system back again. + + \snippet examples/painting/painterpaths/renderarea.cpp 10 + + Then we set the QPainter's pen with the instance's rendering + preferences. We create a QLinearGradient and set its colors + corresponding to the \c RenderArea widget's fill colors. Finally, + we set the QPainter's brush (the gradient is automatically + converted into a QBrush), and draw the \c RenderArea widget's + painter path using the QPainter::drawPath() function. +*/