diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-12-12 14:54:50 +0100 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-12-14 20:06:32 +0100 |
commit | 33254fb41f29b510d3d74dbaab60f0a67ef56d46 (patch) | |
tree | f79f0857335ee41141e40c6924c2f60bb9f1ec27 | |
parent | 92b5992a29e6a5463200157ab9934fae9a3ec8cb (diff) |
Turn the "concentriccircles" example into snippets, update screenshot
The example has a lot of code and documentation, but in essence shows
how to use float-based QPainter APIs and how to set a render hint. That
is two lines of code, which we can show as snippets.
Update the screenshot of the example with a higher-resolution version.
Pick-to: 6.7 6.6
Fixes: QTBUG-119983
Change-Id: Iafcb813dff6ab8c269176f7994c95947ebf5e559
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
-rw-r--r-- | doc/src/images/concentriccircles-example.png | bin | 29623 -> 0 bytes | |||
-rw-r--r-- | examples/widgets/doc/src/concentriccircles.qdoc | 210 | ||||
-rw-r--r-- | examples/widgets/painting/CMakeLists.txt | 1 | ||||
-rw-r--r-- | examples/widgets/painting/concentriccircles/CMakeLists.txt | 38 | ||||
-rw-r--r-- | examples/widgets/painting/concentriccircles/circlewidget.cpp | 84 | ||||
-rw-r--r-- | examples/widgets/painting/concentriccircles/circlewidget.h | 36 | ||||
-rw-r--r-- | examples/widgets/painting/concentriccircles/concentriccircles.pro | 11 | ||||
-rw-r--r-- | examples/widgets/painting/concentriccircles/main.cpp | 14 | ||||
-rw-r--r-- | examples/widgets/painting/concentriccircles/window.cpp | 56 | ||||
-rw-r--r-- | examples/widgets/painting/concentriccircles/window.h | 33 | ||||
-rw-r--r-- | examples/widgets/painting/painting.pro | 1 | ||||
-rw-r--r-- | src/gui/doc/images/qpainter-concentriccircles.png | bin | 31294 -> 95529 bytes | |||
-rw-r--r-- | src/gui/doc/snippets/code/src_gui_painting_qpainter.cpp | 20 | ||||
-rw-r--r-- | src/gui/painting/qpainter.cpp | 24 | ||||
-rw-r--r-- | tests/auto/guiapplauncher/examples.txt | 1 |
15 files changed, 30 insertions, 499 deletions
diff --git a/doc/src/images/concentriccircles-example.png b/doc/src/images/concentriccircles-example.png Binary files differdeleted file mode 100644 index fd308b5642..0000000000 --- a/doc/src/images/concentriccircles-example.png +++ /dev/null diff --git a/examples/widgets/doc/src/concentriccircles.qdoc b/examples/widgets/doc/src/concentriccircles.qdoc deleted file mode 100644 index 3884261926..0000000000 --- a/examples/widgets/doc/src/concentriccircles.qdoc +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -/*! - \example painting/concentriccircles - \title Concentric Circles Example - \examplecategory {Graphics & Multimedia} - \ingroup examples-painting - \brief Demonstrates the improved quality that antialiasing and floating point precision gives. - - \brief The Concentric Circles example shows the improved rendering - quality that can be obtained using floating point precision and - anti-aliasing when drawing custom widgets. The example also shows - how to do simple animations. - - The application's main window displays several widgets which are - drawn using various combinations of precision and - anti-aliasing. - - \image concentriccircles-example.png - - Anti-aliasing is one of QPainter'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. - - The difference between floating point precision and integer - precision is a matter of accuracy, and is visible in the - application's main window: Even though the logic that is - calculating the circles' geometry is the same, floating points - ensure that the white spaces between each circle are of the same - size, while integers make two and two circles appear as if they - belong together. The reason is that the integer based precision - rely on rounding off non-integer calculations. - - The example consists of two classes: - - \list - \li \c CircleWidget is a custom widget which renders several animated - concentric circles. - \li \c Window is the application's main window displaying four \c - {CircleWidget}s drawn using different combinations of precision - and aliasing. - \endlist - - First we will review the CircleWidget class, then we will take a - look at the Window class. - - \section1 CircleWidget Class Definition - - The CircleWidget class inherits QWidget, and is a custom widget - which renders several animated concentric circles. - - \snippet painting/concentriccircles/circlewidget.h 0 - - We declare the \c floatBased and \c antialiased variables to hold - whether an instance of the class should be rendered with integer - or float based precision, and whether the rendering should be - anti-aliased or not. We also declare functions setting each of - these variables. - - In addition we reimplement the QWidget::paintEvent() function to - apply the various combinations of precision and anti-aliasing when - rendering, and to support the animation. We reimplement the - QWidget::minimumSizeHint() and QWidget::sizeHint() functions to - give the widget a reasonable size within our application. - - We declare the private \c nextAnimationFrame() slot, and the - associated \c frameNo variable holding the number of "animation - frames" for the widget, to facilitate the animation. - - \section1 CircleWidget Class Implementation - - In the constructor we make the widget's rendering integer based - and aliased by default: - - \snippet painting/concentriccircles/circlewidget.cpp 0 - - We initialize the widget's \c frameNo variable, and set the - widget's background color using the QWidget::setBackgroundColor() - function which takes a \l {QPalette::ColorRole}{color role} as - argument; the QPalette::Base color role is typically white. - - Then we set the widgets size policy using the - QWidget::setSizePolicy() function. QSizePolicy::Expanding means - that the widget's \l {QWidget::sizeHint()}{sizeHint()} is a - sensible size, but that the widget can be shrunk and still be - useful. The widget can also make use of extra space, so it should - get as much space as possible. - - \snippet painting/concentriccircles/circlewidget.cpp 1 - \codeline - \snippet painting/concentriccircles/circlewidget.cpp 2 - - The public \c setFloatBased() and \c setAntialiased() functions - update the widget's rendering preferences, i.e. whether the widget - should be rendered with integer or float based precision, and - whether the rendering should be anti-aliased or not. - - The functions also generate a paint event by calling the - QWidget::update() function, forcing a repaint of the widget with - the new rendering preferences. - - \snippet painting/concentriccircles/circlewidget.cpp 3 - \codeline - \snippet painting/concentriccircles/circlewidget.cpp 4 - - The default implementations of the QWidget::minimumSizeHint() and - QWidget::sizeHint() functions return invalid sizes if there is no - layout for the widget, otherwise they return the layout's minimum and - preferred size, respectively. - - We reimplement the functions to give the widget minimum and - preferred sizes which are reasonable within our application. - - \snippet painting/concentriccircles/circlewidget.cpp 5 - - The nextAnimationFrame() slot simply increments the \c frameNo - variable's value, and calls the QWidget::update() function which - schedules a paint event for processing when Qt returns to the main - event loop. - - \snippet painting/concentriccircles/circlewidget.cpp 6 - - A paint event is a request to repaint all or part of the - widget. The \c paintEvent() function is an event handler that can - be reimplemented to receive the widget's paint events. We - reimplement the event handler to apply the various combinations of - precision and anti-aliasing when rendering the widget, and to - support the animation. - - First, we create a QPainter for the widget, and set its - antialiased flag to the widget's preferred aliasing. We also - translate the painters coordinate system, preparing to draw the - widget's cocentric circles. The translation ensures that the - center of the circles will be equivalent to the widget's center. - - \snippet painting/concentriccircles/circlewidget.cpp 7 - - When painting a circle, we use the number of "animation frames" to - determine the alpha channel of the circle's color. The alpha - channel specifies the color's transparency effect, 0 represents a - fully transparent color, while 255 represents a fully opaque - color. - - \snippet painting/concentriccircles/circlewidget.cpp 8 - - If the calculated alpha channel is fully transparent, we don't - draw anything since that would be equivalent to drawing a white - circle on a white background. Instead we skip to the next circle - still creating a white space. If the calculated alpha channel is - fully opaque, we set the pen (the QColor passed to the QPen - constructor is converted into the required QBrush by default) and - draw the circle. If the widget's preferred precision is float - based, we specify the circle's bounding rectangle using QRectF and - double values, otherwise we use QRect and integers. - - The animation is controlled by the public \c nextAnimationFrame() - slot: Whenever the \c nextAnimationFrame() slot is called the - number of frames is incremented and a paint event is - scheduled. Then, when the widget is repainted, the alpha-blending - of the circles' colors change and the circles appear as animated. - - \section1 Window Class Definition - - The Window class inherits QWidget, and is the application's main - window rendering four \c {CircleWidget}s using different - combinations of precision and aliasing. - - \snippet painting/concentriccircles/window.h 0 - - We declare the various components of the main window, i.e., the text - labels and a double array that will hold reference to the four \c - {CircleWidget}s. In addition we declare the private \c - createLabel() function to simplify the constructor. - - \section1 Window Class Implementation - - \snippet painting/concentriccircles/window.cpp 0 - - In the constructor, we first create the various labels and put - them in a QGridLayout. - - \snippet painting/concentriccircles/window.cpp 1 - - Then we create a QTimer. The QTimer class is a high-level - programming interface for timers, and provides repetitive and - single-shot timers. - - We create a timer to facilitate the animation of our concentric - circles; when we create the four CircleWidget instances (and add - them to the layout), we connect the QTimer::timeout() signal to - each of the widgets' \c nextAnimationFrame() slots. - - \snippet painting/concentriccircles/window.cpp 2 - - Before we set the layout and window title for our main window, we - make the timer start with a timeout interval of 100 milliseconds, - using the QTimer::start() function. That means that the - QTimer::timeout() signal will be emitted, forcing a repaint of the - four \c {CircleWidget}s, every 100 millisecond which is the reason - the circles appear as animated. - - \snippet painting/concentriccircles/window.cpp 3 - - The private \c createLabel() function is implemented to simlify - the constructor. -*/ diff --git a/examples/widgets/painting/CMakeLists.txt b/examples/widgets/painting/CMakeLists.txt index 055ae44c45..0d771ec638 100644 --- a/examples/widgets/painting/CMakeLists.txt +++ b/examples/widgets/painting/CMakeLists.txt @@ -2,7 +2,6 @@ # SPDX-License-Identifier: BSD-3-Clause qt_internal_add_example(basicdrawing) -qt_internal_add_example(concentriccircles) qt_internal_add_example(affine) qt_internal_add_example(composition) qt_internal_add_example(deform) diff --git a/examples/widgets/painting/concentriccircles/CMakeLists.txt b/examples/widgets/painting/concentriccircles/CMakeLists.txt deleted file mode 100644 index 995a974b25..0000000000 --- a/examples/widgets/painting/concentriccircles/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause - -cmake_minimum_required(VERSION 3.16) -project(concentriccircles LANGUAGES CXX) - -if(NOT DEFINED INSTALL_EXAMPLESDIR) - set(INSTALL_EXAMPLESDIR "examples") -endif() - -set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/concentriccircles") - -find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets) - -qt_standard_project_setup() - -qt_add_executable(concentriccircles - circlewidget.cpp circlewidget.h - main.cpp - window.cpp window.h -) - -set_target_properties(concentriccircles PROPERTIES - WIN32_EXECUTABLE TRUE - MACOSX_BUNDLE TRUE -) - -target_link_libraries(concentriccircles PRIVATE - Qt6::Core - Qt6::Gui - Qt6::Widgets -) - -install(TARGETS concentriccircles - RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" - BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" - LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" -) diff --git a/examples/widgets/painting/concentriccircles/circlewidget.cpp b/examples/widgets/painting/concentriccircles/circlewidget.cpp deleted file mode 100644 index febaa5d709..0000000000 --- a/examples/widgets/painting/concentriccircles/circlewidget.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include "circlewidget.h" - -#include <QPainter> - -#include <stdlib.h> - -//! [0] -CircleWidget::CircleWidget(QWidget *parent) - : QWidget(parent) -{ - floatBased = false; - antialiased = false; - frameNo = 0; - - setBackgroundRole(QPalette::Base); - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); -} -//! [0] - -//! [1] -void CircleWidget::setFloatBased(bool floatBased) -{ - this->floatBased = floatBased; - update(); -} -//! [1] - -//! [2] -void CircleWidget::setAntialiased(bool antialiased) -{ - this->antialiased = antialiased; - update(); -} -//! [2] - -//! [3] -QSize CircleWidget::minimumSizeHint() const -{ - return QSize(50, 50); -} -//! [3] - -//! [4] -QSize CircleWidget::sizeHint() const -{ - return QSize(180, 180); -} -//! [4] - -//! [5] -void CircleWidget::nextAnimationFrame() -{ - ++frameNo; - update(); -} -//! [5] - -//! [6] -void CircleWidget::paintEvent(QPaintEvent *) -{ - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing, antialiased); - painter.translate(width() / 2, height() / 2); -//! [6] - -//! [7] - for (int diameter = 0; diameter < 256; diameter += 9) { - int delta = abs((frameNo % 128) - diameter / 2); - int alpha = 255 - (delta * delta) / 4 - diameter; -//! [7] //! [8] - if (alpha > 0) { - painter.setPen(QPen(QColor(0, diameter / 2, 127, alpha), 3)); - - if (floatBased) - painter.drawEllipse(QRectF(-diameter / 2.0, -diameter / 2.0, diameter, diameter)); - else - painter.drawEllipse(QRect(-diameter / 2, -diameter / 2, diameter, diameter)); - } - } -} -//! [8] diff --git a/examples/widgets/painting/concentriccircles/circlewidget.h b/examples/widgets/painting/concentriccircles/circlewidget.h deleted file mode 100644 index 5632ee1d72..0000000000 --- a/examples/widgets/painting/concentriccircles/circlewidget.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#ifndef CIRCLEWIDGET_H -#define CIRCLEWIDGET_H - -#include <QWidget> - -//! [0] -class CircleWidget : public QWidget -{ - Q_OBJECT - -public: - CircleWidget(QWidget *parent = nullptr); - - void setFloatBased(bool floatBased); - void setAntialiased(bool antialiased); - - QSize minimumSizeHint() const override; - QSize sizeHint() const override; - -public slots: - void nextAnimationFrame(); - -protected: - void paintEvent(QPaintEvent *event) override; - -private: - bool floatBased; - bool antialiased; - int frameNo; -}; -//! [0] - -#endif // CIRCLEWIDGET_H diff --git a/examples/widgets/painting/concentriccircles/concentriccircles.pro b/examples/widgets/painting/concentriccircles/concentriccircles.pro deleted file mode 100644 index 844c01a9c2..0000000000 --- a/examples/widgets/painting/concentriccircles/concentriccircles.pro +++ /dev/null @@ -1,11 +0,0 @@ -QT += widgets - -HEADERS = circlewidget.h \ - window.h -SOURCES = circlewidget.cpp \ - main.cpp \ - window.cpp - -# install -target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/concentriccircles -INSTALLS += target diff --git a/examples/widgets/painting/concentriccircles/main.cpp b/examples/widgets/painting/concentriccircles/main.cpp deleted file mode 100644 index 1d8fd919b2..0000000000 --- a/examples/widgets/painting/concentriccircles/main.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include "window.h" - -#include <QApplication> - -int main(int argc, char *argv[]) -{ - QApplication app(argc, argv); - Window window; - window.show(); - return app.exec(); -} diff --git a/examples/widgets/painting/concentriccircles/window.cpp b/examples/widgets/painting/concentriccircles/window.cpp deleted file mode 100644 index 9f25c2fcde..0000000000 --- a/examples/widgets/painting/concentriccircles/window.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include "circlewidget.h" -#include "window.h" - -#include <QtWidgets> - -//! [0] -Window::Window() -{ - aliasedLabel = createLabel(tr("Aliased")); - antialiasedLabel = createLabel(tr("Antialiased")); - intLabel = createLabel(tr("Int")); - floatLabel = createLabel(tr("Float")); - - QGridLayout *layout = new QGridLayout; - layout->addWidget(aliasedLabel, 0, 1); - layout->addWidget(antialiasedLabel, 0, 2); - layout->addWidget(intLabel, 1, 0); - layout->addWidget(floatLabel, 2, 0); -//! [0] - -//! [1] - QTimer *timer = new QTimer(this); - - for (int i = 0; i < 2; ++i) { - for (int j = 0; j < 2; ++j) { - circleWidgets[i][j] = new CircleWidget; - circleWidgets[i][j]->setAntialiased(j != 0); - circleWidgets[i][j]->setFloatBased(i != 0); - - connect(timer, &QTimer::timeout, - circleWidgets[i][j], &CircleWidget::nextAnimationFrame); - - layout->addWidget(circleWidgets[i][j], i + 1, j + 1); - } - } -//! [1] //! [2] - timer->start(100); - setLayout(layout); - - setWindowTitle(tr("Concentric Circles")); -} -//! [2] - -//! [3] -QLabel *Window::createLabel(const QString &text) -{ - QLabel *label = new QLabel(text); - label->setAlignment(Qt::AlignCenter); - label->setMargin(2); - label->setFrameStyle(QFrame::Box | QFrame::Sunken); - return label; -} -//! [3] diff --git a/examples/widgets/painting/concentriccircles/window.h b/examples/widgets/painting/concentriccircles/window.h deleted file mode 100644 index a111ffbe58..0000000000 --- a/examples/widgets/painting/concentriccircles/window.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#ifndef WINDOW_H -#define WINDOW_H - -#include <QWidget> - -QT_BEGIN_NAMESPACE -class QLabel; -QT_END_NAMESPACE -class CircleWidget; - -//! [0] -class Window : public QWidget -{ - Q_OBJECT - -public: - Window(); - -private: - QLabel *createLabel(const QString &text); - - QLabel *aliasedLabel; - QLabel *antialiasedLabel; - QLabel *intLabel; - QLabel *floatLabel; - CircleWidget *circleWidgets[2][2]; -}; -//! [0] - -#endif // WINDOW_H diff --git a/examples/widgets/painting/painting.pro b/examples/widgets/painting/painting.pro index 7d5c2e0209..1dfd660f77 100644 --- a/examples/widgets/painting/painting.pro +++ b/examples/widgets/painting/painting.pro @@ -1,6 +1,5 @@ TEMPLATE = subdirs SUBDIRS = basicdrawing \ - concentriccircles \ affine \ composition \ deform \ diff --git a/src/gui/doc/images/qpainter-concentriccircles.png b/src/gui/doc/images/qpainter-concentriccircles.png Binary files differindex 4889dcd76d..d9489a4162 100644 --- a/src/gui/doc/images/qpainter-concentriccircles.png +++ b/src/gui/doc/images/qpainter-concentriccircles.png diff --git a/src/gui/doc/snippets/code/src_gui_painting_qpainter.cpp b/src/gui/doc/snippets/code/src_gui_painting_qpainter.cpp index 6f52930f73..cfbf3e44a2 100644 --- a/src/gui/doc/snippets/code/src_gui_painting_qpainter.cpp +++ b/src/gui/doc/snippets/code/src_gui_painting_qpainter.cpp @@ -63,6 +63,7 @@ struct MyWidget : public QWidget void wrapper13(); void wrapper14(); void wrapper15(); + void concentricCircles(); }; QLine drawingCode; @@ -355,4 +356,21 @@ painter.drawRect(rectangle.adjusted(0, 0, -pen.width(), -pen.width())); } // MyWidget::wrapper15 -} // src_gui_painting_qpainter2 + +void MyWidget::concentricCircles() +{ +//! [renderHint] + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); +//! [renderHint] + int diameter = 50; +//! [floatBased] + painter.drawEllipse(QRectF(-diameter / 2.0, -diameter / 2.0, diameter, diameter)); +//! [floatBased] +//! [intBased] + painter.drawEllipse(QRect(-diameter / 2, -diameter / 2, diameter, diameter)); +//! [intBased] + +} // MyWidget::concentricCircles + +} // src_gui_painting_qpainter2
\ No newline at end of file diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 70bcd92fdd..756acdb583 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -1125,24 +1125,22 @@ void QPainterPrivate::updateState(QPainterState *newState) The QPainter class also provides a means of controlling the rendering quality through its RenderHint enum and the support for floating point precision: All the functions for drawing primitives - has a floating point version. These are often used in combination + have floating point versions. + + \snippet code/src_gui_painting_qpainter.cpp floatBased + + These are often used in combination with the \l {RenderHint}{QPainter::Antialiasing} render hint. + \snippet code/src_gui_painting_qpainter.cpp renderHint + \table 100% \row + \li Comparing concentric circles with int and float, and with or without + anti-aliased rendering. Using the floating point precision versions + produces evenly spaced rings. Anti-aliased rendering results in + smooth circles. \li \inlineimage qpainter-concentriccircles.png - \li - \b {Concentric Circles Example} - - The \l {painting/concentriccircles}{Concentric Circles} example - shows the improved rendering quality that can be obtained using - floating point precision and anti-aliasing when drawing custom - widgets. - - The application's main window displays several widgets which are - drawn using the various combinations of precision and - anti-aliasing. - \endtable The RenderHint enum specifies flags to QPainter that may or may diff --git a/tests/auto/guiapplauncher/examples.txt b/tests/auto/guiapplauncher/examples.txt index 1cfa04488d..0cca93745f 100644 --- a/tests/auto/guiapplauncher/examples.txt +++ b/tests/auto/guiapplauncher/examples.txt @@ -63,7 +63,6 @@ "painting/affine Example", "examples/widgets/painting/affine", "affine", 0, -1 "painting/basicdrawing Example", "examples/widgets/painting/basicdrawing", "basicdrawing", 10, -1 "painting/composition Example", "examples/widgets/painting/composition", "composition", 0, -1 -"painting/concentriccircles Example", "examples/widgets/painting/concentriccircles", "concentriccircles", 0, -1 "painting/deform Example", "examples/widgets/painting/deform", "deform", 0, -1 "painting/fontsampler Example", "examples/widgets/painting/fontsampler", "fontsampler", 0, -1 "painting/gradients Example", "examples/widgets/painting/gradients", "gradients", 0, -1 |