有没有办法真正确保QSplashScreen已经在屏幕上重新绘制了?
Is there any way to make really sure QSplashScreen has been repainted on the screen?
我有一个问题,在带有Xorg(Ubuntu 14.04)和Qt 5.5.1的Linux上,QSplashScreen
直到我进入事件循环才被绘制。即使我多次调用QApplication::processEvents()
,即使在 1000 次调用之后,它仍然没有被绘制,尽管窗口已经在屏幕上,保留了应用程序启动前存在的原始像素,因此实际上是不可见的*。从这个答案中,我得到了一个调用QApplication::processEvents()
的定时循环的想法,如下所示:
#include <QThread>
#include <QApplication>
#include <QSplashScreen>
int main(int argc, char** argv)
{
QApplication a(argc,argv);
QSplashScreen splash;
splash.show();
splash.showMessage("Loading...");
// The hack to try to ensure that splash screen is repainted
for(int i=0;i<30;++i)
{
QThread::usleep(1e3);
a.processEvents();
}
QThread::usleep(5e6); // simulate slow loading process
splash.showMessage("Finished");
return a.exec();
}
上面的代码主动休眠 30 毫秒,试图重新绘制QSplashScreen
。这对我有用,但我不确定它是否总是可以工作,例如在繁忙/慢速的 CPU 或任何其他条件下(30 次迭代的神奇值是根据经验发现的)。
另一种通常相当侵入性的方法是在另一个线程中进行所有必要的加载,只是为了确保主线程中的QSplashScreen
确实具有活动的消息队列。由于需要大量重做主程序,这看起来不太好的解决方案。
那么,有没有办法确保QSplashScreen
已被重新粉刷,使其窗口不包含垃圾,然后才能进行长时间的阻塞加载过程?
*当我在启动画面后面移动一个窗口时,我发现了这一点
避免不可知的先验魔术超时的一种方法是等待一个确切的事件:绘画事件。在 X11 上,它似乎有延迟。要完成此等待,我们必须对QSplashScreen
进行子类化并覆盖QSplashScreen::paintEvent()
,如下所示:
#include <QThread>
#include <QApplication>
#include <QSplashScreen>
class MySplashScreen : public QSplashScreen
{
bool painted=false;
void paintEvent(QPaintEvent* e) override
{
QSplashScreen::paintEvent(e);
painted=true;
}
public:
void ensureFirstPaint() const
{
while(!painted)
{
QThread::usleep(1e3);
qApp->processEvents();
}
}
};
int main(int argc, char** argv)
{
QApplication a(argc,argv);
MySplashScreen splash;
splash.show();
splash.showMessage("Loading...");
splash.ensureFirstPaint();
QThread::usleep(5e6); // simulate slow loading process
splash.showMessage("Finished");
return a.exec();
}
解决方案相当简单:保持事件循环运行,直到重新绘制窗口。这应该在没有任何旋转的情况下完成,即您不应该使用任何显式超时。
#include <QtWidgets>
class EventSignaler : public QObject {
Q_OBJECT
QEvent::Type m_type;
protected:
bool eventFilter(QObject *src, QEvent *ev) override {
if (ev->type() == m_type)
emit hasEvent(src);
return false;
}
public:
EventSignaler(QEvent::Type type, QObject *object) :
QObject(object), m_type(type) {
object->installEventFilter(this);
}
Q_SIGNAL void hasEvent(QObject *);
};
int execUntilPainted(QWidget *widget) {
EventSignaler painted{QEvent::paint, widget};
QObject::connect(&painted, &EventSignaler::hasEvent, qApp, &QCoreApplication::quit);
return qApp->exec();
}
int main(int argc, char **argv) {
QApplication app{argc, argv};
MySplashScreen splash;
EventSignaler painted{QEvent::Paint, &splash};
splash.show();
splash.showMessage("Loading...");
execUntilPainted(&splash);
QThread::sleep(5); // simulate slow loading process
splash.showMessage("Finished");
return app.exec();
}
#include "main.moc"
相关文章:
- QuadTree只在窗口的右上角绘制
- 绘制旋转的三角形
- flutter:即使shouldRepaint()返回true,自定义画家也不会重新绘制
- 如何在QT中的自定义视频小工具t上绘制矩形
- 如何在Visual Basic中使用矩形函数OpenGL绘制矩形
- 无法使用VAO和EBO(openGL)绘制多个对象
- 为什么我的点没有在 OpenGL 中绘制鼠标所在的位置?
- 绘制顺时针三角形,重新排序点
- 在顶点着色器中使用 OpenGl 的未声明标识符,我在顶点着色器中绘制三角形时遇到问题
- SFML 文本未绘制在窗口上
- 如何在快板的屏幕中显示子位图的绘制?
- 如何绘制自定义形状的元素?
- QPainter 将 QBrush 设置为 在 QT/C++ 中绘制文本
- 除非重新绘制大小,否则SDL_Texture在调整大小后呈现黑色
- C++ WinApi 绘制图像.jpg到新窗口
- 如何获取绘制点的新坐标
- 如果新图像中的原始像素为黑色,则Qt绘制一个蓝色像素
- 在 OpenGL 中每帧绘制新的全屏图像的最快方法是什么?
- MFC在最大化窗口处绘制新窗口
- 如何编辑SFML源代码来添加一个新的可绘制对象