Problem beim Auslesen eines Entrys

Fragen zu Tkinter.
Antworten
Schlange
User
Beiträge: 15
Registriert: Freitag 24. August 2018, 12:03

Hallo,
ich schreibe zur Zeit ein Programm zum berechnen der freiwerdenden Energie einer Kernreaktion.
Die Benutzeroberfläche funktioniert zwar einwandfrei und ich komme auch an die Werte der Scales,
jedoch kann ich die Entrys zur Eingabe der Edukt- und Produktmassen nicht auslesen.
Ich erhalte lediglich die Fehlermeldung: "NameError: name 'massE_1' is not defined"

Hier ist mein bisheriger Code:

Code: Alles auswählen

import tkinter.font as tkf
from tkinter import *

'''
#Formeln
E = 'm*c**2'
m = 'M*n'
n = 'N/A'

#Konstanten
A    = 6.02214086*10**23
J_eV = 6.24*10**18
eV_J = 1.67*10**-19
'''

#andere
EPnumbers = list(range(1, 5))

M_alphaE    = 0
M_betaE     = 0
M_neutronE  = 0

M_alphaP    = 0
M_betaP     = 0
M_neutronP  = 0

def Interface():
    def value_alpha_E  (value):
        global M_alphaE
        M_alphaE = (2*(2*(2.3*10**6)+4.8*10**6)+2*(2*(4.8*10**6))+2.3*10**6)*float(value)
        
    def value_beta_E   (value):
        global M_betaE
        M_betaE  = 0.511*10**6*float(value)
        
    def value_neutron_E(value):
        global M_neutronE
        M_neutronE = (2.3*10**6+2*4.8*10**6)*float(value)

    def value_alpha_P  (value):
        global M_alphaP
        M_alphaP = (2*(2*(2.3*10**6)+4.8*10**6)+2*(2*(4.8*10**6))+2.3*10**6)*float(value)
        
    def value_beta_P   (value):
        global M_betaP
        M_betaP  = 0.511*10**6*float(value)
        
    def value_neutron_P(value):
        global M_neutronP
        M_neutronP = (2.3*10**6+2*4.8*10**6)*float(value)

    def calculate():
        print(M_alphaE, M_betaE, M_neutronE, M_alphaP, M_betaP, M_neutronP)
        print(massE_1)
        
    GUI = Tk()
    GUI.wm_title('Energy-Calculator')
    #GUI.iconbitmap('atom.ico')

    #Schriftarten
    Font_h = tkf.Font(family = 'Arial', size = 50)
    Font_c = tkf.Font(family = 'Arial', size = 10)

    #Frames
    top    = Frame(GUI)
    main   = Frame(GUI)
    bottom = Frame(GUI)

    #content_top
    header = Label(top, text = 'Energy Calculator', font = Font_h)
    
    #Edukte
    for n in EPnumbers:
        exec('Edukt_'  + str(n) + ' = Frame(main) ')
        exec('titleE_' + str(n) + ' = Label(master = Edukt_' + str(n) + ', text = "Masse Edukt'  + str(n) + '", font = Font_c)')
        exec('massE_'  + str(n) + ' = Entry(Edukt_'  + str(n) + ')')
        exec('Edukt_'  + str(n) + '.grid(column = '  + str(n) + ', row = 0, pady = 20)')
        exec('titleE_' + str(n) + '.pack()')
        exec('massE_'  + str(n) + '.pack()')

    n_alphaE     = Label(main, text = '\u03B1', font = Font_c)
    n_betaE      = Label(main, text = '\u03B2', font = Font_c)
    n_neutronenE = Label(main, text = 'n'     , font = Font_c)

    n_alphaE    .grid(column = 1, row = 1)
    n_betaE     .grid(column = 2, row = 1)
    n_neutronenE.grid(column = 3, row = 1)
    
    alphaE   = Scale(main, from_ = 0, to = 10, orient = HORIZONTAL, command = value_alpha_E  )
    betaE    = Scale(main, from_ = 0, to = 10, orient = HORIZONTAL, command = value_beta_E   )
    neutronE = Scale(main, from_ = 0, to = 10, orient = HORIZONTAL, command = value_neutron_E)

    alphaE  .grid(column = 1, row = 2)
    betaE   .grid(column = 2, row = 2)
    neutronE.grid(column = 3, row = 2)
        

    #Produkte
    for n in EPnumbers:
        exec('Produkt_' + str(n) + ' = Frame(main) ')
        exec('titleP_'  + str(n) + ' = Label(master = Produkt_' + str(n) + ', text = "Masse Produkt'  + str(n) + '", font = Font_c)')
        exec('massP_'   + str(n) + ' = Entry(Produkt_'  + str(n) + ')')
        exec('Produkt_' + str(n) + '.grid(column = '  + str(n) + ', row = 3, pady = 20)')
        exec('titleP_'  + str(n) + '.pack()')
        exec('massP_'   + str(n) + '.pack()')

    n_alphaP     = Label(main, text = '\u03B1', font = Font_c)
    n_betaP      = Label(main, text = '\u03B2', font = Font_c)
    n_neutronenP = Label(main, text = 'n'     , font = Font_c)

    n_alphaP    .grid(column = 1, row = 4)
    n_betaP     .grid(column = 2, row = 4)
    n_neutronenP.grid(column = 3, row = 4)
    
    alphaP   = Scale(main, from_ = 0, to = 10, orient = HORIZONTAL, command = value_alpha_P  )
    betaP    = Scale(main, from_ = 0, to = 10, orient = HORIZONTAL, command = value_beta_P   )
    neutronP = Scale(main, from_ = 0, to = 10, orient = HORIZONTAL, command = value_neutron_P)

    alphaP  .grid(column = 1, row = 5)
    betaP   .grid(column = 2, row = 5)
    neutronP.grid(column = 3, row = 5)

    start = Button(bottom, text = 'BERECHNEN', font = Font_c, command = calculate)
    start.grid(column = 0, row = 0, pady = 20)

    #positioning_Frames
    top   .grid(column = 0, row = 1)
    main  .grid(column = 0, row = 2)
    bottom.grid(column = 0, row = 3)
    
    #positioning_top
    header.pack()
    
    GUI.mainloop()

Interface()
Ich hoffe, dass mir jemand weiterhelfen kann.
Benutzeravatar
sls
User
Beiträge: 480
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

Sternimporte sollten vermieden werden, da du dir unglaublich viel Zeug in dein Modul lädst, was du gar nicht brauchst. Außerdem kann es zu Namenskollisionen mit gleichnamigen Klassen anderer Module kommen.

Was ist `andere`?

Auf Modulebene sollten nur Klassen, Funktionen und Konstanten stehen, M_* usw. sind keine Konstanten, neben der kryptischen Namensgebung ist die Deklaration mit 0 überflüssig, vergiss außerdem gleich wieder dass es `global` gibt. Dadurch können extrem hässliche und schwer zu erkennende Fehler entstehen, da du nicht genau erkennst welche Funktion gerade auf die globale Variable zugreift und welchen Zustand diese somit hat. Verschachtelte Funktionen sind in Python unüblich, benutze eine Klasse, trenne dabei die GUI- von der Geschäftslogik.

`massE_1` wurde nie deklariert, ist also völlig unbekannt. Wo soll das herkommen? Bei Schlüsselwortargumenten sollte man keine Leerzeichen machen: family='Arial' statt family = 'Arial'.

Wenn du "vermutest" exec() könnte dein Problem lösen, liegst du vermutlich falsch. Hier gibt es saubere Lösungen die weniger fehleranfällig, schneller und einfacher zu implementieren sind.

Vermeide diese Horrorleerzeichen, bei einer Zuweisung gibt es nur ein Leerzeichen zwischen Bezeichner und eines zwischen Wert und ist-Zeichen: variable = wert, nicht variable = wert.

Auch wenn du auf eine Funktion / Methode über ein Objekt zugreifst: alpha_e.grid(column=1, row=2) statt alphaE .grid(column = 1, row = 2) (und auch hier den Bezeichner alpha_e in was aussagekräftiges)

GUI-Programmierung ist schwer. Der Code ist wenig strukturiert und ergibt so erstmal keinen Sinn.
When we say computer, we mean the electronic computer.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Schlange: Sternchenimporte solltest Du vermeiden, das holt Dir unkontrolliert Namen in Deinen Namensraum. tkinter wird üblicherweise als `import tkinter as tk` importiert und alle Namen über z.B. tk.Label angesprochen.
Mehrzeilige Strings sind kein Ersatz für Kommentare.

Vermeide Abkürzungen, was bedeutet das M oder das E? Variablennamen werden generell klein_mit_unterstrich geschrieben, also alpha_energy.
Benutze keine globalen Variablen. Vergiß dass es `global` überhaupt gibt. Alles was eine Funktion braucht, bekommst sie über ihre Argumente, Ergebnisse werden per `return` zurückgegeben. Benutze keine verschachtelten Funktionen. Schreibe Zahlen als Konstanten vorneweg. In Deinen Formeln kommen etliche male 2.3*10**6 und 4.8*10**6 vor. Wären das Konstanten, könnte man anhand des Namens schon erkennen, was die Formel ist.

Vergiss dass es `exec` überhaupt gibt. Benutze Listen!

Code: Alles auswählen

from functools import partial
import tkinter.font as tkf
import tkinter as tk

# Formeln
# E = 'm*c**2'
# m = 'M*n'
# n = 'N/A'

# Konstanten
# A    = 6.02214086*10**23
# J_eV = 6.24*10**18
# eV_J = 1.67*10**-19

