そのため、スレッド内からウィジェットを変更することはできません。そうしないと、次のようなエラーでアプリケーションがクラッシュします:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
Segmentation fault
これを回避するには、次のように、スレッド化された作業をクラスにカプセル化する必要があります。
class RunThread:public QThread{
Q_OBJECT
public:
void run();
signals:
void resultReady(QString Input);
};
run() には、実行したいすべての作業が含まれています。
親クラスには、データを生成する呼び出し関数と QT ウィジェット更新関数があります:
class DevTab:public QWidget{
public:
void ThreadedRunCommand();
void DisplayData(QString Input);
...
}
次に、スレッドを呼び出すために、いくつかのスロットを接続します。
void DevTab::ThreadedRunCommand(){
RunThread *workerThread = new RunThread();
connect(workerThread, &RunThread::resultReady, this, &DevTab::UpdateScreen);
connect(workerThread, &RunThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
接続関数は 4 つのパラメーターを取り、パラメーター 1 は原因クラス、パラメーター 2 はそのクラス内のシグナルです。パラメータ 3 はコールバック関数のクラス、パラメータ 4 はクラス内のコールバック関数です。
次に、子スレッドにデータを生成する関数を作成します:
void RunThread::run(){
QString Output="Hello world";
while(1){
emit resultReady(Output);
sleep(5);
}
}
次に、親関数にウィジェットを更新するためのコールバックがあります:
void DevTab::UpdateScreen(QString Input){
DevTab::OutputLogs->append(Input);
}
その後、実行すると、発行マクロがスレッドで呼び出されるたびに、親のウィジェットが更新されます。接続関数が適切に構成されている場合、発行されたパラメーターが自動的に取得され、コールバック関数の入力パラメーターに格納されます。
仕組み:
<オール>emit
をどうするか 通常の方法ではスレッドからデータを返すことができないため、ted データ->start()
でスレッドを実行します 呼び出し (QThread にハードコードされています)、QT はハードコードされた名前 .run()
を探します クラスのメンバー関数emit
resultReady マクロが子スレッドで呼び出され、QString データが共有データ領域に格納され、スレッド間で行き詰まる
基本的に connect()
関数は、子スレッドと親スレッドの間のインターフェースであり、データが行き来できるようにします。
注: resultReady() を定義する必要はありません。 QT 内部に存在するマクロのようなものと考えてください。
Qt で重要なことは、しなければならないことです。 メイン スレッドである GUI スレッドからのみ Qt GUI を操作します。
そのため、これを行う適切な方法は 通知 することです ワーカーからのメイン スレッドであり、メイン スレッドのコードは実際にテキスト ボックス、進行状況バー、またはその他のものを更新します。
これを行う最善の方法は、posix スレッドの代わりに QThread を使用し、Qt シグナル を使用することだと思います スレッド間の通信用。これは、thread_func
の代わりとなるワーカーになります。 :
class WorkerThread : public QThread {
void run() {
while(1) {
// ... hard work
// Now want to notify main thread:
emit progressChanged("Some info");
}
}
// Define signal:
signals:
void progressChanged(QString info);
};
ウィジェットでスロットを定義します .h:のシグナルと同じプロトタイプを持つ
class MyWidget : public QWidget {
// Your gui code
// Define slot:
public slots:
void onProgressChanged(QString info);
};
.cpp でこの関数を実装します:
void MyWidget::onProgressChanged(QString info) {
// Processing code
textBox->setText("Latest info: " + info);
}
スレッドを生成したい場所 (ボタンのクリック時):
void MyWidget::startWorkInAThread() {
// Create an instance of your woker
WorkerThread *workerThread = new WorkerThread;
// Connect our signal and slot
connect(workerThread, SIGNAL(progressChanged(QString)),
SLOT(onProgressChanged(QString)));
// Setup callback for cleanup when it finishes
connect(workerThread, SIGNAL(finished()),
workerThread, SLOT(deleteLater()));
// Run, Forest, run!
workerThread->start(); // This invokes WorkerThread::run in a new thread
}
シグナルとスロットを接続した後、 emit progressChanged(...)
でスロットを発行します ワーカー スレッドではメイン スレッドにメッセージが送信され、メイン スレッドはそのシグナルに接続されているスロットを呼び出します onProgressChanged
追記私はまだコードをテストしていないので、どこか間違っている場合は自由に編集を提案してください