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
|
\example widgets/shapedclock
|
||||||
\title Shaped Clock Example
|
\title Translucent Background
|
||||||
\ingroup examples-widgets
|
\ingroup examples-widgets
|
||||||
\brief The Shaped Clock example shows how to apply a translucent background
|
\brief The example shows how to make a round window with a translucent
|
||||||
and a widget mask to a top-level widget to produce a shaped window.
|
background.
|
||||||
|
|
||||||
\borderedimage shapedclock-example.png
|
\borderedimage shapedclock-example.png
|
||||||
|
|
||||||
Widget masks are used to customize the shapes of top-level widgets by
|
Widgets that set their background to be translucent will be transparent for all
|
||||||
restricting the area available for painting and mouse input. Using a
|
unpainted pixels, and the background will shine through pixels painted with an
|
||||||
translucent background facilitates partially transparent windows and smooth
|
opacity of less than 100%. Pixels that are not painted at all will also not
|
||||||
edges. On most window systems, setting certain window flags will cause the
|
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,
|
window decoration (title bar, window frame, buttons) to be disabled,
|
||||||
allowing specially-shaped windows to be created. In this example, we use
|
allowing specially-shaped windows to be created. In this example, we use
|
||||||
this feature to create a circular window containing an analog clock.
|
this feature to create a circular window containing an analog clock.
|
||||||
@ -30,12 +31,10 @@
|
|||||||
|
|
||||||
\snippet widgets/shapedclock/shapedclock.h 0
|
\snippet widgets/shapedclock/shapedclock.h 0
|
||||||
|
|
||||||
The \l{QWidget::paintEvent()}{paintEvent()} implementation is the same as
|
The \l{QWidget::paintEvent()}{paintEvent()} implementation draws an analog clock
|
||||||
that found in the \c AnalogClock class, with one important exception: we
|
on a semi-transparent background (the clock face). In addition, we implement
|
||||||
now must also draw background (the clock face) ourselves, since the widget
|
\l{QWidget::sizeHint()}{sizeHint()} so that we don't have to resize the widget
|
||||||
background is just transparent. We implement \l{QWidget::sizeHint()}{sizeHint()}
|
explicitly.
|
||||||
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.
|
|
||||||
|
|
||||||
Since the window containing the clock widget will have no title bar, we provide
|
Since the window containing the clock widget will have no title bar, we provide
|
||||||
implementations for \l{QWidget::mouseMoveEvent()}{mouseMoveEvent()} and
|
implementations for \l{QWidget::mouseMoveEvent()}{mouseMoveEvent()} and
|
||||||
@ -45,8 +44,9 @@
|
|||||||
|
|
||||||
\section1 ShapedClock Class Implementation
|
\section1 ShapedClock Class Implementation
|
||||||
|
|
||||||
The \c ShapedClock constructor performs many of the same tasks as the \c AnalogClock
|
The \c ShapedClock constructor sets up a timer and connect it to the widget's
|
||||||
constructor. We set up a timer and connect it to the widget's update() slot:
|
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
|
\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.
|
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
|
The \c paintEvent() function is mainly the same as described in the
|
||||||
\l{Analog Clock} example. The one addition is that we
|
\l{Analog Clock} example. The one addition is that we use QPainter::drawEllipse() to
|
||||||
use QPainter::drawEllipse() to draw a round clock face with the current
|
draw a round clock face. We reduce the painter's opacity to 90%, and use the palette's
|
||||||
palette's default background color. We make the clock face a bit smaller
|
default background color.
|
||||||
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.
|
|
||||||
|
|
||||||
\snippet widgets/shapedclock/shapedclock.cpp 3
|
\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
|
Finally, we implement the \c sizeHint() for the widget so that it is given a reasonable
|
||||||
default size when it is first shown:
|
default size when it is first shown:
|
||||||
|
|
||||||
\snippet widgets/shapedclock/shapedclock.cpp 5
|
\snippet widgets/shapedclock/shapedclock.cpp 4
|
||||||
|
|
||||||
\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().
|
|
||||||
*/
|
*/
|
||||||
|
@ -78,7 +78,9 @@ void ShapedClock::paintEvent(QPaintEvent *)
|
|||||||
|
|
||||||
painter.setPen(Qt::NoPen);
|
painter.setPen(Qt::NoPen);
|
||||||
painter.setBrush(palette().window());
|
painter.setBrush(palette().window());
|
||||||
|
painter.setOpacity(0.9);
|
||||||
painter.drawEllipse(QPoint(0, 0), 98, 98);
|
painter.drawEllipse(QPoint(0, 0), 98, 98);
|
||||||
|
painter.setOpacity(1.0);
|
||||||
|
|
||||||
painter.setPen(Qt::NoPen);
|
painter.setPen(Qt::NoPen);
|
||||||
painter.setBrush(hourColor);
|
painter.setBrush(hourColor);
|
||||||
@ -114,18 +116,8 @@ void ShapedClock::paintEvent(QPaintEvent *)
|
|||||||
//! [3]
|
//! [3]
|
||||||
|
|
||||||
//! [4]
|
//! [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
|
QSize ShapedClock::sizeHint() const
|
||||||
{
|
{
|
||||||
return QSize(200, 200);
|
return QSize(200, 200);
|
||||||
}
|
}
|
||||||
//! [5]
|
//! [4]
|
||||||
|
@ -19,7 +19,6 @@ protected:
|
|||||||
void mouseMoveEvent(QMouseEvent *event) override;
|
void mouseMoveEvent(QMouseEvent *event) override;
|
||||||
void mousePressEvent(QMouseEvent *event) override;
|
void mousePressEvent(QMouseEvent *event) override;
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPoint dragPosition;
|
QPoint dragPosition;
|
||||||
|
@ -10233,7 +10233,7 @@ void QWidget::ensurePolished() const
|
|||||||
Returns the mask currently set on a widget. If no mask is set the
|
Returns the mask currently set on a widget. If no mask is set the
|
||||||
return value will be an empty region.
|
return value will be an empty region.
|
||||||
|
|
||||||
\sa setMask(), clearMask(), QRegion::isEmpty(), {Shaped Clock Example}
|
\sa setMask(), clearMask(), QRegion::isEmpty()
|
||||||
*/
|
*/
|
||||||
QRegion QWidget::mask() const
|
QRegion QWidget::mask() const
|
||||||
{
|
{
|
||||||
@ -12964,8 +12964,16 @@ QPainter *QWidget::sharedPainter() const
|
|||||||
widget, window system controls in that area may or may not be
|
widget, window system controls in that area may or may not be
|
||||||
visible, depending on the platform.
|
visible, depending on the platform.
|
||||||
|
|
||||||
Note that this effect can be slow if the region is particularly
|
Since QRegion allows arbitrarily complex regions to be created, widget
|
||||||
complex.
|
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
|
\sa windowOpacity
|
||||||
*/
|
*/
|
||||||
@ -13051,7 +13059,7 @@ void QWidgetPrivate::setMask_sys(const QRegion ®ion)
|
|||||||
Masked widgets receive mouse events only on their visible
|
Masked widgets receive mouse events only on their visible
|
||||||
portions.
|
portions.
|
||||||
|
|
||||||
\sa clearMask(), windowOpacity(), {Shaped Clock Example}
|
\sa clearMask(), windowOpacity()
|
||||||
*/
|
*/
|
||||||
void QWidget::setMask(const QBitmap &bitmap)
|
void QWidget::setMask(const QBitmap &bitmap)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user