Triggern von dynamisch generierten Checkboxen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
hueschel
User
Beiträge: 4
Registriert: Dienstag 21. Dezember 2010, 18:11

Hallo!

Im Moment vezweifele ich daran, eine dynamische Anzahl von QCheckBox-Elementen zu generieren, die ein jeweils zugehöriges QLineEdit-Element freigeben bzw. sperren.
Unten das Minimalbeispiel.


Dabei meldet sich der Fehler File "D:\python\slmauto\slmgui-minimum.py", line 34, in __init__
self.check.toggled.connect(self.invertcheck(i))
TypeError: argument 1 has unexpected type 'NoneType'


Wenn ich die Zeile

Code: Alles auswählen

self.check[i].toggled.connect(self.invertcheck(i))
ausklammere, werden keine Fehler mehr generiert und das GUI sieht aus, wie es vorgesehen ist.
Ich kann mir leider nicht erklären wo der Fehler liegt :?

Achja, wenn ich statt

Code: Alles auswählen

self.code = []
self.code.append(QLineEdit())
self.code.append(QLineEdit())
self.code.append(QLineEdit())
self.code.append(QLineEdit())


einfach schreibe

Code: Alles auswählen

self.code = [0]*4
dann kommt die Fehlermeldung File "D:\python\slmauto\slmgui-minimum.py", line 48, in invertcheck
self.code.setEnabled(True)
AttributeError: 'int' object has no attribute 'setEnabled'


Daher der Umweg mit der append-Funktion. Gibt es hier vielleicht auch eine elegantere Lösung?


Viele Grüße
hueschel

Code: Alles auswählen

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import * 


class Dialog(QDialog):

   
    def __init__(self):
        super(Dialog, self).__init__()

       
        SamplesGroupBox = QGroupBox("Samples:")
        sampleslayout = QGridLayout()
 
        
        self.check = []
        self.check.append(QCheckBox())
        self.check.append(QCheckBox())
        self.check.append(QCheckBox())
        self.check.append(QCheckBox())
        self.code = []
        self.code.append(QLineEdit())
        self.code.append(QLineEdit())
        self.code.append(QLineEdit())
        self.code.append(QLineEdit())
        for i in range(1,4):
            self.check[i] = QCheckBox("Sample #" + str(i))
            self.check[i].setChecked(True)     
            sampleslayout.addWidget(self.check[i], 2*i-1, 0)
            self.check[i].toggled.connect(self.invertcheck(i))
            
            self.code[i] = QLineEdit()
            sampleslayout.addWidget(QLabel("sample code:"), 2*i, 1)
            sampleslayout.addWidget(self.code[i], 2*i, 2)
            self.code[i].setEnabled(True)

        
        SamplesGroupBox.setLayout(sampleslayout)
 
    
        self.setWindowTitle("slmgui")        
        mainlayout = QVBoxLayout()
        mainlayout.addWidget(SamplesGroupBox)
        self.setLayout(mainlayout)
    
    def invertcheck(self,i):
        if self.check[i].isChecked():
             self.code[i].setEnabled(True)
        else:
            self.code[i].setDisabled(True)


if __name__ == '__main__':

    import sys
    app = QApplication(sys.argv)
    dialog = Dialog()
    sys.exit(dialog.exec_())
    
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@hueschel: In Python werden keine Listen vorbelegt, um dann die Elemente zu überschreiben. Du erzeugst ja auch völlig unnötigerweise QCheckBoxen, die Du danach wieder verwirfst. connect erwartet eine Funktion als Argument. Welche Funktion liefert denn der Aufruf von self.invertcheck(i) zurück? Wenn code und check zusammen gehören, sollten das auch keine zwei Listen sein, sondern eine mit Tuplen.
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Probier das mal aus:

Code: Alles auswählen

from PyQt5.QtGui import *
 
class Dialog(QDialog):
   
    def __init__(self):
        super(Dialog, self).__init__()
 
        self.code = []       
        samplesGroupBox = QGroupBox("Samples:")
        self.sampleslayout = QGridLayout()
        for i in range(4): # i geht von 0 bis 3
            self.code.append(self.addRow(i))
       
        samplesGroupBox.setLayout(self.sampleslayout)
        self.setWindowTitle("slmgui")        
        mainlayout = QVBoxLayout()
        mainlayout.addWidget(samplesGroupBox)
        self.setLayout(mainlayout)
        
    def addRow(self, rowNo):
        self.sampleslayout.addWidget(QLabel("sample code:"), rowNo, 1)

        code = QLineEdit()
        self.sampleslayout.addWidget(code, rowNo, 2)
        
        check = QCheckBox("Sample #%i" % (rowNo+1))
        check.setChecked(True)    
        self.sampleslayout.addWidget(check, rowNo, 0)
        check.toggled.connect(lambda: code.setEnabled(check.isChecked()))
        
        return code
   
if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    dialog = Dialog()
    sys.exit(dialog.exec_())
In Python ist die Indizierung 0-basiert, der 1. Index einer Liste oder eines Arrays ist 0. Die Liste self.code wird in diesem Beispiel so nicht gebraucht, ich habe sie trotzdem hinzugefügt, damit Du Zugriff auf die Benutzereingaben hast. Eine Liste self.check ist aber nicht erforderlich.
a fool with a tool is still a fool, www.magben.de, YouTube
hueschel
User
Beiträge: 4
Registriert: Dienstag 21. Dezember 2010, 18:11

Guten Morgen!

Super, ich habe mir schon gedacht, dass mein Skript sehr chaotisch ist. Im Moment habe ich leider kein PyQt Modul zur Verfügung, aber heute abend werde ich es ausprobieren. :)
AxXel001
User
Beiträge: 29
Registriert: Sonntag 7. Juni 2015, 22:22

Um mal genau auf deine Frage zu antworten, die Funktion invertcheck gibt nichts zurück, also ist ihr Rückgabewert None. Du versuchst also das toggled Signal in Zeile 31 an einen Slot zu knüpfen, der None ist. Das generiert offensichtlich einen Fehler.
Antworten