Flash text on Tkinter / Side effect

Asked

Viewed 581 times

3

Hello, I’m starting my studies in Python, with the use of Tkinter. Take it easy on the answers / critics (rs!).
I need to "blink" a text (Blink), with a value, when this is the fastest (lap record).
I searched for information in several places on how to do this in a simple way, but only found results using the method ". after".
However, there was a side effect, doing so. After a few "blinks", it slows down.
My doubts are:
1) There is something wrong the way I did?
2) Has another way to make a text blink?

Below is a summary of what I did, presenting the problem ("blinking" slowing down).

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()

1 answer

1

The basic idea is correct - the way to keep something lively on Tkinter, even blinking text, is to have a function or method that is called by a timer like the one you do on janela.after.

The fundamental problem here is that you didn’t take into account how Tkinter’s Canvas works: it doesn’t just draw text on the screen, like pixels, and forget about that text. If that’s all he’d do at the next performance of his duties, Placar, he would create another text, with another color, on top, and all right.

But when drawing an object in Tkinter’s Canvas this object is "alive": it has attributes and colors, and can be moved - Tkinter’s Canvas is a "vector" canvas: it redesigns all objects that were created in it each time it is updated.

And then your code, every blink, creates a new text object, and inserts it into Canvas - what happens is that Canvas draws ALL the texts that you created, from when it was created to the last, one on top of the other - and only really updates what’s on the screen when you’ve finished drawing in the background.

It seems that it is clear why after about 20 or 30 cycles this will start to get slow - he has to draw, one over the other the text 20 or 30 times -- with more time - in just one minute, would be 600 text objects, has no CPU that holds!

So - the fix is simple: if it was really necessary to create a new text object in each frame, it would just be a matter of deleting the old text - the method create_text returns an integer number (which you do not store anywhere in your code - it is thrown away) - that number is the identifier (Handler) of that object within Canvas, and it is necessary to delete an object, or change one of its parameters.

So, keeping this number, it would be a matter of calling the method janela_treino.delete(...) with it to delete the previous text, before creating a new text.

But - the thing is even simpler - given that you want to keep the text, the font, the position, etc - and you just want to change the color, just reconfigure the text object with the desired color. The same text identifier number is used, but with the method itemconfig. The code can go 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 only flashes text - adjust the counters and "if" to flash on specific frames - and use the method .move canvas to change the position of the text, as its original code did, if desired)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.