1

我有一个问题,在带有 Xorg(Ubuntu 14.04)和 Qt 5.5.1QSplashScreen的 Linux 上直到我进入事件循环才被绘制。即使我QApplication::processEvents()多次调用,它仍然没有被绘制,即使在 1000 次调用之后,虽然窗口已经在屏幕上,保留了应用程序启动之前存在的原始像素,因此实际上是不可见的*。从这个答案中,我想到了使用 call 的定时循环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已经被重新粉刷,使其窗口不包含垃圾,然后才能继续进行长时间的阻塞加载过程呢?


*当我将一个窗口移到启动画面后面时,我发现了这一点

4

2 回答 2

0

避免不可知的先验魔法超时的一种方法是等待一个确切的事件:绘制事件。在 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();
}
于 2018-04-27T14:04:56.253 回答
0

解决方案相当简单:保持事件循环运行,直到重新绘制窗口。这应该在没有任何旋转的情况下完成,即您不应该使用任何显式超时。

#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"
于 2018-04-29T04:19:41.267 回答