1

問題

QTimerを使用して、プログレス バーを描画する派生を更新しQSplashScreen(ウィジェットではなくペイント コマンドを使用)、プログラムの実行開始時期を予測したいと考えています。

必然的に、これは のexec呼び出しの前に発生しQCoreApplicationます。これをX11 と Windowsの両方で (リリース モードでのみ) 動作させるには、2 番目のスレッドにタイマーを配置し、スプラッシュ スクリーンで進行状況を更新してウィジェットを再描画する関数を呼び出します。ただし、次のエラーが発生するため、これはデバッグ モードでは機能しません。

"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;
};

MyMainWindow

#include <QMainWindow>

class myMainWindow : public QMainWindow
{
public:

    void configure()
    {
        // Create and configure a bunch of widgets. 
        // This takes a long time.
    }
}
4

1 に答える 1