2013-03-28 27 views
2

我有一個QPushButton,以及連接到它的「按下」信號那樣的槽:調用兩次Qt的按鈕插槽,儘管禁用

connect(&m_oBtnSnapshot, SIGNAL(pressed()), this, 
    SLOT(SnapshotClicked())); 

插槽爲這樣的實現:

void 
GUI::SnapshotClicked() 
{ 
    m_oBtnSnapshot.blockSignals(true); 
    m_oBtnSnapshot.setDisabled(true); 

    m_oBtnBenchmark.repaint(); 
    m_oBtnBenchmark.update(); 


    emit(DoSnapshotWork()); 

    m_oBtnSnapshot.setDisabled(false); 
    m_oBtnSnapshot.blockSignals(false); 
} 

正如你所看到的,當我點擊它時,我禁用了按鈕,並在所有事情完成時重新啓用它。 讓我們假設DoSnapshotWork()函數需要5秒鐘...雖然這5秒鐘按鈕被禁用,但如果我點擊它,SnapshotClicked()插槽將被調用。爲什麼禁用按鈕不會阻止我點擊它?

我已經嘗試斷開信號進入插槽並重新連接後,但沒有任何幫助。

回答

1

GUI::SnapshotClicked()是GUI線程的一部分,這意味着,它運行時,您的GUI無法訪問。我假設,信號DoSnapshotWork()連接了一個插槽,在Qt::QueuedConnection(或Qt::AutoConnection)的另一個線程中運行。在這種情況下,發出此信號是異步的,這意味着GUI::SnapshotClicked()在插槽完成之前就已經完成。我想你應該做這樣的事情:

gui.h

public slots: 
    void onReleaseButton(); 

gui.cpp

void 
GUI::SnapshotClicked() 
{ 
    m_oBtnSnapshot.setDisabled(true); 

    m_oBtnBenchmark.repaint(); 
    m_oBtnBenchmark.update(); 

    emit(DoSnapshotWork()); 
} 

void 
GUI::onReleaseButton() 
{ 
    m_oBtnSnapshot.setDisabled(false); 
} 

別的地方:

connect(shapshotWorker, SIGNAL(releaseButton()), gui, SLOT(onReleaseButton())); 

... 

DoSnapshotWork() 
{ 
... 

emit releaseButton(); 
} 

PS:你需要一個很好的理由使用QPushButton :: pressed()()信號。在大多數情況下,你會更喜歡QPushButton :: clicked()。

+0

爲什麼?推動和點擊之間的區別?我完全像你說的那樣,但是當按鈕被禁用時,我仍然能夠「點擊」它。它被禁用,但發出DoSnapshotWork()信號。 – Hafnernuss 2013-03-28 08:54:50

+0

我現在想通了。不知何故,當將DoSnapshotWork()插槽連接到其他線程(GUI所在的位置,按鈕被按下)時,我錯過了Qt :: QueuedConnection標誌。我不知道爲什麼,但這不知何故導致兩次插槽。感謝提示! – Hafnernuss 2013-03-28 09:04:05

+0

當您在按鈕區域內按下鼠標左鍵時(並且每次以後都會進入此區域,而不釋放鼠標按鍵),會按下()按鈕。當在按鈕區域內釋放鼠標左鍵時,按下左鍵後,點擊()會被省略。你可以編寫一個簡單的應用程序來感受不同之處。 P.S:非常歡迎:) – Amartel 2013-03-28 09:11:50

1

由於鼠標按下事件放置在事件循環中,並等到您的SnapshotClicked()方法完成,屆時該按鈕將再次啓用。

一個簡單的解決方案是在emit之後立即致電QCoreApplication::processEvents(),這將導致按鈕事件在按鈕仍處於禁用狀態時進行處理。或者您可以讓DoSnapshotWork()方法在完成時發出信號,並啓用該按鈕並取消阻止信號。

此外,

m_oBtnBenchmark.repaint(); 
m_oBtnBenchmark.update(); 

repaint()重新繪製控件強制,而update()通過調用事件循環repaint() - 不叫他們倆。

+0

我試過你的processEvents()方法,在發出DoSnapshotWork()後面,它沒有改變任何東西。但感謝提示重繪和更新。 – Hafnernuss 2013-03-28 08:55:33