Checkbutton Frage/Problem - Anregung gesucht

Fragen zu Tkinter.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

So ich melde mich mal wieder ;)

Ich hab folgendes Problem bzw. vllt auch ein gedanklichen Fehler.
In meiner for-Schleife hab ich es so geschrieben das Checkbuttons angelegt werden, abhängig von dem wie viele Datensätze angezeigt werden. Sprich Datenbankabfrage enumerate, laufende Nummer etc. passt alles wunderbar aber wenn ich jetzt 2 Checkbuttons anklicke bzw aktiviere wird immer nur der letzte genommen der "ge-checked" is. Ich hab mir testweise eine kleine Ausgabe dazu gebastelt bzw auch eine txt-Datei angelegt wo das "ge-checkte" eingetragen wird.
Es sollen aber alle aktivierte Checkbuttons übertragen werden und nicht nur der letzte.

Hier mein Code (kleiner Auszug, sonst regnets wieder Steine :wink: )

Code: Alles auswählen

            self.cursor.execute("select * from patient, bilder where patient.klein_name=%s and bilder.patnu=patient.patnu", [self.eingabe.get()])
            for self.i, s in enumerate(self.cursor, 1):
                self.test_checkbox = StringVar()
                Label(self.ueberframe, text=self.i,relief='sunken', anchor=CENTER, background='lightblue').grid(row=self.i, column=0, sticky=NSEW)
                Label(self.ueberframe, text=self.datum_ausgabe, relief='sunken', anchor=CENTER).grid(sticky=NSEW, row=self.i, column=1)
                Label(self.ueberframe, text=s[30],relief='sunken', anchor=CENTER).grid(sticky=NSEW, row=self.i, column=2)
                Label(self.ueberframe, text=s[29],relief='sunken', anchor=CENTER).grid(sticky=NSEW, row=self.i, column=3)
                Label(self.ueberframe, text=s[28],relief='sunken', anchor=CENTER).grid(sticky=NSEW, row=self.i, column=4)
                Checkbutton(self.ueberframe, variable= self.test_checkbox, onvalue="Serie: "+str(s[29])+" Studie: "+str(s[28]) + " ID " + str(self.i) , offvalue="").grid(row=self.i, column=5)
Und bitte meckert nicht über meinen Code, ich weiß das der mistig/unschön/hässlich/überflüssig oder wie es immer nennen wollt ist.
Ihr seht ja selbst an den Namen das es sich immer noch um ein Test handelt :wink:
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@Kalli87: auch bei Tests ist es gut, schön zu programmieren.
Es ist wirklich nie sinnvoll, ein Attribut als Schleifenvariable zu benutzen. Wo brauchst Du denn das self.i wieder? Dann wurde Dir glaube ich schon mehrfach gesagt, dass ein "select *" das anpassen Deiner Datenbank unnötig verkompliziert. Wenn Du sowieso nur Feld 28, 29 und 30 brauchst, warum selectierst Du dann alles??
Strings sollte man nicht so mit + zusammenstückeln. Dafür gibt es Stringformatierung.
Wenn Du alle Checkbox-Variablen brauchst, würde ich die ja nicht gleich wieder wegwerfen, sondern in einer Liste sammeln.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@Sirius3: Ja es stimmt, es wurde mir schon mehrmals mitgeteilt ich solle es doch bitte ändern und es steht auf meiner Liste der Dinge die ich noch abarbeiten muss und will.
Gut das mit der self.i stimmt das hab ich geändert.
Stringformatierung..... schon drüber gelesen aber nicht wirklich damit beschäftigt, ein Punkt mehr auf meiner liste
Die Checkbox-Variablen in eine Liste packen soweit war ich mit meinen Gedanken auch nur scheitert es da bissl an der Umsetzung, leider.
Ich weiß das die Variablen in test_checkbox gespeichert sind, aber wenn ich die einfach mit print versuche auszugeben is die immer leer egal ob was angeklickt ist oder nicht.
Und das versteh ich nicht wirklich.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Kalli87 hat geschrieben: Die Checkbox-Variablen in eine Liste packen soweit war ich mit meinen Gedanken auch nur scheitert es da bissl an der Umsetzung, leider.
Öh... Du weißt jetzt also nicht, wie man ein Objekt in eine Liste packt :?: Das kannst Du einfach mal schnell im offiziellen Tutorial nachlesen 8)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Na doch Hyperion mit append :P
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@Kalli87: ein "select *" durch etwas besseres zu ersetzen geht schneller, als es auf irgendeine Liste zu schreiben. Und eine Stunde sich hinzusetzen und den Abschnitt über Stringformatierung in der Dokumentation zu lesen und noch ein bißchen damit interaktiv herumzuspielen, ist auf jeden Fall eine gut investierte Stunde.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Kalli87 hat geschrieben:Na doch Hyperion mit append :P
Und woran scheitert es dann noch :K
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@Hyperion: Ich hab gestern noch paar Stunden gesessen und heute früh ebenso um mir eine Liste zu erstellen. Das Problem jetzt aber dabei is das trotz alledem irgendwo ein Fehler bei den Checkboxen liegt. In dem Code den ich gepostet hatte kann ich beide Checkboxen aktivieren, was so ja auch sein soll aber! Bei der Übergabe an eine Liste bleibt die erste Checkbox leer und nur die Zweite liefert das gewünschte Ergebnis.
Ich hatte eine neue Funktion geschrieben die ich über "command" in den Checkboxen aufrufe die halt per Aktivierung die Daten in eine liste schreiben soll, aber wie schon geschrieben bleibt die erste Checkbox leer. Testweise hab ich mal "self.test_checkbox = StringVar()" vor die "For-Schleife" gesetzt und dabei werden beide richtig abgefangen aber es kann nur eine Checkbox aktiv bleiben was leider nicht Sinn und Zweck der ganzen Sache ist. Sie sollen ja Aktiv bleiben wenn man Sie anklickt. Woran liegt das?
BlackJack

