2013-05-11 7 views
9

私はマルチスレッドのqtアプリケーションを持っています。私がmainwindow.cppでいくつかのプロセスを実行しているとき、同時に、私はmainwindow.uiを他のスレッドから更新したい。Qt - メインウィンドウを第2のスレッドで更新しています

私はmythread.h

#ifndef MYTHREAD_H 
#define MYTHREAD_H 
#include <QThread> 
#include "mainwindow.h" 

class mythread : public QThread 
{ 
    public: 
     void run(); 
     mythread(MainWindow* ana); 
    MainWindow* ana; 
private: 

}; 

#endif // MYTHREAD_H 

mythread.cpp

mythread::mythread(MainWindow* a) 
{ 
    cout << "thread created" << endl; 
     ana = a; 
} 

void mythread::run() 
{ 
    QPixmap i1 (":/notes/pic/4mdodiyez.jpg"); 
    QLabel *label = new QLabel(); 
    label->setPixmap(i1); 
    ana->ui->horizontalLayout_4->addWidget(label); 


} 

持っていますが、問題は、私は到達できない、ということであるana->ui->horizontalLayout_4->addWidget(label);

私はそれをどのように行うことができますか?

+0

私が好きで、締め切りまで10分がある場合は、作業者からuiを更新する必要があるときはいつでも、メインウィンドウにダミーのボタンを追加します(幅と高さ0)。ワーカーでclick()イベントを発生させ、そのボタンのクリックハンドラを上書きして更新を行います。 – cristid9

答えて

12

が、問題は、私は ana-> UI-> horizo​​ntalLayout_4-> addWidget(ラベル)に達することができない、ということです。

メインウィンドウのスロットにUIの変更を加え、スレッド信号をそのスロットに接続すると、それはうまくいく可能性があります。私はメインスレッドだけがQtのUIにアクセスできると思う。したがって、GUI機能が必要な場合は、そこに存在しなければならず、他のスレッドからのみ通知することができます。

OK、これは簡単な例です。ところで、あなたのシナリオは実際にはQThreadを拡張する必要はありません - あなたが本当にしなければならない限り、それをやっていない方が良いです。この例では、私が代わりにQObjectベースの労働者と通常のQThreadを使用する理由ですが、あなたはQThreadをサブクラス化した場合のコンセプトは同じです。

メインUI:

class MainUI : public QWidget 
{ 
    Q_OBJECT 

public: 
    explicit MainUI(QWidget *parent = 0): QWidget(parent) { 
     layout = new QHBoxLayout(this); 
     setLayout(layout); 
     QThread *thread = new QThread(this); 
     GUIUpdater *updater = new GUIUpdater(); 
     updater->moveToThread(thread); 
     connect(updater, SIGNAL(requestNewLabel(QString)), this, SLOT(createLabel(QString))); 
     connect(thread, SIGNAL(destroyed()), updater, SLOT(deleteLater())); 

     updater->newLabel("h:/test.png"); 
    } 

public slots: 
    void createLabel(const QString &imgSource) { 
     QPixmap i1(imgSource); 
     QLabel *label = new QLabel(this); 
     label->setPixmap(i1); 
     layout->addWidget(label); 
    } 

private: 
    QHBoxLayout *layout; 
}; 
...とワーカー・オブジェクト:

class GUIUpdater : public QObject { 
    Q_OBJECT 

public: 
    explicit GUIUpdater(QObject *parent = 0) : QObject(parent) {}  
    void newLabel(const QString &image) { emit requestNewLabel(image); } 

signals:  
    void requestNewLabel(const QString &); 
}; 

ワーカー・オブジェクトが作成され、別のスレッドに移動し、その後、ラベルを作成するスロットに接続され、そのnewLabelメソッドが呼び出され、0を放出するだけのラッパーであり、これは信号を入力し、パスを画像に渡します。この信号は、ワーカーオブジェクト/スレッドから画像パスパラメータとともにメインUIスロットに渡され、新しいラベルがレイアウトに追加されます。

