tkinter Wert in anderem fenster setzen

Fragen zu Tkinter.
Antworten
Tomax
User
Beiträge: 31
Registriert: Sonntag 21. August 2016, 08:05

Hallo Zusammen

Ich erzeuge aus meinem Hauptfenster mit einem Button ein Zusatzfenster, in dem ich mit buttns Werte in einer Textdatei ändere.
Klappt alles.
Jetzt möchte ich in diesem Zusatzfenster auch den aktuell eingestellten Wert anzeigen.
Im Listing: dr_label und dz_label, im Fenster window. Wie kann ich jetzt den angezeigten Wert ändern?

Die Funktionen mod_drehz und mod_druck änder die Werte in der csv-Datei.

Code: Alles auswählen

def mod_druck(betrag):
    with open('livedaten.csv', 'r') as file:
        data = file.readlines()
    data[1] = str(round(float(data[1]) + betrag, 2)) + "\n"
    with open('livedaten.csv', 'w') as file:
        file.writelines(data)


def mod_drehz(betrag):
    with open('livedaten.csv', 'r') as file:
        data = file.readlines()
    data[0] = str(round(float(data[0]) + betrag, 2)) + "\n"
    with open('livedaten.csv', 'w') as file:
        file.writelines(data)


def create_window():
    window = tk.Toplevel(hauptfenster)
    window.title("Werte simulieren")
    window.geometry("160x400")
    window.configure(bg=bg_farbe)
    window.resizable(width=False, height=False)
    tk.Label(window, text="Drehzahl", bg=bg_farbe, font=("Helvetica", 12)).place(x=20, y=20, width=120, height=25)
    tk.Button(window, text="+", command=lambda: mod_drehz(20)).place(x=90, y=50, width=20, height=25)
    tk.Button(window, text="-", command=lambda: mod_drehz(-20)).place(x=50, y=50, width=20, height=25)
    dz_label = tk.Label(window, text=str(drehzahl_lesen()), bg=bg_farbe, font=("Helvetica", 12))
    dz_label.place(x=20, y=80, width=120, height=25)
    tk.Label(window, text="Druck", bg=bg_farbe, font=("Helvetica", 12)).place(x=20, y=110, width=120, height=25)
    tk.Button(window, text="+", command=lambda: mod_druck(0.1)).place(x=90, y=140, width=20, height=25)
    tk.Button(window, text="-", command=lambda: mod_druck(-0.1)).place(x=50, y=140, width=20, height=25)
    dr_label = tk.Label(window, text=str(druck_lesen()), bg=bg_farbe, font=("Helvetica", 12))
    dr_label.place(x=20, y=170, width=120, height=25)
BlackJack

@Tomax: Du müsstest beim Aufruf halt noch das Anzeige-Element mit übergeben. Allerdings ist das in Python unüblich das so, über Closures, zu lösen, denn Python ist eine objektorientierte Programmiersprache. Ausserdem würde man auf diese Weise, egal ob man das nun funktional oder objektorientiert löst, Anzeige und Geschäftslogik vermischen.

Sonstige Anmerkungen: Die beiden `mod_*()`-Funktionen sind fast identisch, das sollte man in eine allgemeine Funktion heraus ziehen.

`place()` sollte man nicht verwenden. Das kann auf Systemen mit anderer Bildschirmeinstellungen zu falscher bis hin zu unbenutzbarer Darstellung führen.
Tomax
User
Beiträge: 31
Registriert: Sonntag 21. August 2016, 08:05

So besser? :-)

Wie könnte ich denn das Anzeige-Element übergeben? Es geht um dr_label und dz_label, die aktualisiert werden sollen.

Was verwende ich denn besser statt place()?

Code: Alles auswählen

def mod_dr_dz(betrag, dr_dz):
    with open('livedaten.csv', 'r') as file:
        data = file.readlines()
    
    if dr_dz == "dr":
        data[1] = str(round(float(data[1]) + betrag, 2)) + "\n"
    else:
        data[0] = str(round(float(data[0]) + betrag, 2)) + "\n"
    with open('livedaten.csv', 'w') as file:
        file.writelines(data)



