diff options
Diffstat (limited to 'doc/src/examples/styles.qdoc')
-rw-r--r-- | doc/src/examples/styles.qdoc | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/doc/src/examples/styles.qdoc b/doc/src/examples/styles.qdoc new file mode 100644 index 0000000..b68a310 --- /dev/null +++ b/doc/src/examples/styles.qdoc @@ -0,0 +1,486 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example widgets/styles + \title Styles Example + + The Styles example illustrates how to create custom widget + drawing styles using Qt, and demonstrates Qt's predefined styles. + + \image styles-enabledwood.png Screenshot of the Styles example + + A style in Qt is a subclass of QStyle or of one of its + subclasses. Styles perform drawing on behalf of widgets. Qt + provides a whole range of predefined styles, either built into + the \l QtGui library or found in plugins. Custom styles are + usually created by subclassing one of Qt's existing style and + reimplementing a few virtual functions. + + In this example, the custom style is called \c NorwegianWoodStyle + and derives from QMotifStyle. Its main features are the wooden + textures used for filling most of the widgets and its round + buttons and comboboxes. + + To implement the style, we use some advanced features provided by + QPainter, such as \l{QPainter::Antialiasing}{antialiasing} (to + obtain smoother button edges), \l{QColor::alpha()}{alpha blending} + (to make the buttons appeared raised or sunken), and + \l{QPainterPath}{painter paths} (to fill the buttons and draw the + outline). We also use many features of QBrush and QPalette. + + The example consists of the following classes: + + \list + \o \c NorwegianWoodStyle inherits from QMotifStyle and implements + the Norwegian Wood style. + \o \c WidgetGallery is a \c QDialog subclass that shows the most + common widgets and allows the user to switch style + dynamically. + \endlist + + \section1 NorwegianWoodStyle Class Definition + + Here's the definition of the \c NorwegianWoodStyle class: + + \snippet examples/widgets/styles/norwegianwoodstyle.h 0 + + The public functions are all declared in QStyle (QMotifStyle's + grandparent class) and reimplemented here to override the Motif + look and feel. The private functions are helper functions. + + \section1 NorwegianWoodStyle Class Implementation + + We will now review the implementation of the \c + NorwegianWoodStyle class. + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 0 + + The \c polish() function is reimplemented from QStyle. It takes a + QPalette as a reference and adapts the palette to fit the style. + Most styles don't need to reimplement that function. The + Norwegian Wood style reimplements it to set a "wooden" palette. + + We start by defining a few \l{QColor}s that we'll need. Then we + load two PNG images. The \c : prefix in the file path indicates + that the PNG files are \l{The Qt Resource System}{embedded + resources}. + + \table + \row \o \inlineimage widgets/styles/images/woodbackground.png + + \o \bold{woodbackground.png} + + This texture is used as the background of most widgets. + The wood pattern is horizontal. + + \row \o \inlineimage widgets/styles/images/woodbutton.png + + \o \bold{woodbutton.png} + + This texture is used for filling push buttons and + comboboxes. The wood pattern is vertical and more reddish + than the texture used for the background. + \endtable + + The \c midImage variable is initialized to be the same as \c + buttonImage, but then we use a QPainter and fill it with a 25% + opaque black color (a black with an \l{QColor::alpha()}{alpha + channel} of 63). The result is a somewhat darker image than \c + buttonImage. This image will be used for filling buttons that the + user is holding down. + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 1 + + We initialize the palette. Palettes have various + \l{QPalette::ColorRole}{color roles}, such as QPalette::Base + (used for filling text editors, item views, etc.), QPalette::Text + (used for foreground text), and QPalette::Background (used for + the background of most widgets). Each role has its own QBrush, + which usually is a plain color but can also be a brush pattern or + even a texture (a QPixmap). + + In addition to the roles, palettes have several + \l{QPalette::ColorGroup}{color groups}: active, disabled, and + inactive. The active color group is used for painting widgets in + the active window. The disabled group is used for disabled + widgets. The inactive group is used for all other widgets. Most + palettes have identical active and inactive groups, while the + disabled group uses darker shades. + + We initialize the QPalette object with a brown color. Qt + automatically derivates all color roles for all color groups from + that single color. We then override some of the default values. For + example, we use Qt::darkGreen instead of the default + (Qt::darkBlue) for the QPalette::Highlight role. The + QPalette::setBrush() overload that we use here sets the same + color or brush for all three color groups. + + The \c setTexture() function is a private function that sets the + texture for a certain color role, while preserving the existing + color in the QBrush. A QBrush can hold both a solid color and a + texture at the same time. The solid color is used for drawing + text and other graphical elements where textures don't look good. + + At the end, we set the brush for the disabled color group of the + palette. We use \c woodbackground.png as the texture for all + disabled widgets, including buttons, and use a darker color to + accompany the texture. + + \image styles-disabledwood.png The Norwegian Wood style with disabled widgets + + Let's move on to the other functions reimplemented from + QMotifStyle: + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 3 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 4 + + This QStyle::polish() overload is called once on every widget + drawn using the style. We reimplement it to set the Qt::WA_Hover + attribute on \l{QPushButton}s and \l{QComboBox}es. When this + attribute is set, Qt generates paint events when the mouse + pointer enters or leaves the widget. This makes it possible to + render push buttons and comboboxes differently when the mouse + pointer is over them. + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 5 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 6 + + This QStyle::unpolish() overload is called to undo any + modification done to the widget in \c polish(). For simplicity, + we assume that the flag wasn't set before \c polish() was called. + In an ideal world, we would remember the original state for each + widgets (e.g., using a QMap<QWidget *, bool>) and restore it in + \c unpolish(). + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 7 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 8 + + The \l{QStyle::pixelMetric()}{pixelMetric()} function returns the + size in pixels for a certain user interface element. By + reimplementing this function, we can affect the way certain + widgets are drawn and their size hint. Here, we return 8 as the + width around a shown in a QComboBox, ensuring that there is + enough place around the text and the arrow for the Norwegian Wood + round corners. The default value for this setting in the Motif + style is 2. + + We also change the extent of \l{QScrollBar}s, i.e., the height + for a horizontal scroll bar and the width for a vertical scroll + bar, to be 4 pixels more than in the Motif style. This makes the + style a bit more distinctive. + + For all other QStyle::PixelMetric elements, we use the Motif + settings. + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 9 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 10 + + The \l{QStyle::styleHint()}{styleHint()} function returns some + hints to widgets or to the base style (in our case QMotifStyle) + about how to draw the widgets. The Motif style returns \c true + for the QStyle::SH_DitherDisabledText hint, resulting in a most + unpleasing visual effect. We override this behavior and return \c + false instead. We also return \c true for the + QStyle::SH_EtchDisabledText hint, meaning that disabled text is + rendered with an embossed look (as QWindowsStyle does). + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 11 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 12 + + The \l{QStyle::drawPrimitive()}{drawPrimitive()} function is + called by Qt widgets to draw various fundamental graphical + elements. Here we reimplement it to draw QPushButton and + QComboBox with round corners. The button part of these widgets is + drawn using the QStyle::PE_PanelButtonCommand primitive element. + + The \c option parameter, of type QStyleOption, contains + everything we need to know about the widget we want to draw on. + In particular, \c option->rect gives the rectangle within which + to draw the primitive element. The \c painter parameter is a + QPainter object that we can use to draw on the widget. + + The \c widget parameter is the widget itself. Normally, all the + information we need is available in \c option and \c painter, so + we don't need \c widget. We can use it to perform special + effects; for example, QMacStyle uses it to animate default + buttons. If you use it, be aware that the caller is allowed to + pass a null pointer. + + We start by defining three \l{QColor}s that we'll need later on. + We also put the x, y, width, and height components of the + widget's rectangle in local variables. The value used for the \c + semiTransparentWhite and for the \c semiTransparentBlack color's + alpha channel depends on whether the mouse cursor is over the + widget or not. Since we set the Qt::WA_Hover attribute on + \l{QPushButton}s and \l{QComboBox}es, we can rely on the + QStyle::State_MouseOver flag to be set when the mouse is over the + widget. + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 13 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 14 + + The \c roundRect variable is a QPainterPath. A QPainterPath is is + a vectorial specification of a shape. Any shape (rectangle, + ellipse, spline, etc.) or combination of shapes can be expressed + as a path. We will use \c roundRect both for filling the button + background with a wooden texture and for drawing the outline. The + \c roundRectPath() function is a private function; we will come + back to it later. + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 15 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 16 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 17 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 18 + + We define two variables, \c brush and \c darker, and initialize + them based on the state of the button: + + \list + \o If the button is a \l{QPushButton::flat}{flat button}, we use + the \l{QPalette::Background}{Background} brush. We set \c + darker to \c true if the button is + \l{QAbstractButton::down}{down} or + \l{QAbstractButton::checked}{checked}. + \o If the button is currently held down by the user or in the + \l{QAbstractButton::checked}{checked} state, we use the + \l{QPalette::Mid}{Mid} component of the palette. We set + \c darker to \c true if the button is + \l{QAbstractButton::checked}{checked}. + \o Otherwise, we use the \l{QPalette::Button}{Button} component + of the palette. + \endlist + + The screenshot below illustrates how \l{QPushButton}s are + rendered based on their state: + + \image styles-woodbuttons.png Norwegian Wood buttons in different states + + To discover whether the button is flat or not, we need to cast + the \c option parameter to QStyleOptionButton and check if the + \l{QStyleOptionButton::features}{features} member specifies the + QStyleOptionButton::Flat flag. The qstyleoption_cast() function + performs a dynamic cast; if \c option is not a + QStyleOptionButton, qstyleoption_cast() returns a null pointer. + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 19 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 20 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 21 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 22 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 23 + + We turn on antialiasing on QPainter. Antialiasing is a technique + that reduces the visual distortion that occurs when the edges of + a shape are converted into pixels. For the Norwegian Wood style, + we use it to obtain smoother edges for the round buttons. + + \image styles-aliasing.png Norwegian wood buttons with and without antialiasing + + The first call to QPainter::fillPath() draws the background of + the button with a wooden texture. The second call to + \l{QPainter::fillPath()}{fillPath()} paints the same area with a + semi-transparent black color (a black color with an alpha channel + of 63) to make the area darker if \c darker is true. + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 24 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 25 + + Next, we draw the outline. The top-left half of the outline and + the bottom-right half of the outline are drawn using different + \l{QPen}s to produce a 3D effect. Normally, the top-left half of + the outline is drawn lighter whereas the bottom-right half is + drawn darker, but if the button is + \l{QAbstractButton::down}{down} or + \l{QAbstractButton::checked}{checked}, we invert the two + \l{QPen}s to give a sunken look to the button. + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 26 + + We draw the top-left part of the outline by calling + QPainter::drawPath() with an appropriate + \l{QPainter::setClipRegion()}{clip region}. If the + \l{QStyleOption::direction}{layout direction} is right-to-left + instead of left-to-right, we swap the \c x1, \c x2, \c x3, and \c + x4 variables to obtain correct results. On right-to-left desktop, + the "light" comes from the top-right corner of the screen instead + of the top-left corner; raised and sunken widgets must be drawn + accordingly. + + The diagram below illustrates how 3D effects are drawn according + to the layout direction. The area in red on the diagram + corresponds to the \c topHalf polygon: + + \image styles-3d.png + + An easy way to test how a style looks in right-to-left mode is to + pass the \c -reverse command-line option to the application. This + option is recognized by the QApplication constructor. + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 32 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 33 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 34 + + The bottom-right part of the outline is drawn in a similar + fashion. Then we draw a one-pixel wide outline around the entire + button, using the \l{QPalette::Foreground}{Foreground} component + of the QPalette. + + This completes the QStyle::PE_PanelButtonCommand case of the \c + switch statement. Other primitive elements are handled by the + base style. Let's now turn to the other \c NorwegianWoodStyle + member functions: + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 35 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 36 + + We reimplement QStyle::drawControl() to draw the text on a + QPushButton in a bright color when the button is + \l{QAbstractButton::down}{down} or + \l{QAbstractButton::checked}{checked}. + + If the \c option parameter points to a QStyleOptionButton object + (it normally should), we take a copy of the object and modify its + \l{QStyleOption::palette}{palette} member to make the + QPalette::ButtonText be the same as the QPalette::BrightText + component (unless the widget is disabled). + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 37 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 38 + + The \c setTexture() function is a private function that sets the + \l{QBrush::texture()}{texture} component of the \l{QBrush}es for + a certain \l{QPalette::ColorRole}{color role}, for all three + \l{QPalette::ColorGroup}{color groups} (active, disabled, + inactive). We used it to initialize the Norwegian Wood palette in + \c polish(QPalette &). + + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 39 + \snippet examples/widgets/styles/norwegianwoodstyle.cpp 40 + + The \c roundRectPath() function is a private function that + constructs a QPainterPath object for round buttons. The path + consists of eight segments: four arc segments for the corners and + four lines for the sides. + + With around 250 lines of code, we have a fully functional custom + style based on one of the predefined styles. Custom styles can be + used to provide a distinct look to an application or family of + applications. + + \section1 WidgetGallery Class + + For completeness, we will quickly review the \c WidgetGallery + class, which contains the most common Qt widgets and allows the + user to change style dynamically. Here's the class definition: + + \snippet examples/widgets/styles/widgetgallery.h 0 + \dots + \snippet examples/widgets/styles/widgetgallery.h 1 + + Here's the \c WidgetGallery constructor: + + \snippet examples/widgets/styles/widgetgallery.cpp 0 + + We start by creating child widgets. The \gui Style combobox is + initialized with all the styles known to QStyleFactory, in + addition to \c NorwegianWood. The \c create...() functions are + private functions that set up the various parts of the \c + WidgetGallery. + + \snippet examples/widgets/styles/widgetgallery.cpp 1 + \snippet examples/widgets/styles/widgetgallery.cpp 2 + + We connect the \gui Style combobox to the \c changeStyle() + private slot, the \gui{Use style's standard palette} check box to + the \c changePalette() slot, and the \gui{Disable widgets} check + box to the child widgets' + \l{QWidget::setDisabled()}{setDisabled()} slot. + + \snippet examples/widgets/styles/widgetgallery.cpp 3 + \snippet examples/widgets/styles/widgetgallery.cpp 4 + + Finally, we put the child widgets in layouts. + + \snippet examples/widgets/styles/widgetgallery.cpp 5 + \snippet examples/widgets/styles/widgetgallery.cpp 6 + + When the user changes the style in the combobox, we call + QApplication::setStyle() to dynamically change the style of the + application. + + \snippet examples/widgets/styles/widgetgallery.cpp 7 + \snippet examples/widgets/styles/widgetgallery.cpp 8 + + If the user turns the \gui{Use style's standard palette} on, the + current style's \l{QStyle::standardPalette()}{standard palette} + is used; otherwise, the system's default palette is honored. + + For the Norwegian Wood style, this makes no difference because we + always override the palette with our own palette in \c + NorwegianWoodStyle::polish(). + + \snippet examples/widgets/styles/widgetgallery.cpp 9 + \snippet examples/widgets/styles/widgetgallery.cpp 10 + + The \c advanceProgressBar() slot is called at regular intervals + to advance the progress bar. Since we don't know how long the + user will keep the Styles application running, we use a + logarithmic formula: The closer the progress bar gets to 100%, + the slower it advances. + + We will review \c createProgressBar() in a moment. + + \snippet examples/widgets/styles/widgetgallery.cpp 11 + \snippet examples/widgets/styles/widgetgallery.cpp 12 + + The \c createTopLeftGroupBox() function creates the QGroupBox + that occupies the top-left corner of the \c WidgetGallery. We + skip the \c createTopRightGroupBox(), \c + createBottomLeftTabWidget(), and \c createBottomRightGroupBox() + functions, which are very similar. + + \snippet examples/widgets/styles/widgetgallery.cpp 13 + + In \c createProgressBar(), we create a QProgressBar at the bottom + of the \c WidgetGallery and connect its + \l{QTimer::timeout()}{timeout()} signal to the \c + advanceProgressBar() slot. +*/ |