tkinter Problem mit Ausgabe in GUI

Fragen zu Tkinter.
Antworten
LiiNKSYS
User
Beiträge: 11
Registriert: Freitag 30. Dezember 2022, 17:38

Hallo,

Ich habe folgendes Problem:
Das Programm und das Gui funktionieren, nur wird sobald ich eine Teilenummer gesucht habe das Label mit den Entsprechenden informationen angezeigt und wenn ich nun eine neue Eingabe mache überlappen die Labels teilweise. Wie kann ich nach erfolgreichem anzeigen eines Labels dieses wieder löschen oder entfernen, um den Platz für die nächste Ausgabe wieder frei zu machen?
Ich danke euch schonmal im Voraus!

Code: Alles auswählen

from tkinter import *
import tkinter
import json

window = Tk()
window.title("Lagerprogramm v1.0")
window.geometry('1000x600')

# Labels
input_field = Entry(window)
input_field_Bestand = Entry(window)
label1 = tkinter.Label(window, text='Teilenummer: ')
label2 = tkinter.Label(window, text='Bestandskorrektur: ')
label3 = tkinter.Label(window, text='Ausgabe: ')

# Sichtbar machen der Labels
label1.grid(row=0, column=0)
label2.grid(row=7, column=0)
label3.grid(row=2, column=1)
input_field.grid(row=0, column=1)
input_field_Bestand.grid(row=7, column=1)
Label_Ausgabe = tkinter.Label(window)


with open("inventar.json", 'r') as file:
    Teile = json.load(file)


# Funktionen
def read_input_field(*event):
    eingabefeld = input_field.get()
    for teil in Teile:
        if teil['Teilenummer'] == eingabefeld:
            Label_Ausgabe = tkinter.Label(window, text=(f"{teil}"))
            Label_Ausgabe.grid(row=3, column=1)
        if teil['Teilenummer'] != eingabefeld:
            label4 = tkinter.Label(window, text=(f'{eingabefeld} konnte nicht gefunden werden!'))
            label4.grid(row=2, column=1)

        if (eingabefeld == ''):
            

def close_window(*event):
    window_close_cmd = window.quit()



# Buttons
ok_button = Button(window, text='Ok', command=read_input_field)
ok_button.grid(row=1, column=1)
window.bind('<Return>', read_input_field)
window.bind('<Escape>', close_window)

window.mainloop()
Benutzeravatar
Axel-WAK
User
Beiträge: 62
Registriert: Dienstag 29. November 2022, 11:52

Vielleicht eine Variable nutzen um den Label Text zu ändern.

Code: Alles auswählen

from tkinter import Tk, StringVar, Label, Button
master = Tk()

def change_text():
    my_var.set("593838")

my_var = StringVar()
my_var.set("12579")
label = Label(master,textvariable=my_var,fg="#222")
button = Button(master,text="Klick",command = change_text)
button.pack()
label.pack()

master.mainloop()
OS: LMDE5 *** Homepage *** Github Seite
Benutzeravatar
__blackjack__
User
Beiträge: 13099
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@LiiNKSYS: Man erzeugt normalerweise die GUI *einmal* und ändert deren Inhalt, statt immer wieder Elemente hinzuzufügen und zu löschen.

Sternchen-Importe sind Böse™. Da holt man sich gerade bei `tkinter` fast 140 Namen ins Modul von denen nur ein kleiner Bruchteil verwendet wird. Auch Namen die gar nicht in `tkinter` definiert werden, sondern ihrerseits von woanders importiert werden. Das macht Programme unnötig unübersichtlicher und fehleranfälliger und es besteht die Gefahr von Namenskollisionen.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Funktionen (und Methoden) bekommen alles was sie ausser Konstanten benötigen, als Argument(e) übergeben.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

Man gibt keine Grössen als Pixelangaben vor. Die Grösse eines Fensters ergibt sich automatisch aus dem Inhalt.

Erstellen von Anzeigeelementen und deren Anordnung sollte man nicht komplett in zwei Blöcke trennen. Das macht es schwieriger nachzuvollziehen wie die GUI aufgebaut wird, und man hat unnötige Mehrarbeit wenn man davon Teile in eigene Funktionen oder Klassen herausziehen will. Es ist auch gar nicht konsequent durchgezogen worden.

