Checkbutton Frage/Problem - Anregung gesucht

Fragen zu Tkinter.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Worin besteht denn der Unterschied zwischen Zeile 1 und 2? Bzw. wieso heißt eine Exemplarvariable ``checkbox`` (also *Singular*), obwohl sie doch eine Liste ist und *beliebig* viele Objekte aufnehmen kann? Und wieso ist ``checkboxen`` nur lokal? Brauchst Du die Daten darin nach verlassen der Methode nicht mehr?

Dir ist schon klar, dass in Zeile 4 der Name ``self.checkbox`` an ein vollkommen anderes Objekt gebunden wird als in Zeile 2? Und das in *jedem* Schleifendurchgang? Und um welchen Typen es sich dabei handelt? Und dass es da sinnlose Klammern gibt? Also dass wirklich bei jedem Durchgang ein *neues* Objekt an diesen Namen gebunden wird? Und dass *nach* dem letzten Durchgang damit darin auch stest der *letzte* erzeugte Wert stehen bleibt?

Auch wenn ich ehrlich gesagt den Thread nicht wirklich verfolgt habe, wundert es mich, dass Du an diesen Punkten offenbar immer noch keine Klarheit hast :!:

Wenn Du *viele* Objekte irgend wie verwalten willst, dann brauchst Du einen Container, wie z.B. eine Liste. Das ist an sich schon ok und vernünftig. Aber wozu verwaltest Du dann noch ein *einzelnes* Objekt (s. erste Frage)? Was willst Du mit dem Namen ``self.checkbox`` erreichen? Wozu willst Du den später nutzen?
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: Danke für die schnelle Antwort, du hast schon recht das in dem von mir gepostetem Code offensichtliche fehler sind. Ich bin Schritt für Schritt alles durchgegangen und hab dementsprechend alles abgeändert.
Sobald ich jetzt aber ein Checkbutton anklicke bekomm ich diese Ausgabe.

[<tkinter.StringVar object at 0x3011310>, <tkinter.StringVar object at 0x3011510>]

Und das bereitet mir Kopfzerbrechen. Was ich daraus erkennen kann ist das es sich um 2 Objekte handelt. Nur wie wandele ich das ganze jetzt so um das die Ausgabe wieder stimmt? "get" funktioniert ja nun nicht mehr.

Google hilft mir da leider auch nicht weiter oder hab ich wieder was falsch gemacht?

Code: Alles auswählen

            self.checkboxen=[]
            for row,(studie, serie, image) in enumerate(cursor, 1):
                self.checkboxen.append(StringVar())

                label_data = \
                [
                    (row, 'lightblue'),
                    (datum_ausgabe, ''),
                    (image, ''),
                    (serie, ''),
                    (studie, ''),
                ]
                serie_studie=('Serie: {} Studie: {}'.format(serie,studie))

                for column, (text, background) in enumerate(label_data):
                    Label(self.ueberframe, text=text, relief='sunken', anchor=CENTER, background=background).grid(row=row, column=column, sticky=NSEW)
                Checkbutton(self.ueberframe,variable=self.checkboxen,text=serie_studie,onvalue=serie_studie, offvalue="",command=self.list_checkbox).grid(row=row, column=5,sticky=E)
Zu deiner frage was ich damit anstellen will: Die Checkbutton bekommen die Studie- und Seriennummer zugewiesen wenn der jeweilige Checkbutton angeklickt wurde soll dessen Daten anhand der Nummern (Studie und Serie) verschickt werden, soweit der Plan aber das steht noch nicht zur Debatte. Bis jetzt versuch ich nur die Nummern richtig abzufangen was bis jetzt nicht funzt.
BlackJack

@Kalli87: Wieso funktioniert `get()` nicht mehr? Auch bei Objekten die man in eine Liste steckt funktionieren *auf diesen Objekten* natürlich die Methoden. Und natürlich *nicht* auf der *Liste* — falls das Dein Verständnis von Listen gewesen sein sollte.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Schau Dir mal diesen Code an und überlege, *was* ausgegeben wird:

