| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the documentation of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:FDL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Free Documentation License Usage |
| ** 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. Please review the following information to ensure |
| ** the GNU Free Documentation License version 1.3 requirements |
| ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| /*! |
| \example painting/painterpaths |
| \title Painter Paths Example |
| \ingroup examples-painting |
| \brief The Painter Paths example shows how painter paths can be |
| used to beuild complex shapes for rendering. |
| |
| \brief 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 |
| \li The \c RenderArea class which is a custom widget displaying |
| a single painter path. |
| \li 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 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 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 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 \c Window constructor, we define the various painter paths |
| and create corresponding \c RenderArea widgets which will render |
| the graphical shapes: |
| |
| \snippet 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 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 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 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 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 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() function 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 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 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 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 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 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 painting/painterpaths/window.cpp 12 |
| |
| We also create the other widgets associated with the filling, the |
| pen and the rotation angle. |
| |
| \snippet 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 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 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 initial pen width and |
| window title. |
| |
| \snippet painting/painterpaths/window.cpp 19 |
| \codeline |
| \snippet painting/painterpaths/window.cpp 20 |
| \codeline |
| \snippet 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 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 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 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 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 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 painting/painterpaths/renderarea.cpp 1 |
| \codeline |
| \snippet 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 painting/painterpaths/renderarea.cpp 3 |
| \codeline |
| \snippet painting/painterpaths/renderarea.cpp 4 |
| \codeline |
| \snippet painting/painterpaths/renderarea.cpp 5 |
| \codeline |
| \snippet painting/painterpaths/renderarea.cpp 6 |
| \codeline |
| \snippet 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 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 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 which 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 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. |
| */ |