问题
我想使用 aQTimer来更新绘制进度条的派生QSplashScreen项(使用绘制命令,而不是小部件)来估计程序何时开始运行。
必要时,这发生在exec调用QCoreApplication. 通过在第二个线程中放置一个计时器,并在启动屏幕中调用一个更新进度并重新绘制小部件的函数,我已经在 X11 和 Windows 上让它工作(仅在发布模式下)。但是,这在调试模式下不起作用,因为它会产生以下错误:
"ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread."
我并不真正担心这个断言,因为代码在发布时不会崩溃,它只是一个闪屏,但是我需要能够在调试中运行程序,所以我想要么a)重构代码所以它不会触发断言,或者 b) 禁用此特定断言。
试过:
- 使用
update()而不是repaint().finish这不会导致断言,但它也不会重新绘制,因为主线程太忙于加载共享库等,并且在我准备好在启动屏幕上调用之前不会处理计时器事件. - 从
QTimer主循环开始。结果与上述相同。 - 使用
QT::QueuedConnection. 结果相同。 
主要的
#include <QApplication>
#include <QtGui>
#include <QTimer>
#include <QThread>
#include "mySplashScreen.h"
#include "myMainWindow.h"       // contains a configure function which takes a
                                // LONG time to load.
int main( int argc, char* argv[] )
{
    // estimate the load time
    int previousLoadTime_ms = 10000;
    QApplication a(argc, argv);
    MySplashScreen* splash = new MySplashScreen(QPixmap(":/splashScreen"));
    // progress timer. Has to be in a different thread since the
    // qApplication isn't started.
    QThread* timerThread = new QThread;
    QTimer* timer = new QTimer(0); // _not_ this!
    timer->setInterval(previousLoadTime_ms / 100.0);
    timer->moveToThread(timerThread);
    QObject::connect(timer, &QTimer::timeout, [&]
    {
        qApp->processEvents(); splash->incrementProgress(1); 
    });
    QObject::connect(timerThread, SIGNAL(started()), timer, SLOT(start()));
    timerThread->start();
    splash->show();
    a.processEvents();
    myMainWindow w;
    QTimer::singleShot(0, [&]
    {
        // This will be called as soon as the exec() loop starts.
        w.configure();  // this is a really slow initialization function
        w.show();
        splash->finish(&w);
        timerThread->quit();
    });
    return a.exec();
}
启动画面
#include <QSplashScreen>
class MySplashScreen : public QSplashScreen
{ 
    Q_OBJECT
public:
    MySplashScreen(const QPixmap& pixmap = QPixmap(), Qt::WindowFlags f = 0) 
        : QSplashScreen(pixmap, f)
    {
        m_pixmap = pixmap;
    }
    virtual void drawContents(QPainter *painter) override
    {
        QSplashScreen::drawContents(painter);
        // draw progress bar
    }
public slots:
    virtual void incrementProgress(int percentage)
    {
        m_progress += percentage;
        repaint();
    }
protected:
    int m_progress = 0;
private:
    QPixmap m_pixmap;
};
我的主窗口
#include <QMainWindow>
class myMainWindow : public QMainWindow
{
public:
    void configure()
    {
        // Create and configure a bunch of widgets. 
        // This takes a long time.
    }
}