2

我有一个 QPushButton,以及一个连接到它的“按下”信号的插槽,如下所示:

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

Slot 是这样实现的:

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() Slot 将在之后被调用。为什么禁用按钮不会阻止我单击它?

我已经尝试在进入插槽时断开信号并在之后重新连接,但没有任何帮助。

4

2 回答 2

1

因为鼠标按下事件被放置到事件循环中,并等到您的SnapshotClicked()方法完成,此时按钮再次启用。

QCoreApplication::processEvents()一个简单的解决方案是在之后立即调用emit,这将导致在按钮仍处于禁用状态时处理按下事件。或者,您可以让该DoSnapshotWork()方法在完成时发出一个信号,然后启用该按钮并解除对信号的阻塞。

还,

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

repaint()强制重绘小部件,同时通过事件循环update()调用repaint()- 不要同时调用它们。

于 2013-03-28T08:27:38.210 回答
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()。

于 2013-03-28T08:35:33.980 回答