Update Tkinter canvas in mainloop()
You are going to want to use after()
to manager an updating loop that wont affect the mainloop. By using after()
we can create a visual update over time. We will need a tracking variable to manage the index on the loop and a global statement for the tracker.
Example:
from tkinter import *
import random
height, width = 350, 600
randomLines = []
master = Tk()
tracker = 0
w = Canvas(master, width=width, height=height)
w.pack()
def drawRandomLines():
global tracker
if tracker <= width:
w.create_line(tracker, 0, tracker, randomLines[tracker])
tracker += 1
master.after(10, drawRandomLines)
def bubbleSort():
for passnum in range(len(randomLines)-1, 0, -1):
for i in range(passnum):
if randomLines[i] > randomLines[i+1]:
temp = randomLines[i]
randomLines[i] = randomLines[i+1]
randomLines[i+1] = temp
for i in range(width):
rnd = random.randint(0, width)
randomLines.append(rnd)
drawRandomLines()
bubbleSort()
mainloop()
Update an element of a canvas interrupting the main loop of Tkinter
widget.after(ms, callback, *args)
calls the callback(*args)
ms
milliseconds after the first time it's been read by the program. So you can define a callback method, self.flashRow
for example, and just call it with your time frame in __init__
like:
self.canvasRoot.after(250, self.flashRow)
or:
self.flashRow
both should be fine as long as they're before the mainloop
call. Then in your callback, self.flashRow
, you need to make sure it recursively calls itself in a time frame such as 250 ms:
self.canvasRoot.after(250, self.flashRow)
I configured self.flashRow
a bit to have some random flashing:
def flashRow(self):
'''Flashes the row specified as attribute'''
import random
global spellerFrame
_row = random.randint(0, 2)
_color = random.choice((color_text_hl, 'grey'))
print(_color)
for col_index in range(self.n_col):
spellerFrame.itemconfig(handle_comm[_row][col_index], fill=_color)
self.canvasRoot.after(250, self.flashRow)
Also see, the entire configuration of the non-mcve code you've provided:
from tkinter import *
class RCP:
global handle_comm
global handle_rect
global handle_res
global spellerFrame
global color_rect_bg, color_rect_hl, color_text_bg, color_text_hl, color_text_wa
def __init__(self, targets, w_width, w_height):
self.n_row = len(targets)
self.n_col = len(targets[0])
self.w_width = w_width
self.w_height = w_height
self.targets = targets
self.canvasRoot = Tk()
self.canvasRoot.configure(background='grey')
self.setDefaults()
# Initializate the main loop
self.createGrid()
self.canvasRoot.after(250, self.flashRow)
self.canvasRoot.mainloop()
def setDefaults(self):
global color_rect_bg, color_rect_hl, color_text_bg
global color_text_hl, color_text_wa
color_rect_bg = '#000000'
color_rect_hl = '#ffffff'
color_text_bg = '#757575'
color_text_hl = '#ffffff'
color_text_wa = '#ffff00'
global font_ratio_bg, font_ratio_hl
font_ratio_bg = 0.5
font_ratio_hl = 0.7
def createGrid(self):
# Calculate the maximum cell and font size that do not
# deform the commands' display
cell_size = min(self.w_height / self.n_row, self.w_width / self.n_col)
font_size = int(round(font_ratio_bg * cell_size))
result_size = int(round(cell_size/5))
# Create the canvas for the result text
global handle_res
resultLabel = Canvas(self.canvasRoot, width=self.w_width,
height=result_size, bd=0,
highlightthickness=0, relief='ridge', background='grey')
resultLabel.grid(row=0, column=0, columnspan=self.n_col)
handle_res = resultLabel.create_text(2, round(result_size/2),
text=' PRUEBA', fill=color_text_wa, anchor='w',
font=("Purisa", round(result_size/2), "bold"))
# Create the frame for the speller
global spellerFrame
spellerFrame = Canvas(self.canvasRoot, width=self.w_width,
height=self.w_height, bd=0,
highlightthickness=0, relief='ridge')
spellerFrame.grid(row=1, column=0)
# Create the grid of commands
global handle_comm, handle_rect
handle_comm = [[None for i in range(self.n_col)] for j in range(self.n_row)]
handle_rect = handle_comm
for row_index in range(self.n_row):
for col_index in range(self.n_col):
x1 = col_index * cell_size
y1 = row_index * cell_size
x2 = (col_index + 1) * cell_size
y2 = (row_index + 1) * cell_size
handle_rect[row_index][col_index] = spellerFrame.create_rectangle(x1,
y1, x2, y2, fill=color_rect_bg)
handle_comm[row_index][col_index] = \
spellerFrame.create_text(((x1+x2)/2,(y1+y2)/2),
text=self.targets[row_index][col_index],
fill=color_text_bg,
font=("Purisa", font_size, "bold"))
def flashRow(self):
'''Flashes the row specified as attribute'''
import random
global spellerFrame
_row = random.randint(0, 2)
_color = random.choice((color_text_hl, 'grey'))
print(_color)
for col_index in range(self.n_col):
spellerFrame.itemconfig(handle_comm[_row][col_index], fill=_color)
self.canvasRoot.after(250, self.flashRow)
targets = [['A','B','C','D'],['E','F','G','H'],['I','J','K','L']]
myRCP = RCP(targets, 800, 600)
how to make tkinter canvas update?
You will need to delete the old graph and create a new graph whenever you change the numbers.
You should do that by moving the code to draw the bar chart into a function.
def draw_barchart(data):
c.delete("all")
for x, y in enumerate(data):
x0 = x * x_stretch + x * x_width + x_gap
y0 = c_height - (y * y_stretch + y_gap)
x1 = x * x_stretch + x * x_width + x_width + x_gap
y1 = c_height - y_gap
c.create_rectangle(x0, y0, x1, y1, fill="red")
c.create_text(x0 + 2, y0, anchor=tk.SW, text=str(y))
You can then call this whenever the data changes, passing in the new data.
There are other problems with your code, however. You need to call mainloop()
at the very end of your program since it won't return until the window is destroyed.
You also either need to use after
to periodically update the data, or call tkinter's update
function to allow the window to redraw itself.
Here's how to write the bottom part of the code to add data and redraw the graph every five seconds:
def update():
count = 0
for i in range(5):
data.append(random.randint(1, 11))
c.delete("all")
draw_barchart(data)
root.after(5000, update)
update()
root.mainloop()
Related Topics
How to Concatenate/Append Multiple Spark Dataframes Column Wise in Pyspark
Finding a Substring Within a String Without Using Any Built in Functions
Convert a Tensor to Numpy Array in Tensorflow
How to Install a Module for All Users With Pip on Linux
How to Convert Strings With Billion or Million Abbreviation into Integers in a List
How to Remove an Item from a List in Python If That Item Contains a Word
Get Value of Span Tag Using Beautifulsoup
How to Find Number of Ways That the Integers 1,2,3 Can Add Up to N
Find the Index of a Value in a 2D Array
How to Convert a 1 Channel Image into a 3 Channel With Opencv2
Possible to Loop Through Excel Files With Differently Named Sheets, and Import into a List
Sub Totals and Grand Totals in Python
How to Stop a Running Function Without Exiting the Tkinter Window Entirely
How to Compute the Gradients of Image Using Python
Check Json Data Is None in Python
How to Constantly Run Python Script in the Background on Windows