したがって、メカニズムは、スレッド内からウィジェットを変更できないというものです。そうしないと、アプリケーションが次のようなエラーでクラッシュします。
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マクロが呼び出されるたびに、親のウィジェットが更新されます。接続関数が適切に構成されている場合、出力されたパラメーターを自動的に取得し、コールバック関数の入力パラメーターに格納します。
これがどのように機能するか:
- クラスを初期化します
emit
通常の方法ではスレッドからデータを返すことができないため、スレッドの終了時に発生する処理と、「返された」別名データを処理するためのスロットを設定します。
->start()
次に、呼び出し(QThreadにハードコードされている)を使用してスレッドを実行し、 QT.run()
はクラス内のハードコードされた名前memberfunctionを探します
emit
resultReadyマクロが子スレッドで呼び出されるたびに、QStringデータが、スレッド間で行き詰まった共有データ領域に隠されます。
- QTは、resultReadyがトリガーされたことを検出し、関数UpdateScreen(QString)に、run()から発行されたQStringを親スレッドの実際の関数パラメーターとして受け入れるように通知します。
- これは、emitキーワードがトリガーされるたびに繰り返されます。
基本的に、connect()
関数は、データが前後に移動できるように、子スレッドと親スレッドの間のインターフェイスです。
注: resultReady()を定義する必要はありません。QT内部に存在するマクロのように考えてください。