Code: Alles auswählen

class Button:

    def __init__(self, command):
        self.command = command
        
    def get(self):
        return self.command
        
buttons = [Button("mache dies!"), Button("Mache was anderes!")]

print(buttons[1].get())

for button in buttons:
    print(button.get())
(Die Methode ``get`` ist natürlich unpythonisch - ich habe das nur als Namen gewählt, weil es da bei Tk offenbar etwas gibt, was so heißt)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Hyperion: Die `Variable`-Objekte von `Tk` sind ”Observables” die genau einen Wert kapseln und bei denen man sich registrieren kann wenn man informiert werden möchte wenn dieser eine Wert gesetzt (oder abgefragt oder ”undefiniert”) wird. Die Objekte haben `get()`, `set()`, und `trace()` — letzteres ist die Methode mit der man Rückruffunktionen registriert. Man könnte sich jetzt einen Namen für den gekapselten Wert ausdenken und ein Property statt `get()` und `set()` verwenden, aber da kommt dann die Frage wo man Properties und wo man Methoden verwenden sollte wenn mehr passiert als eine ”leichtgewichtige” Berechnung die kaum mehr als ein setzen/abfragen eines Wertes ist und wo die Grenze ist. Bei `Variable`-Objekten können beliebig viele Rückruffunktionen aufgerufen werden, die beliebig komplexe Aktionen durchführen können. Ob nun ``answer = variable.get()``/``variable.set(42)`` oder ``answer = variable.value``/``variable.value = 42`` halte ich für Geschmackssache.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@BlackJack: Das frag ich mich ja selbst warum das nicht mehr geht aber hier die Fehlermeldung:
AttributeError: 'list' object has no attribute 'get'
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib64/python3.2/tkinter/__init__.py", line 1399, in __call__
return self.func(*args)
File "/home/gast/Arbeitsfläche/Projekte/Datenbank/Bildarchiv.py", line 495, in list_checkbox
print(self.checkboxen.get())
AttributeError: 'list' object has no attribute 'get'
Also wenn ich jetzt direkt sage "print(self.checkboxen.get())" darauf komm diese Fehlermeldung.
Will ich das "Objekt" direkt ansprechen mit "print(self.checkboxen.get[1])" kommt die gleiche Fehlermeldung.

Liste direkt ausgeben geht ja aber dann komm wieder das hier: [<tkinter.StringVar object at 0x1e5a310>, <tkinter.StringVar object at 0x1e5a510>]

Ps.: Eure Tips seh ich jetzt erst nachdem ich das geschrieben hatte.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@BlackJack: Ah, danke für die Erklärung :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Dann überlege doch mal, was du hier machst:
Kalli87 hat geschrieben:

Code: Alles auswählen

self.checkboxen.get[1]
Du hast ein Objekt namens self. Bei dem greifst du auf das checkboxen-Attribut zu. Dann versuchst du das get-Attribut von der Liste mit den Checkboxen zu bekommen. Listen haben aber kein get-Attribut, was dir die Fehlermeldung sagt. Und von der get-Methode willst du dann auf das Element mit dem Index 1 zugreifen.

Was du willst ist aber die get-Methode des zweiten Elements in self.checkboxen aufzurufen. Du musst schon eins nach dem anderen machen. Das passiert halt, wenn man rät und nicht systematisch vorgeht ;-)
Das Leben ist wie ein Tennisball.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Kalli87: ich habe Dir bereits am 2. April empfohlen, diesen ganzen Tk-Kram erst einmal zu vergessen und Dich mit den Grundlagen von Listen und deren Verarbeitung vertraut zu machen. Oder ganz allgemein, was Datentypen sind, und warum es davon verschiedene gibt. Hättest Du meinen Rat befolgt, hättest Du eine Woche sinnloses Herumgerate gespart und wärst schon viel weiter. Den Code, den Du gestern gepostet hast, hattest Du in der Form glaube ich schon vier mal und ich hab Dir jedesmal gesagt, dass Du auf die Datentypen der Funktionsparameter achten mußt. Vergeblich :cry: .
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