def create_window():
    window = tk.Toplevel(hauptfenster)
    window.title("Werte simulieren")
    window.geometry("160x400")
    window.configure(bg=bg_farbe)
    window.resizable(width=False, height=False)
    tk.Label(window, text="Drehzahl", bg=bg_farbe, font=("Helvetica", 12)).place(x=20, y=20, width=120, height=25)
    tk.Button(window, text="+", command=lambda: mod_dr_dz(20, "dz")).place(x=90, y=50, width=20, height=25)
    tk.Button(window, text="-", command=lambda: mod_dr_dz(-20, "dz")).place(x=50, y=50, width=20, height=25)
    dz_label = tk.Label(window, text=str(drehzahl_lesen()), bg=bg_farbe, font=("Helvetica", 12))
    dz_label.place(x=20, y=80, width=120, height=25)
    tk.Label(window, text="Druck", bg=bg_farbe, font=("Helvetica", 12)).place(x=20, y=110, width=120, height=25)
    tk.Button(window, text="+", command=lambda: mod_dr_dz(0.1, "dr")).place(x=90, y=140, width=20, height=25)
    tk.Button(window, text="-", command=lambda: mod_dr_dz(-0.1, "dr")).place(x=50, y=140, width=20, height=25)
    dr_label = tk.Label(window, text=str(druck_lesen()), bg=bg_farbe, font=("Helvetica", 12))
    dr_label.place(x=20, y=170, width=120, height=25)
BlackJack

@Tomax: Nicht wirklich besser. Jetzt hast Du einen total kryptischen Funktionsnamen für eine Funktion die eigentlich zwei verschiedene Dinge macht. Und das mit einer Indirektion über einen ebenfalls kryptischen Zeichenkettenwert. Ungetestet:

Code: Alles auswählen

from functools import partial

CSV_FILENAME = 'livedaten.csv'


def change_line_value(filename, line_number, amount):
    with open(filename, 'r') as data_file:
        lines = list(data_file)
    lines[line_number] = '{0:.2f}\n'.format(float(lines[line_number]) + amount)
    with open(filename, 'w') as data_file:
        data_file.writelines(lines)


change_pressure = partial(change_line_value, CSV_FILENAME, 1)
change_number_of_revolutions = partial(change_line_value, CSV_FILENAME, 0)
Das Anzeigeelement übergibst Du genau wie die anderen Argumente auch. Da ist nichts besonderes dran, das ist ein Wert wie alles was man in Python an einen Namen binden kann. Ein objectorientierter Ansatz bleibt trotzdem in Python die bessere Wahl, IMHO. GUIs sind ohne objectorientierte Programmierung (OOP) in Python unübersichtlich.

Alles ist besser als absolute Positionierung mit `place()`. Gibt ja nur zwei Alternativen: `pack()` und `grid()`. In der GUI gesamt kann man die mischen, nur im gleichen Containerwidget sollte man immer nur eines von beidem verwenden.

Die Fenstergrösse braucht man dann auch nicht übergeben, die hängt dann vom Inhalt ab und kann automatisch ermittelt werden.

`hauptfenster` kommt übrigens einfach so magisch aus dem Nichts, das sollte als Argument übergeben werden. Bei `bg_farbe` bin ich mir nicht sicher, vermute aber mal das dort einfach nur die Schreibweise ”falsch” ist — Konstanten werden per Konvention komplett gross geschrieben.

Auf Modulebene stehen üblicherweise nur Definitionen von Konstanten, Funktionen, und Klassen.
Tomax
User
Beiträge: 31
Registriert: Sonntag 21. August 2016, 08:05

Wow, ein Haufen Holz, danke!

Mal sehen ob ich das so kapiere. Werde mich mal durcharbeiten.
Zu schaffen macht mir die Zeile: '{0:.2f}........
Und das partial kannte ich auch noch nicht.

Ich programmiere erst 3 Wochen in Python. Und als alter Mann mit Ü50 braucht man ein bischen Zeit.

Besten Dank jedenfalls!
Tomax
User
Beiträge: 31
Registriert: Sonntag 21. August 2016, 08:05

Ich möchte den neuen, geänderten Wert, der gerade in die Datei geschrieben wurde, dem Label (oder Entry) zuweisen.

Leider habe ich das noch nicht aus deinem code herausfiltern und verstehen können.

Grüsse,

Thomas
BlackJack

@Tomax: Man könnte die `change_line_value()`-Funktion den neuen Wert zurück geben lassen und dann eine weitere Funktion zwischen diese und `command` setzen, die das `Label`-Objekt, die Veränderungsfunktion und den Betrag bekommt, die Veränderungsfunktion aufruft und den Rückgabewert in das `Label` setzt.

Code: Alles auswählen

def change_line_value(filename, line_number, amount):
    with open(filename, 'r') as data_file:
        lines = list(data_file)
    result = float(lines[line_number]) + amount
    lines[line_number] = '{0:.2f}\n'.format(result)
    with open(filename, 'w') as data_file:
        data_file.writelines(lines)
    return result
 
 
change_pressure = partial(change_line_value, CSV_FILENAME, 1)
change_number_of_revolutions = partial(change_line_value, CSV_FILENAME, 0)


def do_change_value(label, change_func, amount):
    label['text'] = change_func(amount, amount)


# ...

    do_change_pressure = partial(
        do_change_value, pressure_label, change_pressure
    )
    increase_pressure = partial(do_change_pressure, 0.1)
    decrease_pressure = partial(do_change_pressure, -0.1)
Das wird alles schnell recht unübersichtlich. Habe ich eigentlich schon objektorientierte Programmierung erwähnt? ;-) Solltest Du wirklich mit anfangen.
Tomax
User
Beiträge: 31
Registriert: Sonntag 21. August 2016, 08:05

Sorry wenn ich zu doof bin.
Wie kann ich das Label als parameter übergeben und in der Funktion verändern?

Ich hatte auf so was gehofft:

Code: Alles auswählen

def mod_dr_dz(amount, line_number, label):
    
    with open(CSV_FILENAME, 'r') as data_file:
        lines = list(data_file)
    neuer_wert = '{0:.2f}\n'.format(float(lines[line_number] + amount))
    lines[line_number] = neuer_wert
    with open(CSV_FILENAME, 'w') as data_file:
        data_file.writelines(lines)
        
    label.delete(0, tk.END)
    label.insert(0, neuer_wert)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Tomax: BlackJack hat Dir quasi schon die Musterlösung geliefert, denn das mischen von zwei Aufgaben (Lesen/Schreib in eine Datei und Ändern eines Labels) gehören auf dem Abstraktionsniveau nicht in eine Funktion.

Raten und Hoffen sind zwei Methoden, mit denen man beim Programmieren nicht weit kommt. Was passiert denn, wenn Du das, was Du hoffst einfach mal ausprobierst? Entweder es funktioniert (dann hast Du Glück gehabt), oder wie in Deinem Fall, es gibt eine Fehlermeldung anhand derer man erkennen kann, was falsch läuft.
Tomax
User
Beiträge: 31
Registriert: Sonntag 21. August 2016, 08:05

Hab ich probiert, natürlich kein Glück gehabt.

Aber was kann ich tun, wenn mir das System sagt:
AttributeError: 'Label' object has no attribute 'delete'

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

@Tomax: dann solltest Du in der Dokumentation nachlesen, welche Attribute ein Label hat und wie man den Inhalt wirklich setzt; da ist auch ein kleines Beispiel, wie man das mit veränderlichen Inhalten sauberer lösen kann.
Tomax
User
Beiträge: 31
Registriert: Sonntag 21. August 2016, 08:05

Habs gefundem danke für die Hilfe!

label.config()

Thomas
Antworten