2

I have a problem where the tkinter Scale widget seems to get stuck whenever I run a seemingly big function.

This is the code:

from tkinter import Tk, Button, Frame, Scale

root = Tk()

slider = Scale(root, orient='horizontal')
slider.pack()

frame = Frame(root)
frame.pack()

num = 0


def buttons():
    for widget in frame.winfo_children():
        widget.destroy()

    for i in range(50):
        Button(frame, text='Button' + str(i)).pack()


def basic():
    global num
    slider.set(num)
    num += 1
    print(num)
    if num <= 100:
        slider.after(100, basic)


if __name__ == '__main__':
    buttons()
    basic()

root.bind('<space>', lambda x: buttons())
root.mainloop()

What I want my program to do is update the slider normally even when I press 'Space' (meaning calling the buttons() function)
If you watch closely each time you press Space the slider will get stuck a little.
Since I'm using the slider for an Mp3 player in order to show time elapsed, this loss of time is extremely important for example for audio files of 10 or so seconds since the slider falls behind a lot making it seem as if it's working wrong \

I'd also like to point out that destroying the buttons and then repacking them is necessary for me.
I suspect that this happens because the program has to go over the buttons() function something that takes time since it's creating 50 buttons. Or am I mistaken?

Can I avoid that lag?

PS: As I mentioned in my comment:

I normally have a button that renames a (button) which is a song and in order for them to alphabetically ordered after renaming i need to recall the function that draws them. If I only configure tha name of the button (and not redraw them), it will stay in place and not move down or up depending on its name, while on the actual directory the order will change leading to inappropriate behavior such as playing the same song

Here are some images for better understanding: Before renamingAfter renaming

Thanks in advance!

Thalis
  • 188
  • 2
  • 12
  • `buttons()` is creating `50` buttons. That is why it takes a long time. The only solution is to add a button every like 10ms until you reach the number of buttons you need. Do you really need that many buttons? – TheLizzard May 04 '21 at 22:03
  • I actually need to replace these buttons which represent songs in my app so as them to be alphabetically ordered. The number could even be more than 100. – Thalis May 04 '21 at 22:10
  • Why not only load the ones that need to be displayed. My guess is that the user wouldn't be able to see all 100 of them. Also redrawing that many buttons takes a lot of time. Why are you redrawing them anyways? If you change their attributes, use `.config(...)`. – TheLizzard May 04 '21 at 22:12
  • 2
    Yes as @TheLizzard said can you tell us why exactly do you need to redraw them? Since as he mentioned there perhaps are ways to configure the same buttons again and again. – typedecker May 05 '21 at 07:57
  • I normally have a button that renames a (button) which is a song and in order for them to alphabetically ordered after renaming i need to recall the function that draws them. If I only configure tha name of the button (and not redraw them), it will stay in place and not move down or up depending on its name, while on the actual directory the order will change leading to inappropriate behavior such as playing th same song – Thalis May 05 '21 at 10:09
  • I added some pictures to my question to make the problem of not redrawing the buttons visible – Thalis May 05 '21 at 10:18
  • @Thalis You know that you can also change the button's `command` using the same `.config(command=, text=)` method. – TheLizzard May 10 '21 at 16:47
  • @TheLizzard ok but how would that be useful for me? – Thalis May 11 '21 at 09:49
  • 1
    @Thalis Put all of the buttons in a list then each time you need to redraw them just change their `text` and `command` attributes. It will take less time and might solve your problem. – TheLizzard May 11 '21 at 10:24

1 Answers1

3

Look at this code:

import tkinter as tk

def config_buttons():
    # Get the `text` of the first button
    starting_value = int(buttons[0].cget("text")) + 1
    # Iterate over all of the buttons
    for i, button in enumerate(buttons, start=starting_value):
        # Change the button's `text` and `command` atributes
        button.config(text=i, command=lambda i=i:print("Clicked %i"%i))

root = tk.Tk()
buttons = []

add_button = tk.Button(root, text="+1 on all buttons", command=config_buttons)
add_button.pack()

for i in range(50):
    button = tk.Button(root, text=i, command=lambda i=i:print("Clicked %i"%i))
    button.pack()
    buttons.append(button)

root.mainloop()

When the add_button buttons is pressed, I iterate over all of the buttons and change their text and command attributes. As I am not creating new buttons, the function runs very fast.

You can implement something similar in your code. Basically, avoid creating new buttons and just update the ones you already have on the screen.

TheLizzard
  • 7,248
  • 2
  • 11
  • 31
  • I think I can't use the exact code you provided but I'm going with this idea in general, not create - update. Thanks! – Thalis May 11 '21 at 19:01
  • I'm working on it. I was able to change their place by griding them in another row. I'm fixing the commands now! – Thalis May 14 '21 at 11:44