3

QWidgetを含むクラスクラスがありQLabelます。クラスはQCheckbox'es を生成し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 : callBack 関数を作成するとうまくいきます。

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] ) )

ただし、ラムダ式を1行で使用したいと思います。特に、それがどのように機能するかを理解したいと思います。リンクをたどると、問題はラムダスコープに関するものであることがわかりました。Oleh Prypin がアドバイスしてくれたように、私は次のように書いています。

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 と見なされるようですか? そこで何が起こるの?

4

1 に答える 1

2
lambda: self.nameCheckBox(label,  listCB[i])

変数 にバインドしますi。つまり、 の値はi、作成時ではなく、ラムダが呼び出された時点のものになります。この場合、常に 9です。
可能な修正:

lambda i=i: self.nameCheckBox(label, listCB[i])

このトピックに関する一般的な情報はたくさんあります。出発点: Google 検索、別の質問ループ内でラムダを作成する


残念ながら、私の修正は機能しませんでした。そのシグナルは、checked呼び出す関数に引数を提供し、チェック状態に応じてデフォルトの引数を 0 または 2 でオーバーライドするためです。これは動作します (不要な引数は無視してください):

lambda checked, i=i: self.nameCheckBox(label, listCB[i])

そして、そのクラスを記述する別の方法を次に示します。

class CheckBoxWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.setupUi()

    def setupUi(self):
        vbox = QVBoxLayout(self)
        self.label = QLabel("Last clicked button: None")

        vbox.addWidget(self.label)

        for i in range(10):
            cb = QCheckBox("CheckBox Nb. " + str(i+1))
            cb.stateChanged.connect(self.nameCheckBox)
            vbox.addWidget(cb)

    def nameCheckBox(self, checked):
        checkBox = self.sender()
        if checked:
            print("Checked: " + checkBox.text())
            self.label.setText("Last clicked button: " + checkBox.text())
        else:
            print("Unchecked: " + checkBox.text())
于 2014-12-24T12:15:07.417 に答える