0

I am trying to color the canvas oval item, indicating when the program is busy (status indicator). The expected behavior is to turn the canvas oval red when clicking the check button, and turn it back off (to blue ) when the function is complete.

Here is the code I have so far

class App(tk.Tk):
    def __init__(self):  
        tk.Tk.__init__(self)
        self.entryframe = Frame(self, width=800, height=500)
        self.entryframe.pack(fill=X, padx=8, pady=8)
        self.canvas = Canvas(self.entryframe, width=30, height=30)
        # change fill color of the status oval
        self.status = self.canvas.create_oval(10, 10, 30, 30, fill="blue", tags="state")
        self.canvas.grid(row=0, column=1)
        self.label = Label(self.entryframe, text="Enter your sentence:").grid(row=3, column=0, sticky=W)
        self.text = Text(self.entryframe, wrap=WORD, width=70, height=10)
        self.text.grid(row=4, column=0, sticky=W)
        self.btn_h = Button(self.entryframe, text="Check", width="15", command=self.check_input).grid(row=5, column=0, padx=8, pady=8)

    def check_input(self):
        #change status oval color to red
        self.canvas.itemconfig(status, fill='red')

        # after the function is complete turn it back off
        canvas.itemconfig(light_1, fill='blue')

root = App()
root.mainloop()

The current behavior is the item stays blue color, and does not change at all.

stooicrealism
  • 548
  • 2
  • 9
  • 29

1 Answers1

1

You saved the reference to the oval as a class attribute. So you will need to access it the same way by passing self:

import tkinter as tk
from threading import Thread
import time

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.entryframe = tk.Frame(self, width=800, height=500)
        self.entryframe.pack(fill=tk.X, padx=8, pady=8)
        self.canvas = tk.Canvas(self.entryframe, width=30, height=30)
        # change fill color of the status oval
        self.status = self.canvas.create_oval(10, 10, 30, 30, fill="blue", tags="state")
        self.canvas.grid(row=0, column=1)
        self.label = tk.Label(self.entryframe, text="Enter your sentence:").grid(row=3, column=0, sticky=tk.W)
        self.text = tk.Text(self.entryframe, wrap=tk.WORD, width=70, height=10)
        self.text.grid(row=4, column=0, sticky=tk.W)
        self.btn_h = tk.Button(self.entryframe, text="Check", width="15", command=self.check_input).grid(row=5, column=0, padx=8, pady=8)

    def check_input(self):
        #change status oval color to red
        self.canvas.itemconfig(self.status, fill='red') #use self.status instead
        t = Thread(target=self.lengthy_process,args=("Arg1","Arg2"))
        t.start()

    def lengthy_process(self,param1,param2):
        print (param1, param2)
        time.sleep(10) #simulate the time taken for processing
        print ("Finished!")
        self.canvas.itemconfig(self.status, fill='blue')

root = App()
root.mainloop()

Also, judging from how you inherit the instance of tk and create the rest of the widgets, it looks like you have a mix of both import tkinter as tk and from tkinter import *. This is generally considered bad practice - it is more reasonable to simply use import tkinter as tk so you know which widgets belong to tk, and which belongs to ttk if required. Also read Why is “import *” bad?

Henry Yik
  • 22,275
  • 4
  • 18
  • 40
  • thanks for the answer. it still does not work if I try to change the color after the function is complete. the root.after works though. self.canvas.itemconfig(self.status, fill='blue') if i put this line just after the steps in the function, then it won't work – stooicrealism Jul 18 '19 at 04:09
  • I think its not the color change doesn't work. Rather, your color got changed to red and then back to blue immediately since your function took maybe just a couple milliseconds to finish. – Henry Yik Jul 18 '19 at 04:10
  • it takes roughly a minute or more to execute. and it doesn't change to red at all – stooicrealism Jul 18 '19 at 04:16
  • Did you simply execute the function? It should freeze your GUI if so. – Henry Yik Jul 18 '19 at 04:17
  • If your function takes a minute to finish - you will need to `thread` that function else it will block the main thread of tkinter and render your GUI non-responsive. And when your GUI is not responsive, you won't see any color change at all. – Henry Yik Jul 18 '19 at 04:22
  • can u edit your answer to show this step please? just as simply as u can? – stooicrealism Jul 18 '19 at 04:36