ワーカーオブジェクトは親なしで別のスレッドに移動できるように作成されているため、スレッド破棄信号もワーカーdeleteLater()スロットに接続します。

+0

接続の例を教えてください。私は接続の要素を決定することはできません。 – abby

+0

@abby - 必要なものを達成するための簡単な例を追加しました。 – dtech

+0

私はこれを試しましたが、イメージをロードする代わりにnewLabelText()にいくつかの計算を入れました(newLabel()、requestNewLabel()を修正して、背景の仕事(作者が彼/彼女がやりたいと示唆しているように)。実際には、ちょっとだけ全部をフリーズしています(LCD Numberコントロールと、それが実際にフリーズしているかどうかを確認するためにカウントアップして結果をLCDに表示するボタンをつけています)。つまり、非常に大きな画像を読み込んだ場合、UIがブロックされる可能性があります。 – rbaleksandar

3

まず第一に、"you're doing it wrong"。通常、QObjectから派生したクラスを作成し、Qthreadからクラスを派生させる代わりに、そのクラスを新しいスレッドオブジェクトに移動したいとします。

ここで質問の内容を直接理解することはできません。主なGUIスレッドのui要素を別のスレッドから取得します。あなたはconnectsignalの2番目のスレッドからメインスレッドのslotにしなければなりません。このシグナル/スロット接続を介して必要なデータを渡すことはできますが、ui要素を直接変更することはできません(アプリのフロントエンドをバックエンドとは別にしたい場合は、まったく嫌です)。全体の多くのためのチェックアウトQtのシグナルとスロットdocumentation詳しく

+0

ワーカースレッドからmainwindow.uiを更新する方法はありますか?私は本当にそれが必要なので。 – abby

+0

あなたは別のスレッドからの信号に接続されていたスロットのui要素を更新します – g19fanatic

+0

ああ悪名高い「あなたは間違っているよ」ブログ記事。私は彼に強く反対します。 http://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html –

1

どうすればいいですか?

あなたはすでに何をしているべきかについての回答を得ていますが、理由はありません。その理由を追加します。

他のスレッドからGUI要素を変更しない理由は、GUI要素が通常thread-safeではないためです。これは、メインのGUIスレッドとワーカースレッドの両方がUIを更新した場合、発生したときの順序を特定できないことを意味します。

一般的にデータを読み取る場合、これは場合によっては問題ありません(条件のチェックなど)が、一般的には大文字小文字にすることは望ましくありません。データを書き込むために、これはほとんどいつも "無作為に"発生する非常にストレスの多いバグの原因です。

GUIロジックを1つのスレッドに制限し、対話するための信号を発してレースコンディションの問題を解決するだけでなく、コードをきちんと区画化することも強く求められています。プレゼンテーションロジック(表示ビット)とデータ処理ロジックをきれいに分離することができ、2つのロジックをより簡単に維持できます。

この段階であなたは考えるかもしれません:このスレッドのビジネスはですfarrrrrrあまりにも多くの仕事!私はそれを避けるだけです。なぜこれが悪い考えであるかを知るには、単純なプログレスバーを使ってファイルコピープログラムを単一のスレッドに実装し、コピーの距離を教えてください。大きなファイルで実行します。 Windowsでは、しばらくすると、アプリケーションは「白くなる」(またはXPでは灰色になると思う)、「応答しない」と表示されます。これは非常に文字通り起こっていることです。

GUIアプリケーションは、内部的には大部分が「1つの大きなループ」の処理とメッセージのディスパッチのバリエーションに取り組んでいます。たとえば、Windowsでは、これらのメッセージに対する応答時間が測定されます。応答に時間がかかりすぎると、Windowsはそれが死んでいると判断し、引き継ぎます。 This is documented in GetMessage()

シグナル/スロット(イベントドリブンモデル)は基本的には手に入る方法です - これを考えるもう一つの方法は、スレッドが生成することが完全に容認できるということですUIの「イベント」 - 進行状況の更新など。

関連する問題