Tkinter串口数据显示应用右键关闭异常问题咨询及可行实现代码
Hey there! Let's tackle those Tkinter closing issues you're facing with your serial monitor app. I've looked over your code and spotted a couple of key problems causing those errors, plus some tweaks to make the shutdown process clean and error-free.
Let's break down the root causes first:
- Error 1: "invalid command name GetCounter": When you call
self.frame.destroy()directly, theaftertask you scheduled is still queued to run. Once the widget (and Tkinter context) is destroyed, Tcl can't locate theGetCounterfunction anymore, triggering this error. - Error 2: "can't delete Tcl command": In your
BClickmethod, you're trying to cancel the sameafterIDon bothframe.Fieldandframe.Field2. Butself.afterIDis only linked to the after task created byframe.Field—canceling it onframe.Field2attempts to delete a Tcl command that never existed for that widget, which is why this error pops up.
Here's the fixed code with explanations:
import serial import tkinter as tk import tkinter.font as tkFont import time nr = 0 def incTimer(self): global nr nr += 1 class App: def __init__(self,frame): self.Running = True self.afterID = 0 frame.Field = tk.Label( foreground="black", background="green", font=("Arial",30,"bold"), width=4, height=2) frame.Field2 = tk.Label( foreground = "black", background = "white", width = 8, height = 1, font = ("Arial", 12, "bold") ) self.frame = frame frame.Field2.pack() frame.Field.pack() frame.Field.bind('<Button>', self.BClick) self.fr = frame self.Port = "COM3" # Removed trailing colon (serial.Serial doesn't need it) self.Position = "100x130+0+0" self.BaudRate = 115200 self.MaxSmiley = 11 self.Enter = 11 self.TimeOut = 15 self.HeartBeat = 99 self.Debug = True # Add error handling for serial port initialization try: self.ser = serial.Serial(self.Port, self.BaudRate, timeout=0) except serial.SerialException: print(f"Failed to open port {self.Port}—falling back to debug mode") self.Debug = True frame.geometry(self.Position) frame.overrideredirect(True) self.fr.Field2.config(text=" ") self.fr.Field.config(text=" ") def BClick(self,event): print('Button: {}'.format(event.num)) if event.num == 3: # Right-click detected self.Running = False # Only cancel the after task that's actually tracked if self.afterID != 0: self.fr.Field.after_cancel(self.afterID) # Clean up serial port to avoid resource leaks if hasattr(self, 'ser') and self.ser.is_open: self.ser.close() # Destroy the main window cleanly self.frame.destroy() def GetCounter(self): # Exit early if we're shutting down if not self.Running: return global nr if self.Debug: msg = str(nr) loopdelay = 1000 else: msg = self.ser.read(2) if len(msg) < 2: msg = '88' loopdelay = 100 f = int(msg) - 1 if f == self.Enter: self.fr.Field2.config(text="ENTER") elif f == self.TimeOut: self.fr.Field2.config(text="TIMEOUT") elif f == self.HeartBeat: self.fr.Field2.config(text=" ") elif f < self.MaxSmiley: self.fr.Field.config(text=str(f)) self.fr.Field2.config(text=" ") nr += 1 if nr > 32: nr = 1 # Only schedule the next task if we're still running if self.Running: self.afterID = self.fr.Field.after(loopdelay, self.GetCounter) if __name__ == "__main__": root = tk.Tk() app = App(root) app.GetCounter() root.mainloop()
Key fixes and improvements:
- Clean after cancellation: Only cancel the after task linked to
self.afterID(which belongs toframe.Field), removing the invalid attempt to cancel onframe.Field2. - Proper shutdown flag: Added a check at the start of
GetCounterto exit immediately ifself.Runningis False, so no new after tasks are scheduled once shutdown starts. - Serial port cleanup: Close the serial port before destroying the window to release system resources.
- Serial error handling: Added a try/except block to handle cases where the COM port isn't available, with a fallback to debug mode.
- Fixed port name: Removed the trailing colon from
COM3:sinceserial.Serialexpects the port name without it.
This should resolve both errors—your app will now shut down cleanly when you right-click the label, with no leftover running tasks or Tcl command errors.
内容的提问来源于stack exchange,提问作者Waldemar
相关产品推荐
相关产品推荐

