Modernize shapedclock example
Relying on the hard clipping of QRegion widget masks to create non-rectangular windows is a solution from a bygone era. The result looks horrible with today's eyes, particularly on a high-dpi screen. Update the example to create smooth anti-aliased edges using translucent window bacground. Task-number: QTBUG-64229 Change-Id: I8859d61177d2a2dc446632c23f27f42050e0d7c7 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Reviewed-by: Andy Shaw <andy.shaw@qt.io>
This commit is contained in:
parent
03dc30acca
commit
191ac31598
@ -29,16 +29,18 @@
|
|||||||
\example widgets/shapedclock
|
\example widgets/shapedclock
|
||||||
\title Shaped Clock Example
|
\title Shaped Clock Example
|
||||||
\ingroup examples-widgets
|
\ingroup examples-widgets
|
||||||
\brief The Shaped Clock example shows how to apply a widget mask to a top-level
|
\brief The Shaped Clock example shows how to apply a translucent background
|
||||||
widget to produce a shaped window.
|
and a widget mask to a top-level widget to produce a shaped window.
|
||||||
|
|
||||||
\borderedimage shapedclock-example.png
|
\borderedimage shapedclock-example.png
|
||||||
|
|
||||||
Widget masks are used to customize the shapes of top-level widgets by restricting
|
Widget masks are used to customize the shapes of top-level widgets by
|
||||||
the available area for painting. On some window systems, setting certain window flags
|
restricting the area available for painting and mouse input. Using a
|
||||||
will cause the window decoration (title bar, window frame, buttons) to be disabled,
|
translucent background facilitates partially transparent windows and smooth
|
||||||
allowing specially-shaped windows to be created. In this example, we use this feature
|
edges. On most window systems, setting certain window flags will cause the
|
||||||
to create a circular window containing an analog clock.
|
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.
|
||||||
|
|
||||||
Since this example's window does not provide a \uicontrol File menu or a close
|
Since this example's window does not provide a \uicontrol File menu or a close
|
||||||
button, we provide a context menu with an \uicontrol Exit entry so that the example
|
button, we provide a context menu with an \uicontrol Exit entry so that the example
|
||||||
@ -52,8 +54,10 @@
|
|||||||
|
|
||||||
\snippet widgets/shapedclock/shapedclock.h 0
|
\snippet widgets/shapedclock/shapedclock.h 0
|
||||||
|
|
||||||
The \l{QWidget::paintEvent()}{paintEvent()} implementation is the same as that found
|
The \l{QWidget::paintEvent()}{paintEvent()} implementation is the same as
|
||||||
in the \c AnalogClock class. We implement \l{QWidget::sizeHint()}{sizeHint()}
|
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
|
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.
|
handler for resize events. This allows us to update the mask if the clock is resized.
|
||||||
|
|
||||||
@ -70,9 +74,11 @@
|
|||||||
|
|
||||||
\snippet widgets/shapedclock/shapedclock.cpp 0
|
\snippet widgets/shapedclock/shapedclock.cpp 0
|
||||||
|
|
||||||
We inform the window manager that the widget is not to be decorated with a window
|
We request a transparent window by setting the Qt::WA_TranslucentBackground
|
||||||
frame by setting the Qt::FramelessWindowHint flag on the widget. As a result, we need
|
widget attribute. We inform the window manager that the widget is not to be
|
||||||
to provide a way for the user to move the clock around the screen.
|
decorated with a window frame by setting the Qt::FramelessWindowHint flag
|
||||||
|
on the widget. As a result, we need to provide a way for the user to move
|
||||||
|
the clock around the screen.
|
||||||
|
|
||||||
Mouse button events are delivered to the \c mousePressEvent() handler:
|
Mouse button events are delivered to the \c mousePressEvent() handler:
|
||||||
|
|
||||||
@ -94,14 +100,20 @@
|
|||||||
widget is moved to the point given by subtracting the \c dragPosition from the current
|
widget is moved to the point given by subtracting the \c dragPosition from the current
|
||||||
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 given for completeness. See the
|
The \c paintEvent() function is mainly the same as described in the
|
||||||
\l{Analog Clock Example}{Analog Clock} example for a description of the process used
|
\l{Analog Clock Example}{Analog Clock} example. The one addition is that we
|
||||||
to render the clock.
|
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.
|
||||||
|
|
||||||
\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()
|
In the \c resizeEvent() handler, we re-use some of the code from the \c
|
||||||
to determine the region of the widget that is visible to the user:
|
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
|
\snippet widgets/shapedclock/shapedclock.cpp 4
|
||||||
|
|
||||||
@ -121,6 +133,12 @@
|
|||||||
|
|
||||||
\section1 Notes on Widget Masks
|
\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
|
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
|
made to suit the most unconventionally-shaped windows, and even allow widgets to be
|
||||||
displayed with holes in them.
|
displayed with holes in them.
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
ShapedClock::ShapedClock(QWidget *parent)
|
ShapedClock::ShapedClock(QWidget *parent)
|
||||||
: QWidget(parent, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint)
|
: QWidget(parent, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint)
|
||||||
{
|
{
|
||||||
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
QTimer *timer = new QTimer(this);
|
QTimer *timer = new QTimer(this);
|
||||||
connect(timer, &QTimer::timeout, this, QOverload<>::of(&ShapedClock::update));
|
connect(timer, &QTimer::timeout, this, QOverload<>::of(&ShapedClock::update));
|
||||||
timer->start(1000);
|
timer->start(1000);
|
||||||
@ -122,6 +123,10 @@ void ShapedClock::paintEvent(QPaintEvent *)
|
|||||||
painter.translate(width() / 2, height() / 2);
|
painter.translate(width() / 2, height() / 2);
|
||||||
painter.scale(side / 200.0, side / 200.0);
|
painter.scale(side / 200.0, side / 200.0);
|
||||||
|
|
||||||
|
painter.setPen(Qt::NoPen);
|
||||||
|
painter.setBrush(palette().window());
|
||||||
|
painter.drawEllipse(QPoint(0, 0), 98, 98);
|
||||||
|
|
||||||
painter.setPen(Qt::NoPen);
|
painter.setPen(Qt::NoPen);
|
||||||
painter.setBrush(hourColor);
|
painter.setBrush(hourColor);
|
||||||
|
|
||||||
@ -168,6 +173,6 @@ void ShapedClock::resizeEvent(QResizeEvent * /* event */)
|
|||||||
//! [5]
|
//! [5]
|
||||||
QSize ShapedClock::sizeHint() const
|
QSize ShapedClock::sizeHint() const
|
||||||
{
|
{
|
||||||
return QSize(100, 100);
|
return QSize(200, 200);
|
||||||
}
|
}
|
||||||
//! [5]
|
//! [5]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user