PySide-6.6:单击的信号将额外的布尔参数发送到插槽

问题描述 投票:0回答:1

我刚刚升级了 PySide6(从 6.2.2 开始,PySide6==6.6.0),一个新行为对我的 GUI 程序造成了严重破坏。在我有

clicked
信号的每个地方,连接的插槽都会收到额外的 bool==False 参数。

x = QPushButton('New', clicked = self.new_append_title)
# ..... add x to my gui

def new_append_title(self, *args, **kwargs): 
    print(f' Args: {args}' )
    print(f' Kwargs: {kwargs}' )

这回来了
参数:(假,) 夸格斯:{}

以前的早期版本我没有得到任何争论。我可以修复我的所有代码,因此需要一个额外的虚拟参数,但是有人知道这里发生了什么吗?我还更新了我的要求中的其他一些内容 - 比如迁移到 python 3.12,所以它可能不是 PySide 问题...


为了回应 ekhumoro,我实际上是想在这里发送和争论,并且我已经尝试了我能想到的所有排列。

self.save_button.clicked.connect(lambda *, row=row: self.save_row(row))

TypeError:SemanticTable.save_row() 缺少 1 个必需的位置参数:“已检查”

唯一对我有用的是:

self.save_button.clicked.connect(functools.partial(self.save_row, row)))

为此,我需要将 save_row 容纳为:

def save_row(self, row, checked):

检查的布尔参数排在最后,这让我完全困惑。但我并不完全理解偏颇。很多事情我不明白。

python pyside2 signals-slots pyside6
1个回答
2
投票

我确实可以重现不同版本的 PySide 之间行为上的这种奇怪差异。然而,与我之前对此主题的回答不同,当前的问题涉及如何建立信号连接。看来 PySide 在这方面一直高度不一致,而 PyQt 则可靠得多(至少在我测试的几个版本中)。

与当前情况的重要区别在于,通过

clicked
关键字参数建立的信号连接的行为方式与通过
connect
方法建立的显式连接不同。下面详细介绍了整个令人遗憾的混乱情况,但这里最直接的信息是:为了让您的 PySide 代码面向未来,永远不要依赖于默默删除的默认信号参数。始终假设某个未来版本将开始发送默认参数,并相应地保护您的插槽。这就是 PyQt5/6 一直以来的行为方式,而且 PySide6 似乎最终也会这样做。在我自己的代码中,我最常使用仅关键字参数来解决此问题,如下所示:

button.connect(self.slot)
...
def slot(self, *, mykeyword=True):

正如您将在下面看到的,在我测试的所有版本的 PySide 和 PyQt 中,其行为都是相同的,并且在 API 更改和一般代码改动方面可能是干扰最小的。 (但另请参阅我之前的答案了解其他几个选项 - 有一些附带条件)。


现在是血淋淋的细节。

下面是暴露问题的测试脚本。正如您将从输出中看到的,PySide2 和 PySide6 显示不同的行为,具体取决于信号连接的方式以及所使用的精确版本。好消息是,在通过

clicked
关键字参数建立连接时,PySide-6.6.0 显示了与 PyQt5/6 相同的行为。坏消息是,使用
connect
显示出与 PySide2 相同的不一致行为。另请注意,PySide2 本身在处理槽参数方面表现出一些差异:使用
connect(slot)
时,第一个参数被覆盖,而使用
clicked=slot
时,则不会。

测试脚本

import sys

if (pkg := sys.argv[1]) == 'ps2':
   from PySide2 import QtCore, QtWidgets
elif pkg == 'ps6':
    from PySide6 import QtCore, QtWidgets
elif pkg == 'pq6':
    from PyQt6 import QtCore, QtWidgets
else:
    from PyQt5 import QtCore, QtWidgets

try:
    KEYWORD = sys.argv[2] == 'kw'
except:
    KEYWORD = False

print(f'{QtCore.__package__} (Qt-{QtCore.qVersion()}), keyword={KEYWORD}')

app = QtWidgets.QApplication(['Test'])

def slot1(n=2): print(f'slot1: {n=!r}')
def slot2(*args, n=2): print(f'slot2: {args=!r}, {n=!r}')
def slot3(x, n=2): print(f'slot3: {x=!r}, {n=!r}')
def slot4(*, n=2): print(f'slot4: {n=!r}')

for index in range(1, 5):
    slot = globals()[f'slot{index}']
    if KEYWORD:
        button = QtWidgets.QPushButton(clicked=slot)
    else:
        button = QtWidgets.QPushButton()
        button.clicked.connect(slot)
    button.click()

输出

PySide2:

$ python3 test-signals.py ps2
PySide2 (Qt-5.15.11), keyword=False
slot1: n=False
slot2: args=(), n=2
TypeError: slot3() missing 1 required positional argument: 'x'
slot4: n=2

$ python3 test-signals.py ps2 kw
PySide2 (Qt-5.15.11), keyword=True
slot1: n=2
slot2: args=(), n=2
TypeError: slot3() missing 1 required positional argument: 'x'
slot4: n=2

PySide6:

$ python3 test-signals.py ps6
PySide6 (Qt-6.2.2), keyword=False
slot1: n=False
slot2: args=(), n=2
TypeError: slot3() missing 1 required positional argument: 'x'
slot4: n=2

$ python3 test-signals.py ps6 kw
PySide6 (Qt-6.2.2), keyword=True
slot1: n=2
slot2: args=(), n=2
TypeError: slot3() missing 1 required positional argument: 'x'
slot4: n=2

$ python3 test-signals.py ps6
PySide6 (Qt-6.6.0), keyword=False
slot1: n=False
slot2: args=(), n=2
TypeError: slot3() missing 1 required positional argument: 'x'
slot4: n=2

$ python3 test-signals.py ps6 kw
PySide6 (Qt-6.6.0), keyword=True
slot1: n=False
slot2: args=(False,), n=2
slot3: x=False, n=2
slot4: n=2

PyQt5/6:

$ python3 test-signals.py pq6
PyQt6 (Qt-6.6.0), keyword=False
slot1: n=False
slot2: args=(False,), n=2
slot3: x=False, n=2
slot4: n=2

$ python3 test-signals.py pq6 kw
PyQt6 (Qt-6.6.0), keyword=True
slot1: n=False
slot2: args=(False,), n=2
slot3: x=False, n=2
slot4: n=2

$ python3 test-signals.py pq5
PyQt5 (Qt-5.15.11), keyword=False
slot1: n=False
slot2: args=(False,), n=2
slot3: x=False, n=2
slot4: n=2

$ python3 test-signals.py pq5 kw
PyQt5 (Qt-5.15.11), keyword=True
slot1: n=False
slot2: args=(False,), n=2
slot3: x=False, n=2
slot4: n=2
© www.soinside.com 2019 - 2024. All rights reserved.