REST_ENERGY_UP_QUARK = 2.3*10**6
REST_ENERGY_DOWN_QUARK = 4.8*10**6
REST_ENERGY_ELECTRON = 0.511*10**6 # in eV

NUMBER_OF_PARTICLES = 4

def calculate_alpha_mass(value):
    return (2 * (2*REST_ENERGY_UP_QUARK + REST_ENERGY_DOWN_QUARK) + 4*REST_ENERGY_DOWN_QUARK + REST_ENERGY_UP_QUARK) * value

def calculate_beta_mass(value):
    return REST_ENERGY_ELECTRON * value

def calculate_neutron_mass(value):
    return (REST_ENERGY_UP_QUARK + 2*REST_ENERGY_DOWN_QUARK) * value


def calculate(
        masses_educt, educt_alpha, educt_beta, educt_neutron,
        masses_product, product_alpha, product_beta, product_neutron):
    print(calculate_alpha_mass(educt_alpha.get()))

def main():
    gui = tk.Tk()
    gui.wm_title('Energy-Calculator')
    #gui.iconbitmap('atom.ico')

    #Schriftarten
    font_h = tkf.Font(family='Arial', size=50)
    font_c = tkf.Font(family='Arial', size=10)

    #Frames
    top = tk.Frame(gui)
    tk.Label(top, text='Energy Calculator', font=font_h).pack()
    top.grid(column=0, row=1)
    

    #Edukte
    main = tk.Frame(gui)
    masses_educt = []
    for n in range(1, NUMBER_OF_PARTICLES+1):
        frame = tk.Frame(main)
        frame.grid(column=n, row=0, pady=20)
        tk.Label(frame, text="Masse Edukt {}".format(n), font=font_c).pack()
        mass = tk.Entry(frame)
        mass.pack()
        masses_educt.append(mass)

    tk.Label(main, text='\u03B1', font=font_c).grid(column=1, row=1)
    tk.Label(main, text='\u03B2', font=font_c).grid(column=2, row=1)
    tk.Label(main, text='n', font=font_c).grid(column=3, row=1)
    
    educt_alpha = tk.Scale(main, from_=0, to=10, orient=tk.HORIZONTAL)
    educt_alpha.grid(column=1, row=2)
    educt_beta = tk.Scale(main, from_=0, to=10, orient=tk.HORIZONTAL)
    educt_beta.grid(column=2, row=2)
    educt_neutron = tk.Scale(main, from_=0, to=10, orient=tk.HORIZONTAL)
    educt_neutron.grid(column=3, row=2)

    #Produkte
    masses_product = []
    for n in range(1, NUMBER_OF_PARTICLES+1):
        frame = tk.Frame(main)
        frame.grid(column=n, row=3, pady=20)
        tk.Label(frame, text="Masse Produkt {}".format(n), font=font_c).pack()
        mass = tk.Entry(frame)
        mass.pack()
        masses_product.append(mass)

    tk.Label(main, text='\u03B1', font=font_c).grid(column=1, row=4)
    tk.Label(main, text='\u03B2', font=font_c).grid(column=2, row=4)
    tk.Label(main, text='n', font=font_c).grid(column=3, row=4)

    product_alpha = tk.Scale(main, from_=0, to=10, orient=tk.HORIZONTAL)
    product_alpha.grid(column=1, row=5)
    product_beta = tk.Scale(main, from_=0, to=10, orient=tk.HORIZONTAL)
    product_beta.grid(column=2, row=5)
    product_neutron = tk.Scale(main, from_=0, to=10, orient=tk.HORIZONTAL)
    product_neutron.grid(column=3, row=5)
    main.grid(column=0, row=2)

    bottom = tk.Frame(gui)
    tk.Button(bottom, text='BERECHNEN', font=font_c, command=partial(calculate,
        masses_educt, educt_alpha, educt_beta, educt_neutron,
        masses_product, product_alpha, product_beta, product_neutron
    )).grid(column=0, row=0, pady=20)
    bottom.grid(column=0, row=3)
    
    gui.mainloop()


if __name__ == '__main__':
    main()
Hier merkt man schon, dass die Anzahl der Parameter für `calculate` viel zu groß ist, und man eigentlich eine Klasse braucht.
Schlange
User
Beiträge: 15
Registriert: Freitag 24. August 2018, 12:03

Vielen Dank für die viele Mühe und die guten Tips!

Ich finde lange Variablennamen zwar als störend, kann aber nachvollziehen, dass es eindeutig Sinnvoller ist sie zu verwenden,
auch für den Fall, dass man sich zu einem späteren Zeitpunkt erneut in das Programm einarbeiten muss.

"funktiontools" kannte ich bisher noch nicht, habe jetzt aber mal in die Dokumentation geschaut und ich finde es ziemlich praktisch!
Vielen Dank dafür!
Antworten