Es empfiehlt sich da dann auch die Elemente nicht nach Typ zu sortieren, sondern in der Reihenfolge zu erzeugen in der sie angezeigt werden.

Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.

Falsche Kommentare sind schlimmer als keine Kommentare. Ein Kommentar sollen eventuelle Fragen mit dem Code klären, aber wenn dort falsche Informationen drin stehen, oder gar welche die dem Code direkt wiedersprechen, erreicht man genau das Gegenteil. Der Leser weiss dann nicht was falsch ist, der Code oder der Kommentar. Wenn da steht es geht um Labels und als erstes werden Entries erstellt, verwirrt das mehr als es hilft.

`Label_Ausgabe` wird im Hauptprogramm an ein `Label` gebunden das nirgends angezeigt wird.

Man nummeriert keine Namen. Dann will man sich entweder bessere Namen überlegen, oder gar keine Einzelnamen/-werte verwenden, sondern eine Datenstruktur. Oft eine Liste. Man muss aber auch gar nicht jedes Zwischenergebnis an einen Namen binden.

Beim `grid()` sollte man nich willkürliche Lücken bei den Spalten/Zeilen lassen.

Beim öffnen der JSON-Datei fehlt entweder die Angabe der Kodierung, oder man sollte die als Binärdatei öffnen.

Wofür sollte denn `window_close_cmd` stehen? Es macht keinen Sinn den Rückgabwert von der `quit()`-Methode an diesen Namen zu binden.

`event` ist kein sinnvoller Name für ein *-Argument. Das * ist hier aber auch fraglich, weil da ja tatsächlich (potentiell) nur *ein* Argument übergeben wird, nämlich das Ereignisobjekt. Wenn das Optional ist, dann gibt man dem einen Defaultwert und nimmt nicht einfach beliebig viele Argumente entgegegen.

Die `read_input_field()`-Funktion braucht auch einiges an Argumenten was sie da so verwendet.

`eingabefeld` wär ein guter Name für ein Eingabefeld, aber nicht den *Inhalt* von einem Eingabefeld.

Wenn man in einem ``if`` genau das Gegenteil von der Bedingung des ``if`` davor prüft, sollte das in der Regel eigentlich ein ``else`` sein.

Um die Bedingung bei ``if`` braucht es keine unnötigen Klammern.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import json
import tkinter as tk
from functools import partial


def read_input_field(teile, input_field, ausgabelabel, _event=None):
    teilenummer = input_field.get().strip()
    for teil in teile:
        #
        # FIXME Die Logik hier stimmt so noch nicht.
        #
        if teil["Teilenummer"] == teilenummer:
            ausgabelabel["text"] = str(teil)
        else:
            ausgabelabel[
                "text"
            ] = f"{teilenummer} konnte nicht gefunden werden!"

        # if teilenummer == "":


def main():
    with open("inventar.json", "rb") as file:
        teile = json.load(file)

    window = tk.Tk()
    window.title("Lagerprogramm v1.0")

    tk.Label(window, text="Teilenummer: ").grid(row=0, column=0)
    input_field = tk.Entry(window)
    input_field.grid(row=0, column=1)

    ok_button = tk.Button(window, text="Ok")
    ok_button.grid(row=1, column=1)

    tk.Label(window, text="Ausgabe: ").grid(row=2, column=1)
    ausgabelabel = tk.Label(window)
    ausgabelabel.grid(row=2, column=1)

    tk.Label(window, text="Bestandskorrektur: ").grid(row=7, column=0)
    input_field_bestand = tk.Entry(window)
    input_field_bestand.grid(row=3, column=1)

    callback = partial(read_input_field, teile, input_field, ausgabelabel)
    ok_button["command"] = callback
    window.bind("<Return>", callback)
    window.bind("<Escape>", lambda _event: window.quit())

    window.mainloop()


if __name__ == "__main__":
    main()
Letztlich wird man für jede nicht-triviale GUI nicht um objektorientierte Programmierung (OOP) herum kommen. Also eigene Klassen schreiben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten