Python pyqt:如何禁用QPushButton的多次单击?

Python pyqt:如何禁用QPushButton的多次单击?,python,pyqt4,qpushbutton,Python,Pyqt4,Qpushbutton,当我按下按钮时,会运行一些耗时的代码。当它运行时,我希望避免该按钮对任何进一步的单击作出响应。代码完成后,可以重新启用按钮,并应处理进一步的单击 我正试图通过以下方式实现这一点: self.btn.blockSignals(True) self.btn.setEnabled(False) ... code ... self.btn.blockSignals(True) self.btn.setEnabled(False) 但是,如果我快速点击这个按钮10次,代码将

当我按下按钮时,会运行一些耗时的代码。当它运行时,我希望避免该按钮对任何进一步的单击作出响应。代码完成后,可以重新启用按钮,并应处理进一步的单击

我正试图通过以下方式实现这一点:

   self.btn.blockSignals(True)
   self.btn.setEnabled(False)
   ... code ...
   self.btn.blockSignals(True)
   self.btn.setEnabled(False)
但是,如果我快速点击这个按钮10次,代码将执行10次

实际上,我会将耗时的代码转移到另一个线程。(编辑:但问题仍然是一样的——我认为???。事实上,这解决了它。请参阅。)

当某个按钮正在运行时,如何阻止或忽略对该按钮的单击

以下是我的代码的最低版本:

import time
import sys
from PyQt4 import QtGui

class Example(QtGui.QWidget):

    def __init__(self):
        super(Example, self).__init__()
        self.initUI()

    def initUI(self):
        grid = QtGui.QGridLayout()
        self.setLayout(grid)
        self.btn = QtGui.QPushButton('Count')
        grid.addWidget(self.btn, 1, 1)
        self.txt1 = QtGui.QTextEdit()
        grid.addWidget(self.txt1, 1, 2)
        self.btn.clicked.connect(self.click)
        self.count = 0
        self.show()

    def click(self):
        # Here I want to block any further click in the button, but it is
        # not working - clicking it 10 times quickly will run this 10 times...
        self.btn.blockSignals(True)
        self.btn.setEnabled(False)
        time.sleep(2)  # time consuming code...
        self.count += 1
        self.txt1.append(str(self.count))
        self.repaint()
        self.btn.setEnabled(True)
        self.btn.blockSignals(False)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

如果将长运行代码放在线程中,那么一旦线程启动,控件可以返回到主事件循环,这将允许gui立即更新

以下是基于您的示例的基本演示:

import sys
from PyQt4 import QtGui, QtCore

class Thread(QtCore.QThread):
    def run(self):
        QtCore.QThread.sleep(2)

class Example(QtGui.QWidget):
    def __init__(self):
        super(Example, self).__init__()
        self.initUI()

    def initUI(self):
        grid = QtGui.QGridLayout()
        self.setLayout(grid)
        self.btn = QtGui.QPushButton('Count')
        grid.addWidget(self.btn, 1, 1)
        self.txt1 = QtGui.QTextEdit()
        grid.addWidget(self.txt1, 1, 2)
        self.btn.clicked.connect(self.click)
        self.thread = Thread()
        self.thread.finished.connect(lambda: self.btn.setEnabled(True))
        self.show()

    def click(self):
        self.txt1.append('click')
        if not self.thread.isRunning():
            self.btn.setEnabled(False)
            self.thread.start()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

如果将长运行代码放在线程中,那么一旦线程启动,控件可以返回到主事件循环,这将允许gui立即更新

以下是基于您的示例的基本演示:

import sys
from PyQt4 import QtGui, QtCore

class Thread(QtCore.QThread):
    def run(self):
        QtCore.QThread.sleep(2)

class Example(QtGui.QWidget):
    def __init__(self):
        super(Example, self).__init__()
        self.initUI()

    def initUI(self):
        grid = QtGui.QGridLayout()
        self.setLayout(grid)
        self.btn = QtGui.QPushButton('Count')
        grid.addWidget(self.btn, 1, 1)
        self.txt1 = QtGui.QTextEdit()
        grid.addWidget(self.txt1, 1, 2)
        self.btn.clicked.connect(self.click)
        self.thread = Thread()
        self.thread.finished.connect(lambda: self.btn.setEnabled(True))
        self.show()

    def click(self):
        self.txt1.append('click')
        if not self.thread.isRunning():
            self.btn.setEnabled(False)
            self.thread.start()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

我不熟悉PyQt,但我发现了以下链接:可能您必须在
self.btn.setEnabled(False)
下面添加
QCoreApplication::processEvents()
。在我的系统上,
processEvents
不起作用,但线程起作用。@ekhumoro您的意思是将代码移动到新线程吗?那么blockSignals(False)是否也应该移动到线程?@Raf。我用一个简单的例子给出了答案。不需要阻止信号,但我添加了一个检查以查看线程是否正在运行。我不熟悉PyQt,但我发现了以下链接:可能您必须在
self.btn.setEnabled(False)
下面添加
QCoreApplication::processEvents()
。在我的系统上,
processEvents
不起作用,但是一个线程就可以了。你是说把代码移到一个新线程?那么blockSignals(False)是否也应该移动到线程?@Raf。我用一个简单的例子给出了答案。没有必要阻止信号,但我已经添加了一个检查,以查看线程是否正在运行。太棒了,谢谢!我忽略了这个重要的概念:永远不要用耗时的任务来阻止主事件循环。太棒了,谢谢!我忽略了这个重要的概念:永远不要用耗时的任务阻塞主事件循环。