Problem beim Aufruf einer addWidget-Methode an einer QScrollArea

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
AFX
User
Beiträge: 51
Registriert: Samstag 4. September 2021, 08:40

Ich habe eine Klasse, welche ich wie folgt instanziiere:

ScrollMessageBox(QMessageBox.Information, '', '')

Hier die Klasse:

Code: Alles auswählen

class ScrollMessageBox(QMessageBox):
   def __init__(self, *args, **kwargs):
      QMessageBox.__init__(self, *args, **kwargs)
      chldn = self.children()
      scrll = QScrollArea(self)
      scrll.setWidgetResizable(True)
      grd = self.findChild(QGridLayout)
      lbl = QLabel(chldn[1].text(), self)
      lbl.setWordWrap(True)
      
      #Ich möchte einem vbox-Layout ein Label und einen Button untereinander hinzufügen und dann der 
      #Scrollbar. Geht aber nicht, ich weiß nicht warum.

      vbox = QVBoxLayout()
      
      vbox.addWidget(lbl)
      vbox.addWidget(QPushButton("Test"))
      scrll.setWidget(vbox)            
      
       ##############################################
      
      scrll.setMinimumSize (400,200)
      grd.addWidget(scrll,0,1)
      date_name = args[1]
      self.checkBox = QCheckBox("Connect this")      
      grd.addWidget(self.checkBox,1,0)
      print(chldn[2]) #TODO
      chldn[1].setText('')
      self.exec_()
Ich weiß nicht, wieso ich (siehe Codekommentar) nicht das Label und den Button übereinander auf diese Weise der Scrollbar hinzufügen kann, weswegen ich an dieser Stelle einmal fragen möchte, ob mir jemand einen Tipp geben kann, was da falsch ist; leider komme ich nciht drauf :(
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das eingesparte o bei scroll hat sich aber wirklich gelohnt 😬

Ich rate dir ma l mit dem Designer sowas zu basteln. Dann kannst du dir mit pyuic den generierten Code anschauen.
AFX
User
Beiträge: 51
Registriert: Samstag 4. September 2021, 08:40

__deets__ hat geschrieben: Dienstag 7. Dezember 2021, 09:22 Das eingesparte o bei scroll hat sich aber wirklich gelohnt 😬
An Weihnachten werde ich konsequenter Weise nicht "O du fröhliche" singen sondern "Du fröhliche" ;)

Nun zur Lösung. scrll (ohne o!) erwartet ein Label und nix anderes, so also wird ein Schuh draus:

Code: Alles auswählen

class ScrollMessageBox(QMessageBox):
   def __init__(self, *args, **kwargs):
      QMessageBox.__init__(self, *args, **kwargs)
      chldn = self.children()
      scrll = QScrollArea(self)
      scrll.setWidgetResizable(True)
      grd = self.findChild(QGridLayout)
      lbl = QLabel(chldn[1].text(), self)
      lbl.setWordWrap(True)
      
      ##############################################
      vbox = QVBoxLayout()
      vbox.addWidget(lbl)
      vbox.addWidget(QCheckBox("Connect this"))
      vbox.addWidget(QCheckBox("Connect this"))
      vbox.addWidget(QCheckBox("Connect this"))
      vbox.addWidget(QCheckBox("Connect this"))
      vbox.addWidget(QCheckBox("Connect this"))
      vbox.addWidget(QCheckBox("Connect this"))
      vbox.addWidget(QCheckBox("Connect this"))
      lbl2 = QLabel() #--> scrll erwartet ein Label und nix anderes, jetzt geht es.
      lbl2.setLayout(vbox)
      ##############################################
      
      scrll.setWidget(lbl2)            
      scrll.setMinimumSize (400,200)
      grd.addWidget(scrll,0,1)
      date_name = args[1]
      
      chldn[1].setText('')
      self.exec_()

Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@AFX: __init__ ist dazu da, etwas zu initialisieren, nicht dass es ewig läuft: das `exec_` sollte `exec` heißen und nicht in __init__ stehen.
AFX
User
Beiträge: 51
Registriert: Samstag 4. September 2021, 08:40

Vielen Dank für exec_ -> ich werde es gleich nachher verbessern, aber ich bin da auf ein anderes Problem gestoßen, das ist irre. Ich möchte mehrere Checkboxes in ein Grid setzen, jeder einzelnen Checkbox füge ich die Checkbox hinzu cb.stateChanged.connect(lambda:self.btnstate(cb)) (siehe Code unten) - nun meine Frage. In der Funktion def btnstate(self,b) möchte ich den Objektnamen ausgeben für jede einzelne Checkbox, der jeweils anders ist (habe ich geprüft). Aber egal welche Checkbox ich be- oder enthake, es wird mir immer nur der Name ein und derselben Checkbox ausgegeben, und zwar der letzten. Ich verstehe nicht, wie das sien kann... Hat jemand da einen Tipp für mich?

Code: Alles auswählen

class ScrollMessageBox(QMessageBox):

   def btnstate(self,b):
       print(b.objectName()) # -> IMMER derselbe, nämlich die letzte Checkbox in der Liste.

 
   def __init__(self, *args, **kwargs):
      QMessageBox.__init__(self, *args, **kwargs)
      chldn = self.children()
   
      scrll = QScrollArea(self)
      scrll.setWidgetResizable(True)
      grd = self.findChild(QGridLayout)
      lbl = QLabel(chldn[1].text(), self)
      lbl.setWordWrap(True)
      
      grid_layout = QGridLayout()
      grid_layout.setAlignment(Qt.AlignTop)
      grid_layout.addWidget(lbl, 0, 0, 1, 3)

      d = args[1]
      
      uncheckedResContacts = dbaccess.getUncheckedResContactsFor(d)
      checkedResContacts = dbaccess.getCheckedResContactsFor(d)
      
      self.chckBoxes = {}
      
      i=1
      for d, nme in checkedResContacts.items():
          cb = QCheckBox("Check to connect " + d) 
          cb.setChecked(True)
          cb.setObjectName(d)
          cb.stateChanged.connect(lambda:self.btnstate(cb))
          self.chckBoxes[d] = True
          grid_layout.addWidget(cb, i, 0)
          i+=1
          

      for d, nme in uncheckedResContacts.items():
          cb = QCheckBox("Check to connect " + d)
          cb.setChecked(False)
          cb.setObjectName(d)
          cb.stateChanged.connect(lambda:self.btnstate(cb))
          self.chckBoxes[d] = False
          grid_layout.addWidget(cb, i, 0)
          i+=1
       
      lbl2 = QLabel()
      lbl2.setLayout(grid_layout)
      
      scrll.setWidget(lbl2)            
      scrll.setMinimumSize (400,200)
     
      grd.addWidget(scrll,0,1)
      
      chldn[1].setText('')
      
      self.exec_()
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Eine Murmeltierfrage hier im Forum. Das Problem: deine lambdas fangen den *Namen*, nich den *Wert*, den der Name bei Erzeugung hatte. Damit ist dein cb immer der letzte Wert.

Abhilfe schafft zB die Verwendung von functools.partial oder einem gebundenen keyword-Agument:

Code: Alles auswählen

...connect(functools.partial(self.btnstate, cb))
...connect(lambda cb=cb: self.btnstate(cb))
AFX
User
Beiträge: 51
Registriert: Samstag 4. September 2021, 08:40

Danke, jetzt geht es :)
Antworten