Использование QSignalMapper

Я попытался сделать простой пример, чтобы помочь понять, как концепция 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()

person winteralfs    schedule 11.09.2018    source источник
comment
Не используйте QSignalMapper: используйте QButtonGroup.   -  person ekhumoro    schedule 12.09.2018


Ответы (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)

Или с лямбдой:

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())
person eyllanesc    schedule 11.09.2018
comment
Спасибо за пример и совет, какая есть альтернатива? Правильный подход для Pyside2? - person winteralfs; 12.09.2018
comment
@winteralfs в C++ рекомендуется использовать лямбда-выражения, в python я рекомендую использовать functools.partial(), я покажу вам пример. С другой стороны, если мой ответ поможет вам, не забудьте отметить его как правильный, если вы не знаете, как это сделать, просмотрите тур, это лучший способ отблагодарить. - person eyllanesc; 12.09.2018
comment
В вашем примере с Python есть ли способ, которым он будет работать без использования декоратора в методе fruit_button_event? - person winteralfs; 12.09.2018
comment
@winteralfs вы можете удалить его, преимущество декоратора в том, что соединение происходит быстрее, так как соединение дается на C ++, так как используется меньше ресурсов, поэтому я рекомендую использовать их, хотя это не обязательно. - person eyllanesc; 12.09.2018
comment
Если я удалю его, мне нужно добавить какой-либо другой код, чтобы заменить его? - person winteralfs; 12.09.2018
comment
@winteralfs нет, вам не нужно ничего добавлять, я рекомендую вам попробовать, поэкспериментируйте, прежде чем спрашивать. - person eyllanesc; 12.09.2018