PyQt小部件connect()和disconnect()

33

根据条件,我希望将一个按钮连接/重新连接到不同的函数。

假设我有一个按钮:

myButton = QtGui.QPushButton()

例如,假设我检查是否存在互联网连接。

if connected == True:
    myButton.clicked.connect(function_A)

elif connected == False:
    myButton.clicked.connect(function_B)

首先,我想将一个按钮与其之前连接的任何功能断开连接,然后重新分配/重新连接到另一个函数(函数_A或函数_B)。 其次,我已经注意到,在重新连接按钮后,需要多点击一次按钮才能选择新功能。在将按钮重新连接到另一个函数后,它仍然尝试运行以前连接按钮的函数(重新连接之前)。请给出建议。 预先感谢!

稍后编辑:

似乎 widget 的.disconnect() 方法可用于从其连接的函数中断开按钮。

myButton.disconnect()

不幸的是,如果小部件未连接到任何函数,.disconnect()会抛出一个错误。我正在使用Try/Except来解决这个问题。但我更想使用一种更优雅的解决方案...

遗憾的是,如果小部件未连接到任何函数,.disconnect()会抛出一个错误。我正在使用Try/Except来解决这个问题。但我更想使用一种更优雅的解决方案...

try: myButton.clicked.disconnect() 
except Exception: pass

1
引发了什么异常?有点奇怪。请注意,myButton.disconnect()与myButton.clicked.disconnect()是不同的,你指的是哪一个? - Oliver
@Schollii。它引发了一个“TypeError”。而异常并不奇怪:事实上,这是非常可取的。它被引入的原因是,旧式的连接和断开信号的方法会默默地失败,这可能会隐藏很多潜在的错误。简而言之,在Python中引发异常更加符合Pythonic风格。 - ekhumoro
7
感谢解释。我只是不明白为什么一个应该断开所有信号的函数会将“当前没有连接”视为异常行为。另一方面,如果你尝试去断开某个信号,而这个信号不存在,那么我可以理解这被视为需要标记的异常情况。但无论如何,这并不重要,感谢提供信息。 - Oliver
3个回答

35

如果您需要在多个位置重新连接信号,则可以定义一个通用的实用函数,如下所示:

def reconnect(signal, newhandler=None, oldhandler=None):        
    try:
        if oldhandler is not None:
            while True:
                signal.disconnect(oldhandler)
        else:
            signal.disconnect()
    except TypeError:
        pass
    if newhandler is not None:
        signal.connect(newhandler)

...

if connected:
    reconnect(myButton.clicked, function_A)
else:
    reconnect(myButton.clicked, function_B)

(注意:循环是为了安全地断开特定处理程序的连接,因为它可能已经连接了多次,而disconnect(slot)每次只会删除一个连接。)


1
那么如果你执行 signal.disconnect() - 没有给出 slot 参数 - 那么这个信号将会从所有它的槽位断开连接?换句话说,在这种情况下不需要循环操作吗? - K.Mulier
2
@K.Mulier 这就是文档中所说的,如果您看到不同的行为,那么这将是一个错误。通过检查sender.receivers(sender.signal)的输出,很容易测试这一点。 - ekhumoro

10

试试这个:

from PyQt4 import QtGui as gui

app = gui.QApplication([])

myButton = gui.QPushButton()

def function_A():
    myButton.clicked.disconnect() #this disconnect all!
    myButton.clicked.connect(function_B)
    print 'function_A'

def function_B():
    myButton.clicked.disconnect(function_B) #this disconnect function_B
    myButton.clicked.connect(function_A)
    print 'function_B'

myButton.clicked.connect(function_A)
myButton.setText("Click me!")
myButton.show()

app.exec_()

你知道如何检查小部件是否连接到函数吗?我发现有一个 .isSignalConnected() 小部件方法。不幸的是,我不知道如何使用它... - alphanumeric
你应该阅读这篇文章,我认为没有希望,但如果你找到了方法,请告诉我 ;) - Alvaro Fuentes

0

使用contextlib.suppress可以简洁地处理3.4+版本的问题:

with contextlib.suppress(RuntimeError):
    button.clicked.disconnect()
button.connect(func_a if condition else func_b)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接