Tkinter GUI für Matlab script

Fragen zu Tkinter.
Antworten
panasonic18
User
Beiträge: 4
Registriert: Sonntag 5. April 2020, 13:12

Hallo zusammen,

ich versuche eine GUI application für ein Matlab script in Tkinter zu programmieren. Die Idee ist, zwei benötigte Variablen über ein Entry-field in das Matlab script einzubinden. Die Idee ist mittels scipy die zwei Input Parameter ("mach number" und "number of expansion Waves") in zwei neuen Matlab-files zu speichern und diese dann in dem main-script einzubinden. Das klappt auch ohne probleme.

Was nicht funktioniert, ist der Input über die Entry-fields. Ich würde gerne die Parameter im entry-field eingeben, diese dann in einer Variablen speichern, welche dann über scipy im Matlab-file gespeichert werden kann. Hier fehlt mir der Ansatz für die Speicherung der Eingabe in einer Variablen.

Ich freue mich über jede Hilfe :)

Mein code:

Code: Alles auswählen

import numpy as np
import scipy.io as io
import tkinter as tk 

root = tk.Tk()

HEIGHT = 500
WIDTH = 600



# Appearance ---------------------------------------------------------------

canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
canvas.pack()

frame = tk.Frame(root, bg="#e3e3e3")
frame.place(relwidth=1, relheight=1)

label = tk.Label(frame, text="Design of a 2D Minimum Length Nozzle ", anchor="c", font=('Helvetica', 8, 'bold'))
label.place(x=250, y=20, height=25, width=250)


# Buttons

button = tk.Button(frame, text="Calculate")
button.place(x=400, y=400, height=25, width=100)

# -------------------------------------------------------------------------------

label8 = tk.Label(frame, text="Input parameters", anchor="w", font=('Helvetica', 8, 'bold'))
label8.place(x=25, y=320, height=25, width=130)

label9 = tk.Label(frame, text="Mach number", anchor="w")
label9.place(x=25, y=360, height=25, width=130)

label10 = tk.Label(frame, text="Number exp. waves", anchor="w")
label10.place(x=25, y=400, height=25, width=130)


v = tk.IntVar()
entry9=tk.Entry(frame, textvariable=v)
entry9.place(x=160, y=360, height=25, width=100)

entry10=tk.Entry(frame)
entry10.place(x=160, y=400, height=25, width=100)


# Matlab section

import matlab.engine
eng = matlab.engine.start_matlab()

# Insert number of expansion waves to matlab

number_of_expansion_waves = 50 # --> Diese Zahl sollte über das Entry-widget eingegeben werden
a={}
a['z'] = number_of_expansion_waves
io.savemat('number_expansion_waves.mat',a)


 # Insert Mach number to matlab

mach_number = 10 # --> Diese Zahl sollte über das Entry-widget eingegeben werden
b={}
b['z1'] = mach_number
io.savemat('mach_number.mat',b)


eng.main(nargout=0)
root.mainloop()
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@panasonic18: Importe gehören an den Anfang des Programms, damit man leicht sehen kann wovon ein Modul abgängig ist.

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

Die Konstruktion mit dem `Canvas` der nicht verwendet wird, und der sowieso komplett von einem `Frame`-Verdeckt wird, macht keinen Sinn. Man verwendet auch kein `place()`. Da sieht die GUI dann im besten Fall komisch/falsch aus, und im schlechtesten Fall ist sie unbenutzbar wenn sich Elemente überdecken, wenn man das auf einem anderen Rechner laufen lässt, also dem auf dem das Entworfen wurde.

Auf meinem Recher ist beispielsweise das eine Label zu kurz für den Text, so dass das „s“ von „waves“ fast nicht mehr sichtbar ist, weil es hinter dem Eingabefeld daneben verschwindet.

Namen sollte man nicht durchnummerieren. Das ist in der Regel ein Zeichen das man sich bessere Namen ausdenken sollte, oder gar keine Einzelwerte haben will, sondern eine Datenstruktur. Oft eine Liste. Im Falle der Labels, deren Nummerierung irrerweise auch noch bei 8 anfängt – warum bitte 8? – braucht man aber auch gar keine Namen. Gleiches gibt auch für `Entry`-Objekte die man nie wieder braucht.

Auch kryptische Abkürzungen laufen dem Sinn von Namen zuwieder. `v` ist kein guter Name. Der Leser erkennt daran überhaupt nicht wofür dieser Name steht – welche Bedeutung der Wert dahinter hat. `eng` kann zudem falsch interpretiert werden. Das ist sowohl ein deutsches Wort, als auch eine Abkürzunge für eine Sprache („english“) als auch eine Abkürzung für eine Art Gleitkommazahlen zu formatieren, wo es dann für „engineering“ steht. Wenn man `engine` meint, sollte man das einfach schreiben.

GUI-Programmierung funktioniert nicht so linear wie Du das runtergeschrieben hast. Bei GUI-Programmierung setzt man die GUI auf und registriert Rückrufe für Ereignisse auf die man reagieren will. Zum Beispiel das eine Schaltfläche gedrückt wurde. Dann ruft man die GUI-Hauptschleife auf und die ruft dann die registrierten Funktionen/Methoden im Falle des Ereignisses auf.

Da man dabei bei jeder nicht-trivialen GUI in der Regel Zustand hat, den man sich über Aufrufe hinweg merken muss, kommt man nicht wirklich lange ohne objektorientierte Programmierung aus.

Beim Speichern der Matlab-Dateien wird hier in extrem kleinen Trippelschrittchen vorgegangen. Das passt locker in eine Zeile, ohne unverständlich zu werden, und man spart sich einen schlechten einbuchstabigen Namen:

Code: Alles auswählen

    a = {}
    a["z"] = number_of_expansion_waves
    io.savemat("number_expansion_waves.mat", a)

    # <=>
    
    io.savemat("number_expansion_waves.mat", {"z": number_of_expansion_waves})
Zwischenstand:

Code: Alles auswählen

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

import matlab.engine
import numpy as np
import scipy.io as io

HEADLINE_FONT = ("Helvetica", 8, "bold")


def do_calculate(mach_number_var, expansion_waves_count_var):
    try:
        mach_number = mach_number_var.get()
        expansion_waves_count = expansion_waves_count_var.get()
    except ValueError:
        pass  # Do nothing if one of the values isn't an integer.
    else:
        engine = matlab.engine.start_matlab()
        io.savemat("mach_number.mat", {"z1": mach_number})
        io.savemat("number_expansion_waves.mat", {"z": expansion_waves_count})
        engine.main(nargout=0)


def main():
    root = tk.Tk()
    tk.Label(
        root, text="Design of a 2D Minimum Length Nozzle ", font=HEADLINE_FONT
    ).pack()

    frame = tk.Frame(root)

    input_parameter_frame = tk.Frame(frame)

    tk.Label(
        input_parameter_frame, text="Input parameters", font=HEADLINE_FONT
    ).grid(row=0, column=0, columnspan=2, sticky=tk.W)

    mach_number_var = tk.IntVar()
    tk.Label(input_parameter_frame, text="Mach number").grid(
        row=1, column=0, sticky=tk.E
    )
    tk.Entry(
        input_parameter_frame, textvariable=mach_number_var, width=10
    ).grid(row=1, column=1, sticky=tk.W)

    expansion_waves_count_var = tk.IntVar()
    tk.Label(
        input_parameter_frame,
        text="Number exp. waves",
        textvariable=expansion_waves_count_var,
    ).grid(row=2, column=0, sticky=tk.E)
    tk.Entry(input_parameter_frame, width=10).grid(
        row=2, column=1, sticky=tk.W
    )

    input_parameter_frame.pack(side=tk.LEFT)
    
    tk.Button(
        frame,
        text="Calculate",
        command=partial(
            do_calculate, mach_number_var, expansion_waves_count_var
        ),
    ).pack(side=tk.LEFT, anchor=tk.S)

    frame.pack()
    
    root.mainloop()


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
panasonic18
User
Beiträge: 4
Registriert: Sonntag 5. April 2020, 13:12

Ich danke dir! Das hat mich auf jede Fall schon mal einen guten Schritt weiter gebracht. Wie du wahrscheinlich schon gemerkt hast, arbeite ich das erste mal mit Python..
Das Programm läuft, einziges Problem ist nur, dass die Plot fenster direkt wieder geschlossen werden, ich aber nicht weiß, wie ich das beheben sollte..

Ich versuche als nächstes, die matlab scripte komplett in Python zu schreiben, sodass ich quasi unabhängig von Matlab das Programm laufen lassen kann. Ich habe schon von Matlab to python übersetzern gelesen, kennst du dich damit aus und könntest welche empfehlen?

Oder sollte ich lieber versuchen, den code neu in Python aus zu formulieren?

Beste Grüße und danke dir
Antworten