Вопрос-Ответ

Passing extra arguments through connect

Передача дополнительных аргументов через connect

Возможно ли передавать переменные через слоты, чтобы я мог распечатать определенный текст? Пытаюсь передать переменную 'DiffP', которая определена в другой функции, в слот.

'DiffP' изменяется в зависимости от того, какой файл выбран.

def addLineEdit(self):
try:
self.clearLayout()
self.FileButton ={}
self.Input = {}
self.TotalInput = []
for i in range(int(self.numberLine.text())):
self.FileButton[i] = QtWidgets.QPushButton(self.centralwidget)
self.FileButton[i].setText('Case {}'.format(i+1))
self.FileButton[i].setFlat(True)
self.FileButton[i].setMaximumSize(QtCore.QSize(50, 50))
self.hboxlayout[0].addWidget(self.FileButton[i])
self.FileButton[i].clicked.connect(lambda i=i: self.openfile(i))
self.buttonGroup.addButton(self.FileButton[i],i)
self.buttonGroup.buttonClicked['int'].connect(self.input)

def searchfile(self,dir):
with open(dir) as f:
content = f.readlines()
MainList = content[44].split()
RPM = round(float(MainList[0]), 2)
Ps = round(float(MainList[1]), 2)
Ts = round(float(MainList[2]), 2)
Pd = round(float(MainList[3]), 2)
Ratio = round(Pd / Ps, 2)
DiffP = round(Pd - Ps, 2)
@pyqtSlot(int)
def input(self,button_or_id,DiffP):
if isinstance(button_or_id, int):
if button_or_id == 0:
self.TotalInput[0].setText(str(DiffP))
elif button_or_id == 1:
self.TotalInput[54].setText('1')

def openfile(self,i):
filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Choose file')
dir = filename[0]
directory = os.path.split(dir)[0]
return self.searchfile(dir)
Переведено автоматически
Ответ 1

Проблему можно решить двумя способами:

Использование лямбда-функций:

В общих чертах:

    obj.signal.connect(lambda param1, param2, ..., arg1=val1, arg2= value2, ... : fun(param1, param2,... , arg1, arg2, ....))

def fun(param1, param2,... , arg1, arg2, ....):
[...]

где:


  • param1, param2, ... : являются параметрами, отправляемыми сигналом

  • arg1, arg2, ...: это дополнительные параметры, которые вы хотите потратить

В вашем случае:

    self.buttonGroup.buttonClicked['int'].connect(lambda i: self.input(i, "text"))

@pyqtSlot(int)
def input(self, button_or_id, DiffP):
if isinstance(button_or_id, int):
if button_or_id == 0:
self.TotalInput[0].setText(DiffP)
elif button_or_id == 1:
self.TotalInput[54].setText('1')

Использование functools.partial:

В общих чертах:

    obj.signal.connect(partial(fun, args1, arg2, ... ))

def fun(arg1, arg2, ..., param1, param2, ...):
[...]

где:


  • param1, param2, ... : являются параметрами, отправляемыми сигналом

  • arg1, arg2, ...: это дополнительные параметры, которые вы хотите отправить

В вашем случае:

from functools import partial

[...]
self.buttonGroup.buttonClicked['int'].connect(partial(self.input, "text"))


@pyqtSlot(int)
def input(self, DiffP, button_or_id):
if isinstance(button_or_id, int):
if button_or_id == 0:
self.TotalInput[0].setText(DiffP)
elif button_or_id == 1:
self.TotalInput[54].setText('1')
Ответ 2

Существует проблема с подходами, предложенными в другом ответе,

self.whatever.connect(lambda x: self.method(..., x))        # approach 1 (suboptimal)
self.whatever.connect(functools.partial(self.method, ...)) # approach 2 (suboptimal)

который заключается в том, что они создают ссылочный цикл: self объект содержит ссылку на (или является) объектом с сигналом, который содержит ссылку на функцию или partial объект, который содержит ссылку на self объект. Результатом является то, что (в CPython) ни один из этих объектов не будет собран мусором, когда все остальные ссылки на них исчезнут; они будут собраны только при следующем запуске сборщика циклов. Они, в свою очередь, сохранят в рабочем состоянии все остальные структуры данных Python, на которые они ссылаются, и все объекты Qt, которыми они совместно владеют. Это не совсем утечка памяти, поскольку в конечном итоге все освобождается, но это может быть проблемой.

Ссылочного цикла не будет, если вы напишете

self.whatever.connect(self.method)

поскольку как в PyQt, так и в PySide, connect имеет особый случай для объектов метода, связанных с Python: он содержит только слабую ссылку на объект "self". functools.partial не возвращает объект определенного типа, который connect распознает. Но вы можете определить замену для functools.partial, которая возвращает этот тип, так что вы получите поведение, исключающее цикл:

def partial_bound_method(bound_method, *args, **kwargs):
f = functools.partialmethod(bound_method.__func__, *args, **kwargs)
# NB: the seemingly redundant lambda is needed to ensure the correct result type
return (lambda *args: f(*args)).__get__(bound_method.__self__)

...

self.whatever.connect(partial_bound_method(self.method, ...)) # approach 2' (better)

Смотрите Этот более длинный ответ для получения более подробной информации.

2024-01-02 08:58 python python-3.x pyqt