indizierte Bindings

Fragen zu Tkinter.
Antworten
oldcoolman
User
Beiträge: 2
Registriert: Donnerstag 25. März 2021, 23:23

Hallo, ich bin neu in Python und hier.
Mein System ist Rasbpi mit einem touchscreen ohne Tastatur in der Endanwendung.
Ich habe ein Fenster mit einigen Labels zu programmieren. Um nicht all zu viel code tippen zu müssen, habe ich die Labels in einer Schleife generiert. Dies funktioniert auch soweit. Nur die bindings der Label ,genau gesagt die bindings Textvariablen der Labels funktionieren nicht indiziert.
Ich habe die bindings einzeln, also ohne Index programmiert. Funktioniert so wie es ist wunderbar.
Nur habe ich vor ein weiteres Fenster zu generieren, das wie eine Tabelle sehr viele Labels erhalten soll. Ein Index wäre hier echt super.

Code: Alles auswählen

class Win_zsu:	# Zeitschaltuhrfenster
    zsu_label=[tk.Label()]*18
    zsu_text_var=[tk.StringVar()]*6
    aktiv=0
    laufzeit=0
    laufzeit_ziel=0
    pausezeit_ziel=0
    wdh=0
    status=0
    def __init__(self):
        #self.zsu_text_var[2].set("0")
        #print(self.zsu_text_var[2])
        pass

    def generate(self):
        try:
            self.win_zsu.lift()
            self.win_zsu.focus()
#            print(self.win_zsu.state())
        except:
            #(labelindex,Anzeigetext)
            zsu_info=[(0,"aktiv?:",""),(1,"aktuell:","min"),(2,"Laufzeit:","min"),(3,"Pausezeit:","min"),
                      (4,"wiederholen?:",""),(5,"Status:","")]
            self.win_zsu=tk.Toplevel()
            self.win_zsu.title("Schaltuhr")   
           
            self.akt_ein = tk.Button(self.win_zsu,text = "ja",command = zsu_akt_ein,font = ("Helvettika",sg))
            self.akt_ein.grid(column = 2, row = 0)
            self.akt_aus = tk.Button(self.win_zsu,text = "nein",command = zsu_akt_aus,font = ("Helvettika",sg))
            self.akt_aus.grid(column = 3, row = 0)
            cfg_datei = open ('schaltuhrconfig.txt','r')

            for labelindex,Anzeigetext,einh in zsu_info:
                self.zsu_text_var[labelindex] = tk.StringVar ()
                self.zsu_text_var[labelindex].set (cfg_datei.readline().rstrip(' \r\n'))
                
                
                self.zsu_label[labelindex] = (tk.Label(self.win_zsu,text = Anzeigetext,font = ("Helvettika",sg)))
                self.zsu_label[labelindex].grid(column = 0,row = labelindex,sticky = tk.W)
                self.zsu_label[labelindex+6] = (tk.Label(self.win_zsu,textvariable = self.zsu_text_var[labelindex],font=("Helvettika",sg)))
                self.zsu_label[labelindex+6].grid(column = 1,row = labelindex,sticky = tk.W)
                #self.zsu_label[labelindex+6].bind("<Button-1>",lambda event:eingabe_callback(labelindex+3))
                
                self.zsu_label[labelindex+12] = tk.Label(self.win_zsu,text = einh,font = ("Helvettika",sg))
                self.zsu_label[labelindex+12].grid(column=2,row = labelindex,sticky = tk.W)
            cfg_datei.close()
            self.laufzeit_ziel=int(self.zsu_text_var[2].get())
            self.pausezeit_ziel=int(self.zsu_text_var[3].get())
            
            if self.zsu_text_var[4].get() == 'ja':
                self.wdh = 1
            #self.zsu_text_var[5].set('ein')
            #self.status = 1
                
#            self.zsu_text_var[2].set(str(self.laufzeit_ziel))
#            self.zsu_text_var[3].set(str(self.pausezeit_ziel))
            self.zsu_label[2].bind("<Button-1>",lambda event:eing_feld.generate(self.zsu_text_var[2],':'))
            self.zsu_label[3].bind("<Button-1>",lambda event:eing_feld.generate(self.zsu_text_var[3],':'))
            self.zsu_label[8].bind("<Button-1>",lambda event:eing_feld.generate(self.zsu_text_var[2],':'))
            self.zsu_label[9].bind("<Button-1>",lambda event:eing_feld.generate(self.zsu_text_var[3],':'))

            self.wdh_ein = tk.Button(self.win_zsu,text = "ja",command = zsu_wdh_ein,font = ("Helvettika",sg))
            self.wdh_ein.grid(column = 2, row = 4)
            self.wdh_aus = tk.Button(self.win_zsu,text = "nein",command = zsu_wdh_aus,font = ("Helvettika",sg))
            self.wdh_aus.grid(column = 3, row = 4)

            self.btn = tk.Button(self.win_zsu,text = "schlie�en",command = self.ok ,font = ("Helvettika",sg))
            self.btn.grid(columnspan=4,column = 0, row = 6,sticky = tk.W+tk.E)

__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ein Klassiker. Closures werden in Python ueber die referenzierten Namen gebildet. NICHT ueber die Werte, welche die zu dem Zeitpunkt haben. Einfaches Beispiel:

Code: Alles auswählen

callbacks = [ lambda: print(i) for i in range(10)]
for callback in callbacks:
   callback()
Wenn du den jeweils gueltigen Wert willst, benutzt functools.partial, oder binde ihn als default-Argument;

Code: Alles auswählen

callbacks = [ lambda i=i: print(i) for i in range(10)]
for callback in callbacks:
   callback()
