У меня есть класс класса QWidget
, содержащий класс QLabel
. Класс генерирует QCheckbox
в QVBox
. Я пытаюсь подключить каждый флажок к методу nameCheckBox
, который обновит QLabel
, чтобы отобразить заголовок последнего отмеченного поля. Однако, когда флажок фактически снят/установлен, он всегда определяется как снятый. Также возвращаемое имя всегда является последним созданным флажком. Я не понимаю, где моя ошибка. Вот мой код:
import sys
from PyQt4 import QtCore
from PyQt4.QtGui import *
from MenusAndToolbars import MenuWindow
class checkBoxWidget(QWidget):
"""
This widget has a QVBox which contains a QLabel and QCheckboxes.
Qcheckbox number is connected to the label.
"""
def __init__(self):
QWidget.__init__(self)
self.__setUI()
def __setUI(self):
vbox = QVBoxLayout(self)
label = QLabel('Last clicked button: ' + "None", self)
vbox.addWidget(label)
listCB = []
for i in range(10):
listCB.append( QCheckBox('CheckBox Nb. ' + str(i+1) ) )
listCB[i].stateChanged.connect(lambda: self.nameCheckBox(label, listCB[i]) )
vbox.addWidget( listCB[i] )
def nameCheckBox(self, label, checkBox):
if checkBox.isChecked():
print "Checked: " + checkBox.text()
label.setText('Last clicked button: ' + checkBox.text())
else:
print "Unchecked: " + checkBox.text()
def main():
app = QApplication(sys.argv)
window = QMainWindow()
window.setCentralWidget( checkBoxWidget() )
window.show()
#window = WidgetWindow()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
РЕДАКТИРОВАТЬ 1
Я нашел несколько «хакерских» решений.
РЕШЕНИЕ 1. Создание функции обратного вызова помогает:
def callBack(self, list, index, label):
return lambda: self.nameCheckBox(label, list[index])
Затем я подключаю сигнал QCheckbox().stateChanged
таким образом:
listCB[i].stateChanged.connect( self.callBack(listCB, i, label) )
РЕШЕНИЕ 2: с помощью модуля partial
:
Сначала мы импортируем модуль:
from functools import partial
Тогда подключение сигнала делается так:
listCB[i].stateChanged.connect( partial( self.nameCheckBox, label, listCB[i] ) )
Однако я хотел бы использовать лямбда-выражение в одной строке. Особенно хотелось бы понять, как это работает. По ссылкам я понял, что проблема связана с областью лямбда. Как мне посоветовал Олег Припин, я написал:
listCB[i].stateChanged.connect(lambda i=i: self.nameCheckBox(label, listCB[i]) )
Здесь переменная i
является новой. Однако моя первоначальная проблема остается. Затем я попробовал это из любопытства:
listCB[i].stateChanged.connect( lambda label=label, listCB=listCB, i=i: self.nameCheckBox(label, listCB[i] ) )
Но я получаю следующую ошибку:
Traceback (most recent call last):
Checked: CheckBox Nb. 2
File "Widgets.py", line 48, in <lambda>
listCB[i].stateChanged.connect( lambda label=label, listCB=listCB, i=i: self.nameCheckBox(label, listCB[i] ) )
File "Widgets.py", line 59, in nameCheckBox
label.setText('Last clicked button: ' + checkBox.text())
AttributeError: 'int' object has no attribute 'setText'
Здесь кажется, что правильная кнопка распознается, когда она не отмечена. Однако кажется, что новая переменная label
рассматривается как int? Что здесь происходит?