Sirius3 hat geschrieben:@Kalli87: ich habe Dir bereits am 2. April empfohlen, diesen ganzen Tk-Kram erst einmal zu vergessen und Dich mit den Grundlagen von Listen und deren Verarbeitung vertraut zu machen. Oder ganz allgemein, was Datentypen sind, und warum es davon verschiedene gibt. Hättest Du meinen Rat befolgt, hättest Du eine Woche sinnloses Herumgerate gespart und wärst schon viel weiter. Den Code, den Du gestern gepostet hast, hattest Du in der Form glaube ich schon vier mal und ich hab Dir jedesmal gesagt, dass Du auf die Datentypen der Funktionsparameter achten mußt. Vergeblich :cry: .
Tut mir Leid Sirius3 das ich nicht wirklich dem Nachkomme, ich bin da bissl eigen wenn ich ein Problem habe versuch ich das zu lösen und ich muss aber auch sagen das ich mir listen usw. angeschaut habe aber nicht intensiv. Ich hätte ja auch nicht gedacht das es so lange dauert.
EyDu hat geschrieben:Du hast ein Objekt namens self. Bei dem greifst du auf das checkboxen-Attribut zu. Dann versuchst du das get-Attribut von der Liste mit den Checkboxen zu bekommen. Listen haben aber kein get-Attribut, was dir die Fehlermeldung sagt. Und von der get-Methode willst du dann auf das Element mit dem Index 1 zugreifen.
Was du willst ist aber die get-Methode des zweiten Elements in self.checkboxen aufzurufen. Du musst schon eins nach dem anderen machen. Das passiert halt, wenn man rät und nicht systematisch vorgeht ;-)
Klingt für mich unverständlich EyDu :K
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Kalli87 hat geschrieben: Klingt für mich unverständlich EyDu :K
Ja, für uns und den Python-Interpreter auch! :twisted:

Jetzt musst Du nur noch lernen, wie man mit Listen arbeitet, und der Spuk hat ein Ende ;-)
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

Ich hab gerade paar Seiten über Listen offen genauso meine 2 Bücher.
Kann aber einer mal mir bitte verraten was das nun heißt? [<tkinter.StringVar object at 0x3140310>, <tkinter.StringVar object at 0x3140510>]

Danke :)
BlackJack

@Kalli87: Das ist die Zeichenkettendarstellung einer Liste die zwei `StringVar`-Objekte enthält.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@BlackJack: Ah ok, danke dir :)
Und wie soll ich den post von EyDu genau verstehen? Es klingt für mich eigenartig was er/sie über self geschrieben hat. Und zweites Element in self.checkboxen?
BlackJack

@Kalli87: Was EyDu's Beitrag sagen will ist: Du musst verstehen was jeder einzelne Teilausdruck macht, welches Ergebnis der liefert, also Wert oder zumindest den Typ wissen, denn daran hängt ja was die weiteren Operationen auf dem jeweiligen Zwischenergebnis bedeuten. Nur so kann man verstehen was passiert und auch nur so kann man dann geziehlt selber Code schreiben der das tut was man haben möchte. Und EyDu erklärt Dir was *Dein* Ausdruck bedeutet. Und warum das so nicht funktionieren kann.

Erklär Du doch mal was die Teilausdrücke in Deinem Ausdruck jeweils für einen Typ haben und zumindest in Worten umschrieben welchen Wert die haben:

Code: Alles auswählen

self.checkboxen.get[1]
Wieviele unterschiedliche Operatoren haben wir in dem Ausdruck? Wie sieht das mit dem Operatorvorrang aus, also in welcher Reigenfolge werden die Teilausdrücke ausgewertet? Zerleg den Ausdruck mal komplett und binde wirklich *jedes* Zwischenergebnis an einen Namen (kann hier auch einfach `a`, `b`, `c`, … usw. sein), zeig das mal und beschreibe zu jedem Namen welchen Typ und Wert der dann hat, wenn möglich mit Erklärung wie Du darauf kommst.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@BlackJack: Ok, ich Versuchs mal.

self dient doch dazu um die variable außerhalb einer Funktion aufrufen zu können
checkbox hier is die variable bzw die liste
und mit get wollte ich quasi den Inhalt daraus holen was ja nicht geht da ja man bei listen kein get benutzen kann

Ich hatte ja vorher die StringVar an die Variable gehängt mit append, heißt ich hab jetzt in self.checkbox die StringVar Objekte
In einer anderen Funktion versuchte ich mir das gespeicherte auszugeben mit print(self.checkbox) (self deswegen da ich die Variable aus einer anderen Funktion aufrufen will)
und bekomme dafür die Zeichenkettendarstellung [<tkinter.StringVar object at 0x3140310>, <tkinter.StringVar object at 0x3140510>] aber nicht die Objekte selbst die darin enthalten sind.

Aber laut Internet und in meinen Büchern kann man darauf mit get() zugreifen und hier scheitert es ja an der Umsetzung und am Verständnis wie das ganze funktionieren soll.

Und jetzt zu deinen Operatoren.... das is doch eine Fangfrage oder? Laut meinem Verständnis von Operatoren hab ich keine bzw. benutze keine in diesem Fall hier.
Maximal das "in" was in den "for-Schleifen" aber das wars ja auch schon.
Oder ich versteh dich gerade falsch dann tut´s mir Leid wenn ich dich gerade nicht verstehe was du genau von mir erwartest gerade. :K
BlackJack

`self` ist das Objekt auf dem die Methode aufgerufen wurde. Hat also auch den Typ in dem diese Methode definiert wurde. Das dient wie eigentlich alle Objekte dazu Werte und Funktionen zu einer Einheit zusammen zu fassen. Die Funktionen werden dabei zu Methoden mit dem obligatorischen ersten Argument welches immer das Objekt ist auf dem die Methode aufgerufen wurde.

`checkbox` ist der Name eines Attributs das vom `self`-Objekt abgefragt wird, und da Du an diesen Attributnamen im vorherigen Programmverlauf eine Liste bebunden hast, ist das hier jetzt auch tatsächlich eine Liste.

Und von der Liste versuchst Du dann ein Attribut mit dem Namen `get` zu bekommen. Und das geht halt nicht weil Listen kein solches Attribut haben. Wie man an einzelne Elemente einer Liste heran kommt sollte man eigentlich nach jedem Grundlagentutorial wissen. Dafür gibt es den Indexzugriff.

Bei einem `print()` bekommst Du niemals die Objekte selbst ausgegeben ausser in einem einzigen Fall: Bei Zeichenketten. Alles andere muss ja in eine Zeichenkettenrepräsentation umgewandelt werden weil die Ausgabe am Ende Text sein muss. (Hier habe ich jetzt mal grosszügig das Thema Unicode und Kodierungen ignoriert, das wäre an der Stelle noch mal eine zusätzliche Schicht Komplexität.)

Du musst `get()` halt auf den einzelnen Elementen der Liste aufrufen und *das* dann ausgeben. Um etwas mit jedem Element einer Liste zu machen gibt es ``for``-Schleifen. Hier sind wir jetzt aber wieder bei absolutem Basiswissen.

Das mit den Operatoren war keine Fangfrage. Es werden zwei Stück verwendet, der Punktoperator (``.``) und der Indexoperator (``[…]``). Beides sind binäre Operatoren, das heisst sie erwarten zwei Operanden.

Beim Punktoperator muss links ein beliebiger Ausdruck stehen der zu einem Objekt ausgewertet wird und rechts ein Name der als Attribut auf dem ersten Operanden existiert. Das Ergebnis ist der Wert des Attributs. (Hier habe ich mal die Fälle „Objekt kann auch auf nicht existierende Attribute reagieren”, und Properties weggelassen.)

Beim Indexoperator muss davor ein beliebiger Ausdruck stehen der zu einem Objekt ausgewertet wird das den Indexzugriff erlaubt und zwischen den Klammern ein beliebiger Ausdruck den der andere Operand als Indexwert akzeptiert. Der Ausdruck in den Klammern wird grundsätzlich ausgewertet bevor der Indexzugriff gemacht wird. Das Ergebnis ist was auch immer der erste Operand für den Indexwert liefert.

Punkt- und Indexoperator haben die gleiche Bindungstärke, das heisst der gesamte Ausdruck wird von links nach rechts ausgewertet.

Oder auf ”Buchstaben verteilt” was ich ja gefragt hatte:

Code: Alles auswählen

self.checkboxen.get[1]

# =>

a = self          # Das Objekt auf dem die Methode aufgerufen wurde.
b = a.checkboxen  # Das Attribut `checkboxen`, eine Liste mit `StringVar`-Objekten.
c = b.get         # FEHLER weil Listen kein `get`-Attribut haben.
d = 1
e = c[d]
Zu `d` und `e` kommt es in der Ausführung wegen des `AttributeError` nicht mehr also kann man bei `e` auch nichts über Wert und Typ sagen weil Wert und damit Typ von `c` undefiniert ist.

Ausgerechnet das ``in`` in der ``for … in …:``-Syntax ist übrigens *kein* Operator sondern Teil der Schleifenanweisung. Es gibt aber in der Tat auch den ``in``-Operator. Ebenfalls ein binärer Operator der links einen Ausdruck erwartet der zu einem beliebigen Objekt ausgewertet wird und rechts ein Objekt das den Test implementiert und das Ergebnis ist ein Wahrheitswert.
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@BlackJack: Puh, viel zu lesen und zu verstehen. Ich werds mir genauer anschauen und probieren aber eine winzige kleine Frage hätte ich noch: Was ist das PY_VAR# (# für eine beliebige Zahl)? Vllt kannst du mir dazu noch eine kleine Erklärung schreiben.

Danke
BlackJack

@Kalli87: Das ist die Zeichenkettendarstellung von `Tkinter.Variable`-Objekten und damit auch von `StringVar`-Objekten. So ziemlich alle Objekte von Datentypen aus dem `Tkinter`-Modul liefern wenn man sie in eine Zeichenkette umwandelt die Zeichenkette unter der der Tk-Interpreter das jeweilige Objekt ansprechen kann. Widgets zum Beispiel den Pfad innerhalb der Widget-Hierarchy im zu dem jeweiligen Widget zu gelangen. Und Tk-Variablen haben entweder einen generierten Namen wie Du ihn beschrieben hast, oder man kann beim erstellen des Objekts einen übergeben. Das kann nötig sein wenn man mehr mit Tk-Arbeitet und auf Tk-Seite Code einen bestimmten Namen erwartet oder wenn es dort bereits eine Variable mit einem bestimmten Namen gibt, für den man auf Python-Seite gerne ein Objekt hätte.

Code: Alles auswählen

In [21]: import Tkinter as tk

In [22]: root = tk.Tk()

In [23]: v = tk.StringVar()

In [24]: print v
PY_VAR0

In [25]: str(v)
Out[25]: 'PY_VAR0'
Kalli87
User
Beiträge: 281
Registriert: Montag 10. November 2014, 11:27

@BlackJack: Das klingt ja voll nach Zeichenkettenformatierung bzw. Verarbeitung von Zeichenketten und wenn ich´s richtig verstanden habe müsste ich so dann auch die PY_VAR zurecht formatieren können bzw. so wäre der Weg um die richtige Ausgabe zu bekommen.
Wenn ich falsch liege bitte berichtige mich.

Danke
Antworten