Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsplashscreen.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include "qapplication.h"
8#include "qpainter.h"
9#include "qpixmap.h"
10#include "qtextdocument.h"
11#include "qtextcursor.h"
12#include <QtGui/qscreen.h>
13#include <QtGui/qwindow.h>
14#include <QtCore/qdebug.h>
15#include <QtCore/qdeadlinetimer.h>
16#include <QtCore/qthread.h>
17#include <private/qwidget_p.h>
18
19#include <chrono>
20
21using namespace std::chrono_literals;
22
23QT_BEGIN_NAMESPACE
24
25class QSplashScreenPrivate : public QWidgetPrivate
26{
27 Q_DECLARE_PUBLIC(QSplashScreen)
28public:
29 QPixmap pixmap;
30 QString currStatus;
31 QColor currColor;
32 int currAlign;
33
34 inline QSplashScreenPrivate();
35
36 void handlePaintEvent();
37};
38
39/*!
40 \class QSplashScreen
41 \brief The QSplashScreen widget provides a splash screen that can
42 be shown during application startup.
43
44 \inmodule QtWidgets
45
46 A splash screen is a widget that is usually displayed when an
47 application is being started. Splash screens are often used for
48 applications that have long start up times (e.g. database or
49 networking applications that take time to establish connections) to
50 provide the user with feedback that the application is loading.
51
52 The splash screen appears in the center of the screen. It may be
53 useful to add the Qt::WindowStaysOnTopHint to the splash widget's
54 window flags if you want to keep it above all the other windows on
55 the desktop.
56
57 Some X11 window managers do not support the "stays on top" flag. A
58 solution is to set up a timer that periodically calls raise() on
59 the splash screen to simulate the "stays on top" effect.
60
61 The most common usage is to show a splash screen before the main
62 widget is displayed on the screen. This is illustrated in the
63 following code snippet in which a splash screen is displayed and
64 some initialization tasks are performed before the application's
65 main window is shown:
66
67 \snippet qsplashscreen/main.cpp 0
68
69 The user can hide the splash screen by clicking on it with the
70 mouse. For mouse handling to work, call QApplication::processEvents()
71 periodically during startup.
72
73
74 It is sometimes useful to update the splash screen with messages,
75 for example, announcing connections established or modules loaded
76 as the application starts up:
77
78 \snippet code/src_gui_widgets_qsplashscreen.cpp 0
79
80 QSplashScreen supports this with the showMessage() function. If you
81 wish to do your own drawing you can get a pointer to the pixmap
82 used in the splash screen with pixmap(). Alternatively, you can
83 subclass QSplashScreen and reimplement drawContents().
84
85 In case of having multiple screens, it is also possible to show the
86 splash screen on a different screen than the primary one. For example:
87
88 \snippet qsplashscreen/main.cpp 2
89*/
90
91/*!
92 Construct a splash screen that will display the \a pixmap.
93
94 There should be no need to set the widget flags, \a f, except
95 perhaps Qt::WindowStaysOnTopHint.
96*/
97QSplashScreen::QSplashScreen(const QPixmap &pixmap, Qt::WindowFlags f)
98 : QWidget(*(new QSplashScreenPrivate()), nullptr, Qt::SplashScreen | Qt::FramelessWindowHint | f)
99{
100 setPixmap(pixmap); // Does an implicit repaint
101}
102
103/*!
104 \overload
105 \since 5.15
106
107 This function allows you to specify the screen for your splashscreen. The
108 typical use for this constructor is if you have multiple screens and
109 prefer to have the splash screen on a different screen than your primary
110 one. In that case pass the proper \a screen.
111*/
112QSplashScreen::QSplashScreen(QScreen *screen, const QPixmap &pixmap, Qt::WindowFlags f)
113 : QWidget(*(new QSplashScreenPrivate()), nullptr, Qt::SplashScreen | Qt::FramelessWindowHint | f)
114{
115 Q_D(QSplashScreen);
116 d->setScreen(screen);
117 setPixmap(pixmap);
118}
119
120/*!
121 Destructor.
122*/
123QSplashScreen::~QSplashScreen()
124{
125}
126
127/*!
128 \reimp
129*/
130void QSplashScreen::mousePressEvent(QMouseEvent *)
131{
132 hide();
133}
134
135/*!
136 This overrides QWidget::repaint(). It differs from the standard repaint
137 function in that it also calls QCoreApplication::processEvents() to ensure
138 the updates are displayed, even when there is no event loop present.
139*/
140void QSplashScreen::repaint()
141{
142 QWidget::repaint();
143 QCoreApplication::processEvents();
144}
145
146/*!
147 \fn QSplashScreen::messageChanged(const QString &message)
148
149 This signal is emitted when the message on the splash screen
150 changes. \a message is the new message and is a null-string
151 when the message has been removed.
152
153 \sa showMessage(), clearMessage()
154*/
155
156
157
158/*!
159 Draws the \a message text onto the splash screen with color \a
160 color and aligns the text according to the flags in \a alignment.
161 This function calls repaint() to make sure the splash screen is
162 repainted immediately. As a result the message is kept up
163 to date with what your application is doing (e.g. loading files).
164
165 \sa Qt::Alignment, clearMessage(), message()
166*/
167void QSplashScreen::showMessage(const QString &message, int alignment,
168 const QColor &color)
169{
170 Q_D(QSplashScreen);
171 d->currStatus = message;
172 d->currAlign = alignment;
173 d->currColor = color;
174 emit messageChanged(d->currStatus);
175 repaint();
176}
177
178/*!
179 \since 5.2
180
181 Returns the message that is currently displayed on the splash screen.
182
183 \sa showMessage(), clearMessage()
184*/
185
186QString QSplashScreen::message() const
187{
188 Q_D(const QSplashScreen);
189 return d->currStatus;
190}
191
192/*!
193 Removes the message being displayed on the splash screen
194
195 \sa showMessage()
196 */
197void QSplashScreen::clearMessage()
198{
199 d_func()->currStatus.clear();
200 emit messageChanged(d_func()->currStatus);
201 repaint();
202}
203
204static bool waitForWidgetMapped(QWidget *widget)
205{
206 auto isMapped = [widget] {
207 const auto handle = widget->windowHandle();
208 return handle && handle->isVisible();
209 };
210
211 if (isMapped())
212 return true;
213 QDeadlineTimer timer(1s);
214 do {
215 QCoreApplication::processEvents(QEventLoop::AllEvents, timer);
216 QCoreApplication::sendPostedEvents();
217 if (isMapped())
218 return true;
219 QThread::sleep(10ms);
220 } while (!timer.hasExpired());
221 return false;
222}
223
224/*!
225 Makes the splash screen wait until the widget \a mainWin is displayed
226 before calling close() on itself.
227*/
228
229void QSplashScreen::finish(QWidget *mainWin)
230{
231 if (mainWin) {
232 if (!mainWin->windowHandle())
233 mainWin->createWinId();
234 waitForWidgetMapped(mainWin);
235 }
236 close();
237}
238
239/*!
240 Sets the pixmap that will be used as the splash screen's image to
241 \a pixmap.
242*/
243void QSplashScreen::setPixmap(const QPixmap &pixmap)
244{
245 Q_D(QSplashScreen);
246 d->pixmap = pixmap;
247 setAttribute(Qt::WA_TranslucentBackground, pixmap.hasAlpha());
248
249 const QRect r(QPoint(), pixmap.deviceIndependentSize().toSize());
250 resize(r.size());
251
252 move(screen()->geometry().center() - r.center());
253 if (isVisible())
254 repaint();
255}
256
257/*!
258 Returns the pixmap that is used in the splash screen. The image
259 does not have any of the text drawn by showMessage() calls.
260*/
261const QPixmap QSplashScreen::pixmap() const
262{
263 return d_func()->pixmap;
264}
265
266/*!
267 \internal
268*/
269inline QSplashScreenPrivate::QSplashScreenPrivate() : currAlign(Qt::AlignLeft)
270{
271}
272
273/*!
274 Draw the contents of the splash screen using painter \a painter.
275 The default implementation draws the message passed by showMessage().
276 Reimplement this function if you want to do your own drawing on
277 the splash screen.
278*/
279void QSplashScreen::drawContents(QPainter *painter)
280{
281 Q_D(QSplashScreen);
282 painter->setPen(d->currColor);
283 QRect r = rect().adjusted(5, 5, -5, -5);
284 if (Qt::mightBeRichText(d->currStatus)) {
285 QTextDocument doc;
286#ifdef QT_NO_TEXTHTMLPARSER
287 doc.setPlainText(d->currStatus);
288#else
289 doc.setHtml(d->currStatus);
290#endif
291 doc.setTextWidth(r.width());
292 QTextCursor cursor(&doc);
293 cursor.select(QTextCursor::Document);
294 QTextBlockFormat fmt;
295 fmt.setAlignment(Qt::Alignment(d->currAlign));
296 fmt.setLayoutDirection(layoutDirection());
297 cursor.mergeBlockFormat(fmt);
298 const QSizeF txtSize = doc.size();
299 if (d->currAlign & Qt::AlignBottom)
300 r.setTop(r.height() - txtSize.height());
301 else if (d->currAlign & Qt::AlignVCenter)
302 r.setTop(r.height() / 2 - txtSize.height() / 2);
303 painter->save();
304 painter->translate(r.topLeft());
305 doc.drawContents(painter);
306 painter->restore();
307 } else {
308 painter->drawText(r, d->currAlign, d->currStatus);
309 }
310}
311
312void QSplashScreenPrivate::handlePaintEvent()
313{
314 Q_Q(QSplashScreen);
315 QPainter painter(q);
316 painter.setRenderHints(QPainter::SmoothPixmapTransform);
317 painter.setLayoutDirection(q->layoutDirection());
318 if (!pixmap.isNull())
319 painter.drawPixmap(QPoint(), pixmap);
320 q->drawContents(&painter);
321}
322
323/*! \reimp */
324bool QSplashScreen::event(QEvent *e)
325{
326 Q_D(QSplashScreen);
327
328 switch (e->type()) {
329 case QEvent::Paint:
330 d->handlePaintEvent();
331 break;
332 case QEvent::Show:
333 waitForWidgetMapped(this);
334 break;
335 default:
336 break;
337 }
338
339 return QWidget::event(e);
340}
341
342QT_END_NAMESPACE
343
344#include "moc_qsplashscreen.cpp"
friend class QPainter
friend class QWidget
Definition qpainter.h:432
static bool waitForWidgetMapped(QWidget *widget)