@Kalli87: *Eine* Textvariable kann halt nur *einen* Wert zur gleichen Zeit beinhalten. Du brauchst also nicht die Checkboxen sondern pro Checkbox eine Textvariable.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Und weil die Variable in den Checkboxen jeweils gleich is kann immer nur eine aktiv sein?
Versteh ich das richtig?
BlackJack

@Kalli87: Naja die Checkboxen teilen sich halt alle *eine* Textvariable. Wenn Du eine anklickst, dann bekommen alle den neuen Wert mitgeteilt, vergleichen den mit ihrem „on”-Wert und der Zustand ändert sich entsprechend.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@BlackJack: Gut zu wissen das es an der Variable liegt das meine Buttons so rum spinnen. Was mir aber aufgefallen is, und das jetzt nur mal am Rande, meine Radiobuttons haben alle! die gleiche Variable aber da funktioniert es ohne Probleme. Am Anfang hatte ich das gleiche Problem und mir is aufgefallen das der Inhalt der Variable gleich war bei 2 Radiobuttons und deswegen immer beide Aktiv waren wenn ich eins davon angeklickt hatte. Hab dann in der config-Datei die Werte geändert und seitdem gehts.

Ich werd mal googlen wie ich die onvalue vergleichen kann am besten, auf Anhieb fällt mir kein Stückchen Code ein wie man so etwas in einem Button vergleichen kann oder anderweitig.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Bei Radiobuttons ist es ja auch richtig, dass sie alle die selbe Variable haben. Die teilen sich ja gerade den selben Zustand, da immer nur ein Radiobutton aus einer Gruppe gesetzt sein soll.

Für Checkboxen, oder Eingabefelder, gilt das natülich nicht. Die sind alle unabhängig und sollen gerade keinen Zustand teilen. Deshalb braucht jedes der Widgets eine eigene Variable.
Das Leben ist wie ein Tennisball.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

EyDu hat geschrieben:Bei Radiobuttons ist es ja auch richtig, dass sie alle die selbe Variable haben. Die teilen sich ja gerade den selben Zustand, da immer nur ein Radiobutton aus einer Gruppe gesetzt sein soll.

Für Checkboxen, oder Eingabefelder, gilt das natülich nicht. Die sind alle unabhängig und sollen gerade keinen Zustand teilen. Deshalb braucht jedes der Widgets eine eigene Variable.
Klingt logisch, danke!
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

So ich hab mal bissl an der Formatierung und an der Abfrage gebastelt, ich hoffe @Sirius3 es entspricht dem was du dir so in etwa vorgestellt hast.

