I'm very new to Python and this is my first ever Python GUI app. I am writing a little app to interact with my STM32 Black Pill board. This is very minimal as I intend to use this as the basis for future project with specific intentions. How did I do? What can I do better?
import tkinter as tk import serial.tools.list_ports from threading import * class Main(tk.Tk): def __init__(self, *args, **kwargs): tk.Tk.__init__(self, *args, **kwargs) self.title("Breadboard MCU Interface") self.resizable(False, False) ### Menu Configuration ############################################################################### self.menubar = tk.Menu(self) self.configmenu = tk.Menu(self.menubar, tearoff=0) self.configmenu.add_command(label="Communications Port", command=lambda: PortConfig()) self.menubar.add_cascade(label="Configure", menu=self.configmenu) self.menubar.add_command(label="Connect", command=connect) self.config(menu=self.menubar) ### End Menu Configuration ########################################################################### ### GPIO Canvas ###################################################################################### self.gpio_canvas = tk.Canvas(self, width=325, height=100) self.gpio_canvas.create_text(170, 30, text="GPIO", font=('Helvetica 15 bold')) self.gpio_canvas.create_text(25, 55, text="Port A") self.gpio_canvas.create_text(25, 70, text="Port B") self.ports = { "A": [], "B": [] } for pin in range(16, 0, -1): self.ports['A'].append(self.gpio_canvas.create_oval(60 + (pin * 15), 50, 70 + (pin * 15), 60, fill = "green")) self.ports['B'].append(self.gpio_canvas.create_oval(60 + (pin * 15), 65, 70 + (pin * 15), 75, fill = "green")) self.gpio_canvas.pack(fill="both") ### End GPIO Canvas ################################################################################### def updatePinDisplay(self, portid, pinvalues): for i in range(0,16): pinvalue = ((pinvalues >> i) & 1) if pinvalue: self.gpio_canvas.itemconfig(self.ports[portid][i], fill="green2") else: self.gpio_canvas.itemconfig(self.ports[portid][i], fill="green") #self.update() class PortConfig(tk.Toplevel): def __init__(self, *args, **kwargs): def getSelection(choice): self.selected = str(choice).split(' ')[0] def setComPort(): global comport comport = self.selected connect() self.destroy() tk.Toplevel.__init__(self, *args, **kwargs) self.title("Connection Configuration") self.resizable(False, False) self.config(padx=5, pady=5) ports = serial.tools.list_ports.comports() default = tk.StringVar(self, "Please select a communications port") self.selected = None self.portslist = tk.OptionMenu(self, default, *ports, command=getSelection).pack(side="left") self.okbutton = tk.Button(self, text="OK", command=setComPort).pack(side="left", padx=10) self.focus() self.grab_set() class WorkThread(Thread): global connection def run(self): global porta_pins print("Worker thread running...") try: while connection.is_open: while connection.in_waiting: indata = connection.readline().decode('Ascii') portid, pinvalues = indata.split('#') app.updatePinDisplay(portid, int(pinvalues)) except Exception as e: print(str(e)) pass print("Worker thread closing down.") def connect(): global connection, connected, workthread try: connection = serial.Serial(comport, baudrate=1152000, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=2) except: pass if connection is not None: connected = True connection.write("Connection established.\r\n".encode('Ascii')) app.menubar.entryconfigure(2, label="Disconnect", command=disconnect) workthread = WorkThread() workthread.start() else: connected = False print("Connection failed.") def disconnect(): global connection, connected, workthread connection.close() connected = False workthread.join() workthread = None app.menubar.entryconfigure(2, label="Connect", command=connect) if __name__ == '__main__': comport = None connection = None connected = False workthread = None app = Main() app.mainloop()