1. 程式人生 > >QT——如何在不同執行緒中對同一個UI介面進行操作

QT——如何在不同執行緒中對同一個UI介面進行操作

最近在做一個介面,這個介面的功能有兩個:

(1)點選開始按鈕,進入迴圈,等待裝置插入;

(2)點選停止按鈕,中止等待過程。

對於“開始”按鈕,很自然的就寫了個while,在迴圈裡等待裝置插入。但是這就出現一個問題:這個執行緒就直接陷進了while裡,就是說點選“取消”沒有反應了。

為了解決這個問題,我建立了一個執行緒,使整個迴圈過程在這個新開的執行緒裡完成(這裡記作執行緒1),而原執行緒則等待取消按鈕按下(記作執行緒2)。

這又產生了一個新的問題,在迴圈過程中,我怎麼輸出我的提示資訊?

一開始我的想法是直接在這個新開的執行緒裡(執行緒1),呼叫介面的資訊提示框(這個元件屬於執行緒2)。

void MainWindow::on_pushButton_clicked()
{
    pthread_create(&moving_thread, NULL, a, (void *)this);
    //建立執行緒,把當前介面的指標當作引數傳入
}
void* MainWindow::a(void* arg)
{
    MainWindow *pointer = (MainWindow *)arg;
    pointer->run(arg);//在run裡我用arg指標訪問了UI的元件,執行時提示段錯誤
}

後來查資料知道,執行緒之間共享的是堆、棧、全域性變數、靜態變數、函式(C++中的靜態成員函式是肯定共享的,非靜態成員函式不知道)等,而非靜態、非全域性變數是不共享的,執行緒2中的資訊提示框正好是非靜態、非全域性的,因此即使執行緒1使用指向這介面的指標訪問資訊提示框,只要不是線上程2中訪問這個屬於執行緒2的元件,就會發生段錯誤。

接著,我想到了QT的訊號與槽的機制:

(1)線上程1中,在需要顯示資訊時傳送“資訊欄顯示”訊號;

(2)執行緒2接收該訊號,在資訊提示框中顯示資訊;

(3)按下取消按鈕,執行緒2發出“結束"訊號;

(4)執行緒1接收訊號,結束本執行緒。

而這裡有個問題,訊號與槽該怎麼連線?準確來說,是哪個物件的訊號連線到哪個物件的槽?

首先,我試著線上程1中,在connect裡填了兩個this指標:

void* MainWindow::a(void* arg)
{
    MainWindow *pointer = new MainWindow;
    pointer->run(arg);
}
void MainWindow::run(void* arg)
{
    connect(this,SIGNAL(message()),
            this,SLOT(get()));
}    

發現執行緒2中的資訊欄沒有任何變化,思考後發現是this指標指向執行緒1的物件,所以這個connect是把這個新的MainWindow例項裡的訊號和槽連起來了。我想要的,應該是執行緒1中的訊號,連線到執行緒2中的槽。因此,作以下改動:

connect(this,SIGNAL(message()),
                (MainWindow *)arg,SLOT(get()));

修改後可實現預期效果。