使用 QSignalMapper

Posted

技术标签:

【中文标题】使用 QSignalMapper【英文标题】:Using QSignalMapper 【发布时间】:2018-09-11 20:04:31 【问题描述】:

我试图做一个简单的例子来帮助理解 QSignalMapping 的概念在 PySide 中是如何工作的。我想通过循环迭代来动态创建一系列按钮,当用户按下其中一个按钮时,我可以激活一个方法,该方法为按下的按钮返回适当的标签。

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。 【参考方案1】:

在下一部分中,我将展示一个如何使用 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++ 中建议在 python 中使用 lambdas 我建议使用 functools.partial(),我将向您展示一个示例。另一方面,如果我的回答对你有帮助,别忘了标记为正确,如果你不知道怎么做,请查看tour,这是最好的感谢方式。 在您的 Python 示例中,有没有一种方法可以在没有在 fruit_button_event 方法上使用装饰器的情况下工作? @winteralfs 你可以删除它,装饰器的优点是连接速度更快,因为连接是在 C++ 中给出的,因为使用的资源更少,所以我建议使用它们,尽管它不是强制性的. 如果我删除它,我是否必须添加任何其他代码来替换它?

以上是关于使用 QSignalMapper的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)