Code: Alles auswählen

           self.cursor.execute("select patient.patnu, patient.klein_name, patient.klein_vname, patient.name, patient.vname, patient.geb, patient.ges, 
            bilder.patnu, bilder.ct_mr, bilder.ustag, bilder.studie_nr, bilder.serie_nr, bilder.image_nr from bilder, patient where patient.patnu=bilder.patnu 
            and patient.patnu=%s", [self.eingabe.get()])
            for i, s in enumerate(self.cursor, 1):
                self.test_checkbox= StringVar()

                label_data = \
                [
                    (i, 'sunken', CENTER, 'lightblue',i,0,NSEW),
                    (self.datum_ausgabe,'sunken', CENTER,'', i,1,NSEW),
                    (("{}").format(s[12]),'sunken', CENTER,'',i,2,NSEW),
                    (("{}").format(s[11]),'sunken', CENTER,'',i,3,NSEW),
                    (("{}").format(s[10]),'sunken', CENTER,'',i,4,NSEW)
                ]
                for text, relief, anchor, background,row,column,sticky in label_data:
                    Label(self.ueberframe, text=text, relief=relief, anchor=anchor, background=background).grid(row=row, column=column, sticky=sticky)
                Checkbutton(self.ueberframe, variable=self.test_checkbox, onvalue="Serie: {} Studie: {}".format(str(s[11]),str(s[10])), offvalue="", command=self.liste_checkbutton).grid(row=i, column=5)
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@Kalli87: Jetzt hast Du zwar 10 Felder weniger, aber immer noch 10 Felder zu viel in Deinem select. Attribute, die für jedes Label gleich sind, kann man auch direkt angeben, spart Schreibarbeit. Und warum heißt i nicht row? Deinem eigentlichen Problem bist Du aber auch nicht näher gekommen.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@Sirius3: Langsam bin ich mit meinem Latein am ende. Ich hab die select-Abfrage überarbeitet und nur die Felder selektiert die ich brauche und das sind nun mal soviel.
i war schon immer für mich eine einfache "lauf"-Variable aber zum Verständnis hab ich sie nun "row" genannt.
Das ich meinem eigentlichen Problem nicht näher gekommen bin is mir bewusst hab eher die Zeit genutzt um das ganze etwas mehr Struktur zu verleihen in der Hoffnung das ich eine Idee bekomme wie ich das ganze löse mit den Checkboxen.

Code: Alles auswählen

           self.cursor.execute("select patient.patnu, patient.klein_name, patient.klein_vname, patient.name, patient.vname, patient.geb, patient.ges, bilder.patnu, bilder.ct_mr, bilder.ustag, 
            bilder.studie_nr, bilder.serie_nr, bilder.image_nr from bilder, patient where patient.patnu=bilder.patnu 
            and patient.patnu=%s", [self.eingabe.get()])
            for row, s in enumerate(self.cursor, 1):
                image = s[12]
                serie = s[11]
                studie = s[10]

                self.test_checkbox= StringVar()

                label_data = \
                [
                    (row, 'sunken', CENTER, 'lightblue',row,0,NSEW),
                    (self.datum_ausgabe,'sunken', CENTER,'', row,1,NSEW),
                    (("{}").format(image),'sunken', CENTER,'',row,2,NSEW),
                    (("{}").format(serie),'sunken', CENTER,'',row,3,NSEW),
                    (("{}").format(studie),'sunken', CENTER,'',row,4,NSEW)
                ]
                for text, relief, anchor, background,row,column,sticky in label_data:
                    Label(self.ueberframe, text=text, relief=relief, anchor=anchor, background=background).grid(row=row, column=column, sticky=sticky)
                Checkbutton(self.ueberframe, variable=self.test_checkbox, onvalue="Serie: {} Studie: {}".format(str(serie),str(studie)), offvalue="", command=self.liste_checkbutton).grid(row=row, column=5)
Denke mal du wolltest daruf hinaus? (Mit den Attributen)
BlackJack

@Kalli87: Im Code verwendest Du drei Werte aus dem SELECT, im SELECT stehen aber deutlich mehr‽
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@BlackJack: Sag nix... war wieder so schlau alles doppelt und dreifach zu verwenden :lol:

Edit: Geändert...... :oops:
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@BlackJack und @Sirius3: Sorry das ich mich echt so "blöd" anstelle und eure subtilen Hinweise, besonders die von Siruis3, nicht verstehe oder einfach übersehe. Ich kann nur Danke sagen bzw. schreiben das ihr soviel Geduld habt und mich noch nicht gelyncht habt obwohl es ihr vielleicht wollt.

Leider häng ich immer noch an diesem kleinen Problem mit den Checkbuttons, vllt könnt Ihr mir nochmal tatkräftig helfen damit dieses Problem gelöst werden kann.
Danke!!!

Code: Alles auswählen

            self.cursor.execute("select bilder.studie_nr, bilder.serie_nr, bilder.image_nr from bilder, patient where patient.patnu=bilder.patnu and patient.patnu=%s", [self.eingabe.get()])
            for row, s in enumerate(self.cursor, 1):
                image = s[2]
                serie = s[1]
                studie = s[0]
                self.test_checkbox= StringVar()
                label_data = \
                [
                    (row, 'sunken', CENTER, 'lightblue',row,0,NSEW),
                    (self.datum_ausgabe,'sunken', CENTER,'', row,1,NSEW),
                    (("{}").format(image),'sunken', CENTER,'',row,2,NSEW),
                    (("{}").format(serie),'sunken', CENTER,'',row,3,NSEW),
                    (("{}").format(studie),'sunken', CENTER,'',row,4,NSEW)
                ]
                for text, relief, anchor, background,row,column,sticky in label_data:
                    Label(self.ueberframe, text=text, relief=relief, anchor=anchor, background=background).grid(row=row, column=column, sticky=sticky)
                Checkbutton(self.ueberframe, variable=self.test_checkbox, onvalue="Serie: {} Studie: {}".format(str(serie),str(studie)), offvalue="", command=self.liste_checkbutton).grid(row=row, column=5)
Ich hoffe das der Code jetzt soweit stimmt was die Struktur betrifft und die Formatierung.
Antworten