Hi, I'm starting my studies in Python, using Tkinter. Take it easy on answers/criticisms (lol!).
I need to "blink" a text (blink), with a value, when this is the fastest (record of the return).
I looked for information in several places on how to do this simply, but I only found results using the ".after" method.
However, a side effect arose in doing so. After a few "blinks", it slows down.
My questions are:
1) Is something wrong the way I did it?
2) Is there another way to make a text blink?
Below is a summary of what I did, showing the problem ("blink" getting slow).
from tkinter import * # Python 3 Piscando=0 class Janela_Treino: def __init__ (self,janela): janela_treino = Canvas(0, width=800, height=600, bg="black") def Placar(): global Piscando x = 0 while x < 4: if (x == 2): # Teste para piscar a posição 3 if Piscando == 0: janela_treino.create_text(400, 75+(150*x),text="00:000", font=('Arial', 120, 'bold'), fill="black") # Esconde Piscando = 1 else: janela_treino.create_text(400, 75+(150*x),text="00:000", font=('Arial', 120, 'bold'), fill="white") # Mostra Piscando = 0 else: janela_treino.create_text(400, 75+(150*x), text="00:000", font=('Arial', 120, 'bold'), fill="white") # Mostra normal x=x+1 janela.after(100,Placar) # Atualiza a tela a cada 0.1 segundo Placar() janela_treino.pack() root = Tk() Janela_Treino(root) root.mainloop()
The basic idea is correct – the way to keep something animated in tkinter, even text blinking, is to have a function or method that is called by a timer like what you do in
The fundamental problem there is that you didn't take into account how tkinter's Canvas works: it doesn't just draw text on the screen, as pixels, and forget about that text. If he did just that, in the next execution of his
Placar function, he would create another text, with another color, on top, and that's fine.
But when you draw an object on Tkinter's Canvas, this object is "live": it has attributes and colors, and can be moved – Tkinter's Canvas is a "vector" canvas: it redraws all the objects that were created on it a each time it is updated.
That's when your code, with each blink, creates a new text object, and inserts it into the Canvas – what happens is Canvas draws ALL the texts you created, from when it was created to the last one, one by on top of the other – and it only really updates what's on the screen when you're done drawing in the background.
It seems to be clear why after about 20 or 30 cycles it will start to slow down – he has to draw the text one over the other 20 or 30 times – with more time – in just one minute, it would be 600 objects of text, there's no CPU that can handle it!
So – the fix is simple: if you really needed to create a new text object in each frame, it would just be a matter of erasing the old text – the
create_text method returns an integer (which you don't keep anywhere in your code – it is thrown away) – this number is the identifier (handler) of that object inside the Canvas, and it is needed to erase an object, or change one of its parameters.
So, keeping that number, it would be a matter of calling the
janela_treino.delete(...) method with it to delete the previous text, before creating new text.
But – the thing is even simpler – since you want to keep the text, the font, the position, etc – – and you just want to change the color, just reset the text object to the desired color. The same identifier number as the text is used, but with the
itemconfig method. The code might look like this:
from tkinter import * # Python 3 class Janela_Treino: def __init__ (self,janela): piscando = False janela_treino = Canvas(0, width=800, height=600, bg="black") identificador_texto = janela_treino.create_text(400, 75+(150),text="00:000", font=('Arial', 120, 'bold'), fill="black") def placar(): nonlocal piscando if piscando: color = "black" else: color = "white" janela_treino.itemconfig(identificador_texto, fill=color) piscando = not piscando janela.after(100, placar) # Atualiza a tela a cada 0.1 segundo placar() janela_treino.pack() root = Tk() Janela_Treino(root) root.mainloop()
(This code just flashes the text – set the counters and "if" to flash at specific frames – and use the canvas's
.move method to change the position of the text, like your original code did, if you wish)