16718


QtでC#のbackgroundworkerのようなものを実現するにはどうすればいいのでしょうか


CC BY-SA 3.0
2015-09-17T12:26:11.307
16713
2015-10-27T07:52:38.537
9130
question
c++ qt
QtでC#のbackgroundworkerのようなもの


`BackgroundWorker`のどのような機能を再現したいかを、もうすこし具体的に質問していただいたほうが回答しやすいと思います。

単純に別のスレッドでタスクを実行したいということであれば、あまり細かい制御はできませんが、`QRunnable`というクラスを利用できます。

[code]

    #include <QCoreApplication>
    #include <QRunnable>
    #include <QThreadPool>
    #include <QDebug>
    
    class BackgroundWorker : public QRunnable {
    private:
        void run() {
            for (int i = 0; i < 5; ++i) {
                qDebug() << "tick" << i;
                QThread::sleep(1);
            }
        }
    };
    
    int main(int argc, char *argv[]) {
        QCoreApplication a(argc, argv);
    
        BackgroundWorker *worker = new BackgroundWorker();
        worker->setAutoDelete(true);
    
        QThreadPool::globalInstance()->start(worker);
    
        return a.exec();
    }
    
[/code]

<http://doc.qt.io/qt-5/qrunnable.html>  
<http://doc.qt.io/qt-5/qthreadpool.html>


CC BY-SA 3.0
2015-09-17T13:22:01.680
16715
2015-09-17T13:22:01.680
3639
16713
answer


既に回答にあるような、QRunnableを使用する方法のほか、QThreadを使う方法もあります。

例として、メインウィンドウにボタンが1個置いてあるアプリケーションを想定します。

QThreadを継承したクラスを作成します。

**MyWorker.h**

[code]

    #ifndef MYWORKER_H
    #define MYWORKER_H
    
    #include <QThread>
    
    class MyWorker : public QThread {
        Q_OBJECT
    protected:
        virtual void run();
    signals:
        void notifyCompleted();
    };
    
    #endif // MYWORKER_H
    
[/code]

**MyWorker.cpp**

[code]

    #include "MyWorker.h"
    
    void MyWorker::run()
    {
        msleep(2000); // あんなことやこんなことを行う
        emit notifyCompleted();
    }
    
[/code]

`run()`の中で時間のかかる処理を行い、完了したら、メインスレッドに通知するためのシグナルを実行します。上の例で、`notifyCompleted()`は、ヘッダファイルで`signals`と定義されており、この関数の中身は、Qtのmocが自動生成してくれます。Qt
Creatorで開発する場合は、特に意識する必要はありません。

次は、スレッドの生成元です。

このオブジェクトを`MainWindow`のメンバに持たせます。

[code]

    private:
        MyWorker worker;
    
[/code]

ボタンが押されたら、スレッドを開始します。（既に実行中ならその旨表示します）

[code]

    void MainWindow::on_pushButton_clicked()
    {
        if (worker.isRunning()) {
            setWindowTitle("running");
        } else {
            worker.start();
            setWindowTitle("started");
        }
    }
    
[/code]

処理が完了した通知を受け取るスロットを作っておきます。

`MainWindow`のヘッダファイルでメンバを宣言する際、Qt特有の`slots`という指定が必要です。

[code]

    private slots:
        void onCompleted();
    
[/code]

関数本体（いわゆるイベントハンドラ）は普通のメンバ関数と同じように書けます。

[code]

    void MainWindow::onCompleted()
    {
        setWindowTitle("completed");
    }
    
[/code]

`MainWindow`のコンストラクタで、シグナルとスロットを結びつけます。

[code]

    connect(&worker, SIGNAL(notifyCompleted()), this, SLOT(onCompleted()));
    
[/code]

connectをすることで、別スレッドからメインスレッドに通知を送ることができるようになります。


CC BY-SA 3.0
2015-09-17T13:38:23.857
16718
2015-09-17T13:38:23.857
3337
16713
answer


他の方が書かれているように用途にもよりますが、  
単に別スレッドで処理を実行するだけであれば`QtConcurrent::run()`の使用が簡単でおすすめです。

<http://doc.qt.io/qt-5/qtconcurrentrun.html>


CC BY-SA 3.0
2015-10-27T07:52:38.537
18126
2015-10-27T07:52:38.537
8334
16713
answer