-2

I have a tiny application receiving numbers via serial port and showin it on the screen. Just a single label. My problem is, how to close the application (there is no close button or top line in the window (overrideredirect is set) I'd like to terminate my program by right-clicking the mouse over the label. Everything is working fine but:

  1. if I use root.frame_destroy() the after loop is still running and I get an error "invalid command name GetCounter" (GetCounter is my after function name)
  2. if I use root.after_cancel(ID) prior to destroy() I get a Tcl error: can't delete Tcl command

the TKInter app is encapsulated as a class. I'm running it on different computer so I can't provide a code snippet now, but I hope my problem is clear anyway

How can I get this up-and-running? I'm pretty new to python

TIA

Waldemar

Here my minimal code, it works now!

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:"
        self.Position = "100x130+0+0"
        self.BaudRate  = 115200            
        self.MaxSmiley = 11
        self.Enter = 11
        self.TimeOut = 15
        self.HeartBeat = 99
        self.Debug =True
        
        self.ser = serial.Serial(self.Port,self.BaudRate, timeout = 0)
        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:
            self.Running = False
            self.frame.Field.after_cancel(self.afterID)
            self.frame.Field2.after_cancel(self.afterID)
            self.frame.destroy() 
        
    def GetCounter(self):
        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")
        if f == self.TimeOut:
                 self.fr.Field2.config(text="TIMEOUT")
        if f == self.HeartBeat:
                 self.fr.Field2.config(text=" ")
        if f < self.MaxSmiley:
             self.fr.Field.config(text=str(f))
             self.fr.Field2.config(text=" ")
             
        nr += 1
        if nr > 32: nr = 1
        self.afterID = self.fr.Field.after(loopdelay,self.GetCounter)

        
if __name__ == "__main__":
        root = tk.Tk()
        app = App(root)
        app.GetCounter()
        root.mainloop()
Waldemar
  • 1
  • 2

1 Answers1

0

If I understand what you meant you can simply just root.destroy()

Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46
Mitja
  • 1
  • 1
  • Yes. But if I do this, there is still root.after function running. After root.destroy() my after function GetCounter is "headless" and causes error. When I stop after function with root.after_cancel(ID) I get a Tcl error after calling root.destroy() – Waldemar Feb 19 '21 at 16:59