使用QSignalMapper

3

我尝试制作一个简单的示例来帮助理解PySide中QSignalMapping的概念。我想通过迭代循环动态创建一系列按钮,当用户按下其中一个按钮时,我可以调用一个方法返回与被按下的按钮相应的标签。

from PySide2 import QtWidgets,QtCore,QtGui

fruit_list = ["apples","oranges","pears"]

def fruit_button_event():
    print "this is the pressed button's label"

def main():
    for fruit in fruit_list:
        fruit_button = QtWidgets.QPushButton(fruit)
        fruit_button.clicked.connect(lambda:fruit_button_event())
main()

不要使用 QSignalMapper:请使用 QButtonGroup - ekhumoro
1个回答

6
在下一部分,我将展示一个如何使用QSignalMapper的示例:
from PySide2 import QtCore, QtWidgets


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        lay = QtWidgets.QVBoxLayout(self)

        fruit_list = ["apples","oranges","pears"]
        mapper =  QtCore.QSignalMapper(self)
        mapper.mapped[str].connect(self.fruit_button_event)

        for fruit in fruit_list:
            btn = QtWidgets.QPushButton(fruit)
            btn.clicked.connect(mapper.map)
            mapper.setMapping(btn, fruit)
            lay.addWidget(btn)

    @QtCore.Slot(str)
    def fruit_button_event(self, text):
        print("this is the pressed button's label", text)


if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

请记住,从 Qt 5.10 QSignalMapper 开始已被弃用:

该类已过时。它仅提供旧源代码的支持。我们强烈建议不要在新代码中使用它。


在Python中,可以使用 functools.partial(...) 来获得相同的功能:

from PySide2 import QtCore, QtWidgets
from functools import partial


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        lay = QtWidgets.QVBoxLayout(self)

        fruit_list = ["apples","oranges","pears"]

        for fruit in fruit_list:
            btn = QtWidgets.QPushButton(fruit)
            btn.clicked.connect(partial(self.fruit_button_event, fruit))
            lay.addWidget(btn)

    @QtCore.Slot(str)
    def fruit_button_event(self, text):
        print("this is the pressed button's label", text)

或者使用 lambda:

btn.clicked.connect(lambda text=fruit: self.fruit_button_event(text))

或者 QButtonGroup:

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        lay = QtWidgets.QVBoxLayout(self)

        fruit_list = ["apples","oranges","pears"]
        group = QtWidgets.QButtonGroup(self)
        group.buttonClicked.connect(self.OnButtonClicked)

        for fruit in fruit_list:
            btn = QtWidgets.QPushButton(fruit)
            group.addButton(btn)
            lay.addWidget(btn)

    @QtCore.Slot(QtWidgets.QAbstractButton)
    def OnButtonClicked(self, btn):
        print("this is the pressed button's label", btn.text())

谢谢您提供的示例和建议,有什么替代方案吗?Pyside2 的正确方法是什么? - winteralfs
在C++中建议使用lambda表达式,在Python中我建议使用functools.partial(),我会给你展示一个例子。另一方面,如果我的答案对你有帮助,请不要忘记将其标记为正确的答案,如果你不知道如何操作,请查看[tour],那是最好的感谢方式。 - eyllanesc
在你的 Python 示例中,有没有一种方式可以在 fruit_button_event 方法上不使用装饰器而使其工作? - winteralfs
1
@winteralfs 你可以移除它,装饰器的好处是连接更快,因为连接是在C++中给出的,使用更少的资源,所以我建议使用它们,尽管这不是强制性的。 - eyllanesc
如果我删除它,我需要添加其他代码来替换它吗? - winteralfs
@winteralfs 不用,你没有必要添加任何东西。我建议你在询问之前先尝试和实验一下。 - eyllanesc

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