Zugriff auf Variabeln

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
BerndBen
User
Beiträge: 2
Registriert: Donnerstag 15. April 2021, 08:53

Guten Tag,
als Python-Anfänger habe ich Probleme auf Variabeln zuzugreifen.

Ich habe mit tkinter ein Frame mit MenuBar erstellt. Von dort rufe ich eine Methode auf
die mir bestimmte Labels und Entry's auf diesem Frame abbilden. Mit einem Button möchte ich
nun in einer Methode die eingegebenen Werte speichern, aber hier ist dieses Entry nicht bekannt!
Hier mein code:

Code: Alles auswählen

from tkinter import *

LPwindow = Tk()
LPwindow.title("Leiterplatten Bestellungen")
LPwindow.geometry("800x600")# X Y

def saveNewPi():
    piAnzahl = int(entryAnz.get()) HIER IST DAS PROBLEM


def piInputView():
#Labels  
    labSn = Label(LPwindow, text="LP-Artikelnummer:", font=(12, 12))
    labSn.place(relx = 0.125, rely = 0.055, anchor = 'nw')
    labAnz = Label(LPwindow, text="Anzahl:", font=(12, 12))
    labAnz.place(relx = 0.225, rely = 0.10, anchor = 'nw')
#Eingabefelder
    entrySn = Entry(LPwindow, font = (12, 12))
    entrySn.place(x = 240, y = 35, width = 100, height = 20)
    entryAnz = Entry(LPwindow, font = (12, 12))
    entryAnz.place(x = 240, y = 60, width = 100, height = 20)
#Button
    btnSave = Button(LPwindow, text = "Speichern", height = 1, width = 10, command = saveNewPi)
    btnSave.place(relx = 0.3, rely = 0.40, anchor = 'nw')

   
#MenuBar
menubar = Menu(LPwindow, background = '#FF8000', foreground = "black", activebackground = 'white', activeforeground = 'black')
file = Menu(menubar, tearoff = 0,  foreground =  'black')
file.add_command(label="Neue PI eingeben", command = piInputView)
file.add_separator()
file.add_command(label='Beenden', command = LPwindow.quit)
menubar.add_cascade(label = "Datei", menu = file)

edit = Menu(menubar, tearoff = 0)
edit.add_command(label="Selektiert nach Artikel")
menubar.add_cascade(label = "Auswertungen", menu = edit)

LPwindow.config(menu = menubar)
LPwindow.mainloop()
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

Benutze keine *-Importe, weil die die Herkunft der Namen verschleiert.
Benutze keine Abkürzungen, weil das den Code schlecht Lesbar macht. Was sind denn labsn? Und was ist ein LPwindow? Ich höre nur noch CDs.
Variablennamen und Funktionen werden nach Konvention komplett klein geschrieben.
Fenster werden normalerweise einmal am Anfang komplett aufgebaut und nicht nachträglich noch Elemente hinzugefügt.
place darf man nicht benutzen, weil das bei unterschiedlichen Systemen mit unterschiedlichen Bildschirmauflösungen zu nicht benutzbaren Fenstern führt.
Alles was eine Funktion braucht, muß sie auch über ihre Argumente bekommen. `entryAnz` ist aber kein Argument von saveNewPi.
Und für jede nicht-triviale GUI braucht man Klassendefinitionen. Bevor Du also mit GUIs anfängst, lerne wie man Klassen benutzt.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@BerndBen: Du schreibst Du willst die Eingaben in einer Methode verarbeiten, aber Du hast da keine Methode sondern eine Funktion. Für nicht-triviale GUIs braucht man aber tatsächlich objektorientierte Programmierung (OOP), also tatsächlich Methoden.

Sternchen-Importe sind Böse™. Da holt man sich gerade bei `tkinter` fast 200 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 sollten alles was sie ausser Konstanten benötigen als Argument(e) übergeben bekommen.

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

Namen sollten keine kryptischen Abkürzungen enthalten und mehrere Worte in einem Namen in der richtigen Reihenfolge geschrieben werden.

Funktions- und Methodennamen beschreiben in der Regel die Tätigkeit, welche die Funktion/Methode durchführt, damit der Leser weiss was da passiert und um Funktionen/Methoden leichter von eher passiven Werten unterscheiden zu können.

Kommentare sollten passend zum Quelltext eingerückt werden, weil sie sonst den Vorteil das man an der Einrückung die Programmstruktur ablesen kann, kaputt machen.

Der Code sollte nicht nach den Widget-Typen sortiert sein die da erzeugt werden, sondern der Anzeigereihenfolge entsprechen, damit man sich die GUI leichter vorstellen kann, und auch leichter Codeteile in andere Funktionen/Methoden auslagern kann.

Das `tkinter`-Modul hat Konstanten für Zeichenketten die bei bestimmten Argumenten feste Werte annehmen kann, wie beispielsweise bei `anchor`. Die sollten man literalen Zeichenketten vorziehen.

Zwischenstand:

Code: Alles auswählen

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


def save_new_pi(anzahl_entry):
    pi_anzahl = int(anzahl_entry.get())
    print(pi_anzahl)


def create_pi_input_view(master):
    tk.Label(master, text="LP-Artikelnummer:").place(
        relx=0.125, rely=0.055, anchor=tk.NW
    )
    artikelnummer_entry = tk.Entry(master)
    artikelnummer_entry.place(x=240, y=35, width=100, height=20)

    tk.Label(master, text="Anzahl:").place(relx=0.225, rely=0.10, anchor=tk.NW)
    anzahl_entry = tk.Entry(master)
    anzahl_entry.place(x=240, y=60, width=100, height=20)

    tk.Button(
        master, text="Speichern", command=partial(save_new_pi, anzahl_entry)
    ).place(relx=0.3, rely=0.40, anchor=tk.NW)


def main():
    root = tk.Tk()
    root.title("Leiterplatten Bestellungen")
    root.geometry("800x600")

    main_menu = tk.Menu(
        root,
        background="#FF8000",
        foreground="black",
        activebackground="white",
        activeforeground="black",
    )
    
    file_menu = tk.Menu(main_menu, tearoff=False, foreground="black")
    file_menu.add_command(
        label="Neue PI eingeben", command=partial(create_pi_input_view, root)
    )
    file_menu.add_separator()
    file_menu.add_command(label='Beenden', command=root.quit)
    main_menu.add_cascade(label="Datei", menu=file_menu)

    auswertungen_menu = tk.Menu(main_menu, tearoff=False)
    auswertungen_menu.add_command(label="Selektiert nach Artikel")
    main_menu.add_cascade(label="Auswertungen", menu=auswertungen_menu)

    root.config(menu=main_menu)
    root.mainloop()


if __name__ == "__main__":
    main()
Das Programm hat aber Probleme. Jedes mal wenn man den "Neue PI eingaben"-Menüpunkt aufruft, werden immer wieder neue Eingabeelemente erstellt. Man erstellt deshalb GUIs einmal am Anfang komplett. Falls in dem Fenster mehrere Inhalte darstellen soll, zwischen denen gewechselt werden soll, dann macht man genau das: man erstellt mehrere Frames, die alle übereinander in einer `grid()`-Zelle liegen, und holt dann immer den Inhalt nach vorne, den man gerade anzeigen möchte.

Man verwendet kein `place()`. Auch relative Angaben helfen nicht kaputte GUIs zu verhindern. Bei mir wird beispielsweise das erste Label nicht komplett dargestellt; das verschwindet hinter dem Eingabefeld:
Bild
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten