ich komme aus der "C"-Programmierung, HTML und PHP. Also alles ablaufgesteuert. Nun soll ich für eine Anwendung ein erstes, objektorientiertes Python-Programm schreiben. Diese soll auf einem Raspberry Pi mit Touchscreen laufen und grob gesagt Eingaben auf Sinnhaftigkeit überprüfen, die Eingaben über Netzwerk an einen PC schicken und von einem PC Befehle entgegennehmen und dementsprechend reagieren.
Auf dem Touchscreen befinden sich Buttons, die wiederum auch Aktionen wie z.B das Senden von Daten über Ethernet oder das Beenden des Programms auslösen.
Das klappt eigentlich ganz gut, allerdings ist es eher ablaufgesteuerter Code ohne Objektorientierung. Die Nutzung von globalen Variablen ist wohl ein weiteres Indiz dafür, dass es wesentlich schöner geht.
Das ich unterschiedliche Threads für die graphische Benutzeroberfläche von TKinter benötige und auch einen separaten Thread für die TCPIP-Kommunikation ist mir auch klar.
Bevor ich nun in die falsche Richtung laufe, benötige ich Tipps zur Optimierung und Strukturierung des Programms:
Welche Klassen würdet ihr anlegen? Getrennte Klassen für TKinter, Kommunikation und eigentlicher Anwendung? Geht diese Trennung? oder muss die Kommunikation in die GUI-Klasse integriert werden, dass sich das Programm nicht aufhängt? Wie kommunizieren die Klassen untereinander
Läuft die TKinter-GUI automatisch als Thread? Wie synchronisiere ich die GUI und den vorhandenen Kommunikations-Thread? Das läuft momentan eigentlich erstaunlich gut ohne Hänger, nur beim Abbruch des Programms mittels F12 oder QUT-Befehl bekomme ich den Fehler " threading.py ... in shutdown t.join" und _wait_for_tstate_lock(). Wie beende ich dieses Programm richtig?
Und sicher sind da noch ganz viele andere Dinge, die den erfahrenen Python-Programmierer die Haare zu Berge stehen lassen.
Schon mal danke für eure Hilfe und den Schubs in die richtige Richtung.
Hier der vermutlich stark verbesserungswürdige Code:
Code: Alles auswählen
import sys
import tkinter as tk
import threading
import time
import socket
HEIGHT = 480
WIDTH = 800
HOST = ''
#HOST = '192.168.xxx.xx'
PORT = 5555
#Globals
SerialValid = False
SerNumber = "0"
SerialLength = 10 # Standard value for serial lenth
#THREAD1
def thr_Communication():
global SerNumber #use these global variables
global SerialValid #use these global variables
global SerialLength #use these global variables
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind((HOST, PORT))
except socket.error:
label2.config(text="Connection failed", bg='white', fg='#00cc99')
time.sleep(5)
sys.exit(0)
s.listen(1) #1 connection allowed
clientsocket, address = s.accept()
clientsocket.send(bytes("Connected", "utf-8"))
label2.config(text="Connected", bg='white', fg='#00cc99')
label4.config(text="Waiting")
while True:
msg = clientsocket.recv(1024)
if msg.decode("utf-8") == 'QUT':
label2.config(text=msg.decode("utf-8"), bg='white', fg='#00cc99')
clientsocket.send(bytes('BYE', "utf-8"))
clientsocket.close()
ExitScreen()
break
elif msg.decode("utf-8") == 'GET':
#mach dies
clientsocket.send(bytes("GET_OK", "utf-8"))
label4.config(text="blabla")
elif msg.decode("utf-8") == 'GOT':
clientsocket.send(bytes("GOT_OK", "utf-8"))
label2.config(text=msg.decode("utf-8"), bg='white', fg='#00cc99')
else:
clientsocket.send(bytes("Unknown command", "utf-8"))
def Funktion_machwas():
global SerNumber
global SerialValid
global SerialLength
entryField.delete(0, 100)
if SerialLength == 10:
SerNumber = "1"
elif SerialLength == 11:
SerNumber = "2"
else:
SerNumber = "0"
SerialValid = True
label2.config(text="Test sample Mode", bg='white', fg='orange')
label4.config(text=SerNumber, bg='white', fg='#00cc99')
def Funktion_machwasanderes():
global SerNumber
global SerialValid
SerNumber = "0"
SerialValid = False
entryField.delete(0, 100)
label2.config(text="BlaBla", bg='white', fg='#00cc99')
label4.config(text="BlaBla2", bg='white', fg='#00cc99')
def ExitScreen(arg=None):
root.destroy()
sys.exit(0)
### GUI ###
root = tk.Tk()
root.config(cursor='none')
canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
canvas.pack()
root.attributes('-fullscreen', True)
frame = tk.Frame(root, bg='#00cc99')
frame.place(anchor='nw', height=HEIGHT, width=WIDTH)
label = tk.Label(frame, text="Title Window", bg='white', fg='#00cc99')
label.place(relx=0, rely=0, relwidth=1, relheight=0.10)
# Configure entry field
entryField = tk.Entry(frame, font=('Arial', 24), bg='white', fg='#00cc99', highlightbackground='black',
justify='center', borderwidth=1, relief='solid')
entryField.focus()
entryField.bind('<Return>', Funktion_machwasanderes)
entryField.bind('<F12>', ExitScreen)
entryField.place(relx=0.35, rely=0.35, relwidth=0.6, relheight=0.15)
# Configure buttons
button1 = tk.Button(frame, text="Repeat Scan", font=('Arial', 16), bg='#00cc99', fg='white', activebackground='#00cc99', activeforeground='white', command=Funktion_machwas)
button2 = tk.Button(frame, text="Sample", font=('Arial', 16), bg='#00cc99', fg='white', activebackground='#00cc99', activeforeground='white', command=Funktion_machwasanderes)
button1.place(relx=0.00, rely=0.10, relwidth=0.3, relheight=0.45)
button2.place(relx=0.00, rely=0.55, relwidth=0.3, relheight=0.45)
label2 = tk.Label(frame, text="Search connection...", font=('Arial', 24), bg='white', fg='#00cc99',
highlightbackground='black', borderwidth=1, relief='solid', wraplength=500)
label2.place(relx=0.3, rely=0.10, relwidth=0.7, relheight=0.45)
label4 = tk.Label(frame, text="Waiting", font=('Arial', 24), bg='white', fg='#00cc99', highlightbackground='black',
borderwidth=1, relief='solid', wraplength=500)
label4.place(relx=0.3, rely=0.55, relwidth=0.7, relheight=0.45)
x = threading.Thread(target=thr_Communication)
x.start()
root.mainloop()