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()