Übernahme der Entry Widgets für Diagramme merkwürdig

Fragen zu Tkinter.
Antworten
bremen_hs_1992
User
Beiträge: 23
Registriert: Montag 16. November 2020, 15:11

Hallo Leute,
Ich schreibe ein GUI Programm zur Berechnung von Einsparpotenzial von Asynchronmotoren bei wechsel zu Synchron Reluktanzmotoren.

Bei der Eingabe von zahlen in den Eingabefeldern skalliert python das Balkendiagramm nie ab 0, auch wenn ich ylim(0,8000) eingebe(dann spinnt das Diagramm komplett)

Dies geschieht jedoch nur wen ich es in der funktion "def get_value(): ausführe.

Wenn man für die Balkenwerte irgendwelche zahlen nimmt anstatt die Variable wo die Eingabe gespeichert wird, klappt es einwandfrei. Irgendwie macht das keinen sinn und mir fällt keine Lösung dazu ein.

Code: Alles auswählen

from tkinter import *
from math import *
import matplotlib.pyplot as plt
import numpy as np

main = Tk()
main.geometry('850x650')
main.title('Energieverbrauchsrechner für Asynchron und Synchron Reluktanzmotoren')

# Eingabefeld Entry Widget ---------------------------------------------------------

def evaluate(event):
    res.configure(text = "Ergebnis: " + str(eval(entry.get())))


entry = Entry(main)
entry.bind("<Return>", evaluate)
entry.place(x=380,y=140)

entry2 = Entry(main)
entry2.bind("<Return>", evaluate)
entry2.place(x=380,y=230)

entry3 = Entry(main)
entry3.bind("<Return>", evaluate)
entry3.place(x=380,y=310)

entry4 = Entry(main)
entry4.bind("<Return>", evaluate)
entry4.place(x=380,y=390)

entry5 = Entry(main)
entry5.bind("<Return>", evaluate)
entry5.place(x=380,y=470)


# Radiobuttons Energieeffizienzklasse -----------------------------------------------



v = IntVar()
v.set(1)  # initializing the choice, i.e. Python

languages = [
    ("IE1",1),
    ("IE2",2),
    ("IE3",3)    
]

def ShowChoice():
    printv.get()

Label(main, 
      text="""Energieeffizienzklasse:""",
      justify = LEFT).place(x=260,y=35)

for txt, val in languages:
    Radiobutton(main, 
                text=txt, 
                variable=v,pady=5, 
                command=ShowChoice,
                value=val).pack()
    
#Einspeichern der Leistung und Betriebsstundenzahl in Variable --------------------------------------------------------------------------------------------------


def get_value():
    KW = entry.get()
    _100_ = entry2.get()
    _75_ = entry3.get()
    _50_ = entry4.get()
    _25_ = entry5.get()
    fig, ax = plt.subplots()
    Last = ('100%', '75%', '50%', '25%')
    Betriebsstunden = [_100_,_75_,_50_,_25_]
    y_pos = np.arange(len(Last))
    plt.title('Lastprofil')
    plt.ylabel('Betriebsstunden pro Jahr')
    plt.xlabel("Lastbereich")
    plt.bar(y_pos, Betriebsstunden, align='center', alpha=0.6)
    ax.set_xticks(range(len(Last)))
    ax.set_xticklabels(Last, rotation='vertical')
    plt.show()
    
#Buttons & Labels --------------------------------------------------------------------------------------------------
    
    
button = Button(main, text="Berechnung starten!", command=get_value)
buttonquit = Button(main, text='Programm schließen!', command=main.quit).place(x=550,y=600)

label1 = Label(main,text='Betriebsstunden im Jahr')
label2 = Label(main,text='Lastbereich des Motors')
label3 = Label(main,text='100%')
label4 = Label(main,text='75%')
label5 = Label(main,text='50%')
label6 = Label(main,text='25%')
msg = Message(main,text='Rechner zur Ermittlung von Einsparpotenzial und Amortisationszeit zwischen Asynchron- & Synchron Reluktanzmotoren')
label7 = Label(main,text='Bemessungsleistung des Asynchronmotors in KW:')

msg.config(bg='lightgreen', font=('times', 15, 'italic'),relief=RIDGE)

#Platzieren der Buttons,Sliders,Labels ----------------------------------------------------------------------------------------------



button.place(x=380,y=600)
label1.place(x=370,y=190)
label2.place(x=10,y=190)
label3.place(x=10,y=230)
label4.place(x=10,y=310)
label5.place(x=10,y=390)
label6.place(x=10,y=470)
label7.place(x=370,y=100)

msg.place(x=10,y=10)



mainloop()
Vielleicht hat ja jemand eine Idee
schonmal vielen dank!
Benutzeravatar
__blackjack__
User
Beiträge: 13121
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@bremen_hs_1992: 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. Von dem `math`-Sternchen-Import wird anscheinend gar nichts verwendet.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Dann sollte das jeztige `main` natürlich anders heissen. Beispielsweise `main_window`.

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

Absolute Grössen- und Positionsangaben sind keine gute Idee. So sieht das bei mir aus:
Bild
Auf anderen Rechnern, mit anderen Einstellungen können mehr Anzeigeelemente überlappen oder ausserhalb des angezeigten Bereichs liegen. Deswegen verwendet man `geometry()` und insbesondere `place()` nicht. Sondern `pack()` und `grid()` und gegebenfalls weitere `Frame`-Objekte um die Anordnung der Anzeigeelemente zu machen. Dann passt alles, nichts überlappt, und das Fenster ist automatisch gross genug, so dass alles angezeigte auch hinein passt.

Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur aus ihnen bestehen, oder gar nur einzelne Buchstaben sein. Wenn man `message` meint, sollte man nicht nur `msg` schreiben. Nicht `txt` wenn man `text` meint, oder `val` wenn man `value` meint, und so weiter. Einbuchstabige Namen gehen fast nur bei ganzen Zahlen die als Index oder Laufvariablen verwendet werden (`i`, `j`, `k`) und Koordinaten (`x`, `y`, `z`). In allen anderen Fällen ist ein sprechender Bezeichner in der Regel deutlich besser.

`languages` ist kein passender Name für Energieeffizienzklassen.

Man nummeriert auch keine Namen durch. Man will dann entweder bessere Namen oder gar keine Einzelnamen, sondern eine Datenstruktur. Oft eine Liste.

`Message` ist veraltet, man kann mehrzeiligen Text auch in `Label`-Widgets anzeigen.

Der Inhalt von `ShowChoice()` sollte wohl etwas anders sein.

`eval()` ist „evil“. Das wertet beliebige Python-Ausdrücke aus und ist deshalb schwierig bis unmöglich gegen Fehler oder gar absichtlichen Schadcode absicherbar. Der Benutzer kann da beliebig im Programm rumpfuschen und alles mögliche mit den Rechten dieses Programms ausführen. Beispielsweise auch Dateien löschen.

Die X-Positionen `y_pos` zu nennen, ist eher ungünstig für das Verständnis des Programms.

`get_value()` macht etwas deutlich anderes als der Name suggeriert.

Zum angesprochenen Problem: Du gibst da keine Zahlen ein. Du gibst Zeichenfolgen ein, die wahrscheinlich aus Ziffern bestehen, aber es sind halt trotzdem Zeichenketten. Wenn Du Zahlen willst, musst Du die umwandeln.

Du solltest da auch a) von den Funktionen weg die auf globalen `Figure`-Objekten operieren und b) das ordentlich in die GUI einbinden und nicht den `show()`-Aufruf das Hauptprogramm blockieren lassen.

Code: Alles auswählen

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

import matplotlib.pyplot as plt
import numpy as np

PERCENTAGES = ["100%", "75%", "50%", "25%"]


def show_choice(efficiency_class_var):
    print(efficiency_class_var.get())


def plot_and_show(rated_output_entry, operating_hours_entries, _event=None):
    rated_output = float(rated_output_entry.get())
    operating_hours = [float(entry.get()) for entry in operating_hours_entries]
    assert len(PERCENTAGES) == len(operating_hours)
    #
    # TODO Von diesen Funktionen weg kommen, die auf globalen Abbildungen
    #   operieren.
    #
    _, ax = plt.subplots()
    plt.title("Lastprofil")
    plt.ylabel("Betriebsstunden pro Jahr")
    plt.xlabel("Lastbereich")
    x_positions = np.arange(len(PERCENTAGES))
    plt.bar(x_positions, operating_hours, align="center", alpha=0.6)
    ax.set_xticks(x_positions)
    ax.set_xticklabels(PERCENTAGES, rotation="vertical")
    #
    # FIXME Blockiert das Programm.
    #
    plt.show()


def main():
    main_window = tk.Tk()
    main_window.title(
        "Energieverbrauchsrechner für Asynchron und Synchron Reluktanzmotoren"
    )
    tk.Label(
        main_window,
        text=(
            "Rechner zur Ermittlung von\n"
            "Einsparpotenzial und\n"
            "Amortisationszeit zwischen\n"
            "Asynchron- & Synchron\n"
            "Reluktanzmotoren"
        ),
        bg="lightgreen",
        font=("times", 15, "italic"),
        relief=tk.RIDGE,
    ).grid(row=0, column=0, rowspan=3)

    efficiency_class_var = tk.IntVar()
    efficiency_class_var.set(1)

    frame = tk.Frame(main_window)
    tk.Label(frame, text="Energieeffizienzklasse:").pack(side=tk.LEFT)
    radiobutton_frame = tk.Frame(frame)

    for text, value in [("IE1", 1), ("IE2", 2), ("IE3", 3)]:
        tk.Radiobutton(
            radiobutton_frame,
            text=text,
            variable=efficiency_class_var,
            pady=5,
            command=partial(show_choice, efficiency_class_var),
            value=value,
        ).pack(side=tk.TOP)

    radiobutton_frame.pack(side=tk.LEFT)
    frame.grid(row=0, column=1)

    tk.Label(
        main_window, text="Bemessungsleistung des Asynchronmotors in KW:"
    ).grid(row=1, column=1)

    rated_output_entry = tk.Entry(main_window)
    rated_output_entry.grid(row=2, column=1)

    tk.Label(main_window, text="Lastbereich des Motors").grid(row=3, column=0)
    tk.Label(main_window, text="Betriebsstunden im Jahr").grid(row=3, column=1)

    operating_hours_entries = []
    row_index = 4
    for row_index, text in enumerate(PERCENTAGES, row_index):
        tk.Label(main_window, text=text).grid(row=row_index, column=0)
        entry = tk.Entry(main_window)
        entry.grid(row=row_index, column=1)
        operating_hours_entries.append(entry)

    row_index += 1
    frame = tk.Frame(main_window)
    do_plot_and_show = partial(
        plot_and_show, rated_output_entry, operating_hours_entries
    )
    rated_output_entry.bind("<Return>", do_plot_and_show)
    tk.Button(
        frame, text="Berechnung starten!", command=do_plot_and_show
    ).pack(side=tk.LEFT)

    tk.Button(
        frame, text="Programm schließen!", command=main_window.quit
    ).pack(side=tk.LEFT)

    frame.grid(row=row_index + 1, column=1)

    main_window.mainloop()


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten