Revamp the shapedclock example
Rename it to "Translucent Background", as that's what the example shows how to do. And modern applications shouldn't use a (binary) mask to create shaped windows. Instead, set the TranslucentBackground attribute, don't paint pixels that should be fully transparent and use anti-aliased or semi-opaque painting for pixels that should be translucent. Adjust the example and documentation accordingly. Move the statment that widget masks create coarse visual clipping to the QWidget::setMask documentation. Pick-to: 6.5 Change-Id: Id49d854093f2cb471afb178d32723081c7543543 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
322387ce7b
commit
8e94af2ed0
@ -3,17 +3,18 @@
|
||||
|
||||
/*!
|
||||
\example widgets/shapedclock
|
||||
\title Shaped Clock Example
|
||||
\title Translucent Background
|
||||
\ingroup examples-widgets
|
||||
\brief The Shaped Clock example shows how to apply a translucent background
|
||||
and a widget mask to a top-level widget to produce a shaped window.
|
||||
\brief The example shows how to make a round window with a translucent
|
||||
background.
|
||||
|
||||
\borderedimage shapedclock-example.png
|
||||
|
||||
Widget masks are used to customize the shapes of top-level widgets by
|
||||
restricting the area available for painting and mouse input. Using a
|
||||
translucent background facilitates partially transparent windows and smooth
|
||||
edges. On most window systems, setting certain window flags will cause the
|
||||
Widgets that set their background to be translucent will be transparent for all
|
||||
unpainted pixels, and the background will shine through pixels painted with an
|
||||
opacity of less than 100%. Pixels that are not painted at all will also not
|
||||
receive any mouse input. This can be used to customize the shapes of top-level
|
||||
widgets. On most window systems, setting certain window flags will cause the
|
||||
window decoration (title bar, window frame, buttons) to be disabled,
|
||||
allowing specially-shaped windows to be created. In this example, we use
|
||||
this feature to create a circular window containing an analog clock.
|
||||
@ -30,12 +31,10 @@
|
||||
|
||||
\snippet widgets/shapedclock/shapedclock.h 0
|
||||
|
||||
The \l{QWidget::paintEvent()}{paintEvent()} implementation is the same as
|
||||
that found in the \c AnalogClock class, with one important exception: we
|
||||
now must also draw background (the clock face) ourselves, since the widget
|
||||
background is just transparent. We implement \l{QWidget::sizeHint()}{sizeHint()}
|
||||
so that we don't have to resize the widget explicitly. We also provide an event
|
||||
handler for resize events. This allows us to update the mask if the clock is resized.
|
||||
The \l{QWidget::paintEvent()}{paintEvent()} implementation draws an analog clock
|
||||
on a semi-transparent background (the clock face). In addition, we implement
|
||||
\l{QWidget::sizeHint()}{sizeHint()} so that we don't have to resize the widget
|
||||
explicitly.
|
||||
|
||||
Since the window containing the clock widget will have no title bar, we provide
|
||||
implementations for \l{QWidget::mouseMoveEvent()}{mouseMoveEvent()} and
|
||||
@ -45,8 +44,9 @@
|
||||
|
||||
\section1 ShapedClock Class Implementation
|
||||
|
||||
The \c ShapedClock constructor performs many of the same tasks as the \c AnalogClock
|
||||
constructor. We set up a timer and connect it to the widget's update() slot:
|
||||
The \c ShapedClock constructor sets up a timer and connect it to the widget's
|
||||
update() slot. In addition, we add an action to the widget, which will automatically
|
||||
become available through a context menu when right-clicking on the widget.
|
||||
|
||||
\snippet widgets/shapedclock/shapedclock.cpp 0
|
||||
|
||||
@ -77,49 +77,14 @@
|
||||
cursor position in global coordinates. If we drag the widget, we also accept the event.
|
||||
|
||||
The \c paintEvent() function is mainly the same as described in the
|
||||
\l{Analog Clock} example. The one addition is that we
|
||||
use QPainter::drawEllipse() to draw a round clock face with the current
|
||||
palette's default background color. We make the clock face a bit smaller
|
||||
than the widget mask, so that the anti-aliased, semi-transparent pixels on
|
||||
the edge are not clipped away by the widget mask. This gives the shaped
|
||||
window smooth edges on the screen.
|
||||
\l{Analog Clock} example. The one addition is that we use QPainter::drawEllipse() to
|
||||
draw a round clock face. We reduce the painter's opacity to 90%, and use the palette's
|
||||
default background color.
|
||||
|
||||
\snippet widgets/shapedclock/shapedclock.cpp 3
|
||||
|
||||
In the \c resizeEvent() handler, we re-use some of the code from the \c
|
||||
paintEvent() to determine the region of the widget that is visible to the
|
||||
user. This tells the system the area where mouse clicks should go to us,
|
||||
and not to whatever window is behind us:
|
||||
|
||||
\snippet widgets/shapedclock/shapedclock.cpp 4
|
||||
|
||||
Since the clock face is a circle drawn in the center of the widget, this is the region
|
||||
we use as the mask.
|
||||
|
||||
Although the lack of a window frame may make it difficult for the user to resize the
|
||||
widget on some platforms, it will not necessarily be impossible. The \c resizeEvent()
|
||||
function ensures that the widget mask will always be updated if the widget's dimensions
|
||||
change, and additionally ensures that it will be set up correctly when the widget is
|
||||
first displayed.
|
||||
|
||||
Finally, we implement the \c sizeHint() for the widget so that it is given a reasonable
|
||||
default size when it is first shown:
|
||||
|
||||
\snippet widgets/shapedclock/shapedclock.cpp 5
|
||||
|
||||
\section1 Notes on Widget Masks
|
||||
|
||||
Widget masks are used to hint to the window system that the application
|
||||
does not want mouse events for areas outside the mask. On most systems,
|
||||
they also result in coarse visual clipping. To get smooth window edges, one
|
||||
should use translucent background and anti-aliased painting, as shown in
|
||||
this example.
|
||||
|
||||
Since QRegion allows arbitrarily complex regions to be created, widget masks can be
|
||||
made to suit the most unconventionally-shaped windows, and even allow widgets to be
|
||||
displayed with holes in them.
|
||||
|
||||
Widget masks can also be constructed by using the contents of pixmap to define the
|
||||
opaque part of the widget. For a pixmap with an alpha channel, a suitable mask can be
|
||||
obtained with QPixmap::mask().
|
||||
\snippet widgets/shapedclock/shapedclock.cpp 4
|
||||
*/
|
||||
|
@ -78,7 +78,9 @@ void ShapedClock::paintEvent(QPaintEvent *)
|
||||
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(palette().window());
|
||||
painter.setOpacity(0.9);
|
||||
painter.drawEllipse(QPoint(0, 0), 98, 98);
|
||||
painter.setOpacity(1.0);
|
||||
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(hourColor);
|
||||
@ -114,18 +116,8 @@ void ShapedClock::paintEvent(QPaintEvent *)
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
void ShapedClock::resizeEvent(QResizeEvent * /* event */)
|
||||
{
|
||||
int side = qMin(width(), height());
|
||||
QRegion maskedRegion(width() / 2 - side / 2, height() / 2 - side / 2, side,
|
||||
side, QRegion::Ellipse);
|
||||
setMask(maskedRegion);
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
QSize ShapedClock::sizeHint() const
|
||||
{
|
||||
return QSize(200, 200);
|
||||
}
|
||||
//! [5]
|
||||
//! [4]
|
||||
|
@ -19,7 +19,6 @@ protected:
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
QPoint dragPosition;
|
||||
|
@ -10233,7 +10233,7 @@ void QWidget::ensurePolished() const
|
||||
Returns the mask currently set on a widget. If no mask is set the
|
||||
return value will be an empty region.
|
||||
|
||||
\sa setMask(), clearMask(), QRegion::isEmpty(), {Shaped Clock Example}
|
||||
\sa setMask(), clearMask(), QRegion::isEmpty()
|
||||
*/
|
||||
QRegion QWidget::mask() const
|
||||
{
|
||||
@ -12964,8 +12964,16 @@ QPainter *QWidget::sharedPainter() const
|
||||
widget, window system controls in that area may or may not be
|
||||
visible, depending on the platform.
|
||||
|
||||
Note that this effect can be slow if the region is particularly
|
||||
complex.
|
||||
Since QRegion allows arbitrarily complex regions to be created, widget
|
||||
masks can be made to suit the most unconventionally-shaped windows, and
|
||||
even allow widgets to be displayed with holes in them. Note that this
|
||||
effect can be slow if the region is particularly complex.
|
||||
|
||||
Widget masks are used to hint to the window system that the application
|
||||
does not want mouse events for areas outside the mask. On most systems,
|
||||
they also result in coarse visual clipping. To get smooth window edges, use
|
||||
translucent background and anti-aliased painting instead, as shown in the
|
||||
\l{Translucent Background} example.
|
||||
|
||||
\sa windowOpacity
|
||||
*/
|
||||
@ -13051,7 +13059,7 @@ void QWidgetPrivate::setMask_sys(const QRegion ®ion)
|
||||
Masked widgets receive mouse events only on their visible
|
||||
portions.
|
||||
|
||||
\sa clearMask(), windowOpacity(), {Shaped Clock Example}
|
||||
\sa clearMask(), windowOpacity()
|
||||
*/
|
||||
void QWidget::setMask(const QBitmap &bitmap)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user