oldcoolman
User
Beiträge: 2
Registriert: Donnerstag 25. März 2021, 23:23

Danke für die schnelle Antwort. Leider blicke ich nicht wirklich durch.
Kann mir das jemand mit der auskommentierten Zeile in der Schleife erklären?
eingabe_callback ist nur die Durchleitung zur eing_feld.generate( textvariable, 'typ')
Sirius3
User
Beiträge: 17709
Registriert: Sonntag 21. Oktober 2012, 17:20

Benutze keine Abkürzungen. Wenn Du Zeitschaltuhr meinst, nenne das nicht zsu. Dann ist auch der Kommentar überflüssig, wenn Du die Klasse einfach Zeitschaltuhrfenster nennst. Dann ist aber die Klasse gar kein Fenster, sondern nur eine Hülle für das eigentliche Programm. Um so verwirrender, wenn es Attribut gleichen Namens win_zsu gibt.

Attribute werden bei einer Klasse in __init__ angelegt. Benutze keine Klassenattribute, sondern Instanzattribute.
Das try-except in `generate` ist schlecht. Erstens benutzt man keine nackten except und zweitens mischt man nicht zwei Aufgaben in einer Funktion. Entweder möchtest Du ein neues Fenster erzeugen, oder ein existierendes in den Vordergrund bringen.
Bei tk.Toplevel fehlt die Angabe des Root-Fensters, bei StringVar auch.
Die Listen, die Du auf Klassenebene erzeugst, benutzt Du nicht, zum Glück, weil Du 18 mal das selbe Label erzeugst.
Man belegt keine Listen vor, sondern erzeugt neue Listen und hängt Elemente per append an.
Die Schriftart Helvettika kenne ich nicht. `sg` wird nirgends definiert.
Man öffnet Dateien mit dem with-Statement und gibt immer ein encoding an.
Warum werden Leerzeichen, Zeilenumbruch und Wagenrücklauf weggestrippt, aber keine Tabs?
Wenn Du nur per magischem Index auf die Labels zugreifst, ist vielleicht eine Liste nicht die beste Wahl.
Du scheinst auch bestimmte Labels mit anderen Widgets zu überlagern. Noch ein Grund, keine for-Schleife zu benutzen.
Für Wahrheitswerte benutzt man True oder False, nicht 1 oder 0.

`zsu_akt_ein`, `zsu_akt_aus`, `eingabe_callback`, `eing_feld` und `Win_zsu.ok` werden nirgends definiert. Bei den ersten paar Funktionen ist seltsam, dass die nicht als
Methoden der Klasse definiert werden.

Code: Alles auswählen

from functools import partial
import tkinter as tk

FONT = ("Helvetica", 12)

class Zeitschaltuhrfenster(tk.Toplevel):
    LABEL_INFO = [("aktiv?:",""),("aktuell:","min"),("Laufzeit:","min"),("Pausezeit:","min"),
                  ("wiederholen?:",""),("Status:","")]

    def __init__(self, root):
        tk.Toplevel.__init__(root)
        self.title("Schaltuhr")
        self.on_switch = tk.Button(self, text="ja", command=self.switch_on, font=FONT)
        self.on_switch.grid(column=2, row=0)
        self.off_switch = tk.Button(self, text="nein", command=self.switch_off, font=FONT)
        self.off_switch.grid(column=3, row=0)

        with open('schaltuhrconfig.txt', encoding="ASCII") as config_file:
            self.labels = []
            self.text_vars = []
            
            for row_index, ((anzeigetext, einheit), line) in enumerate(zip(self.LABEL_INFO, config_file)):
                var = tk.StringVar(root)
                var.set(line.strip())
                
                anzeige_label = tk.Label(self, text=anzeigetext, font=FONT)
                anzeige_label.grid(column=0, row=row_index, tk.W)
                var_label = tk.Label(self, textvariable=var, font=FONT)
                var_label.grid(column=1, row=row_index, tk.W)
                var_label.bind("<Button-1>", partial(self.eingabe_callback, row_index))
                if row_index == 4:
                    self.wiederholung_ein = tk.Button(self, text="ja", command=self.switch_repeat_on, font=FONT)
                    self.wiederholung_ein.grid(column=2, row=row_index)
                    self.wiederholung_aus = tk.Button(self, text="nein", command=self.switch_repeat_off, font=FONT)
                    self.wiederholung_aus.grid(column=3, row=row_index)
                    einheit_label = None
                else:
                    einheit_label = tk.Label(self, text=einheit, font=FONT)
                    einheit_label.grid(column=2, row=row_index, tk.W)
                    if row_index in [2, 3]:
                        callback = partial(self.eingabefeld_generate, var)
                        anzeige_label.bind("<Button-1>", callback)
                        var_label.bind("<Button-1>", callback)
                    
                self.labels.append((anzeige_label, var_label, einheit_label))
                self.text_vars.append(var)

        self.close_button = tk.Button(self, text="Schließen", command=self.ok, font=FONT)
        self.close_button.grid(columnspan=4, column=0, row=6, sticky=tk.W+tk.E)

        self.wiederholung = self.text_vars[4].get() == 'ja'
        self.laufzeit_ziel = int(self.text_vars[2].get())
        self.pausezeit_ziel = int(self.text_vars[3].get())

        self.aktiv = False
        self.laufzeit = 0
        self.status = 0


    def lift_and_focus():
        self.lift()
        self.focus()

    def switch_on(self):
        pass

    def switch_off(self):
        pass

    def switch_repeat_on(self):
        pass

    def switch_repeat_off(self):
        pass

    def eingabe_callback(self, row_index):
        pass

    def eingabefeld_generate(self, variable, event):
        pass

    def ok(self):
        pass
Antworten