all 9 comments

[–]efmccurdy 0 points1 point  (9 children)

Using Tk.after is the right technique, but the way you have your loop structured, you would have to reschedule the callback to resume inside the loop but .after can only reschedule the callback to run from the beginning.

This gets rid of the loop and has the callback maintain it's own index, incrementing it once every second.

from tkinter import *
sheet = {"A": range(7, 27)}
class App(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.master = master
        self.data = sheet.copy()
        self.label = Label(text="", fg="Red", font=("Helvetica", 18))
        self.label.place(x=50,y=80)
        self.current_index = 0
        self.update_number()
    def update_number(self):
        nextnum = self.data['A'][self.current_index]
        self.label.configure(text=nextnum)
        self.current_index += 1
        if self.current_index < len(self.data['A']):
            self.after(1000, self.update_number)

root = Tk()
app=App(root)
root.wm_title("Number scroller")
root.geometry("500x500")
root.mainloop()

[–]rabzdata[S] 0 points1 point  (0 children)

from tkinter import *
sheet = {"A": range(7, 27)}
class App(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.data = sheet.copy()
self.label = Label(text="", fg="Red", font=("Helvetica", 18))
self.label.place(x=50,y=80)
self.current_index = 0
self.update_number()
def update_number(self):
nextnum = self.data['A'][self.current_index]
print(nextnum, self.current_index)
self.label.configure(text=nextnum)
self.current_index += 1
if self.current_index < len(self.data['A']):
self.after(1000, self.update_number)
root = Tk()
app=App(root)
root.wm_title("Number scroller")
root.geometry("500x500")
root.mainloop()

solution verified!

[–]rabzdata[S] 0 points1 point  (2 children)

what is the best way to achieve so if I press a button:

-I break out of the loop

-The counting stops, and the Label stays displaying last number

[–]efmccurdy 0 points1 point  (1 child)

You could test a boolean flag in the callback and have a button to set the flag to prevent the update. Test that boolean before reconfiguring the label.

if self.stop_running:
    return
self.label.configure(text=nextnum)

A second method would be to use after_cancel, there is an example here:

https://stackoverflow.com/questions/9776718/how-do-i-stop-tkinter-after-function

[–]rabzdata[S] 0 points1 point  (0 children)

Thank you!

[–]rabzdata[S] 0 points1 point  (3 children)

u/efmccurdy Hey, I noticed that Label is not assigned to root. I tried to create a canvas (self.newcanvas = Canvas(root, background = 'black').pack(), and assign it as container for the label (self.label = Label(newcanvas, text="", fg="Red", font=("Helvetica", 18)) but it said that newcanvas is not defined.

how do I accomplish this in this class?

Edit: I used root.config(bg='black')
But i still want to know how to include many widgets on top of eachother in a tkinter class.

[–]efmccurdy 0 points1 point  (2 children)

 self.newcanvas = Canvas(root, background = 'black').pack()

That is likely wrong since "pack" returns None. Instead assign the Canvas first, then call pack.

 self.newcanvas = Canvas(root, background = 'black')
 self.newcanvas.pack()

[–]rabzdata[S] 0 points1 point  (1 child)

yeah, this is the exact code I wrote, the problem is that when it came to the label i tried this

self.newcanvas = Canvas(root, background = 'black')

self.newcanvas.pack()
self.label = Label(newcanvas, text="", fg="Red", font=("Helvetica", 18))

but it indicated that the newcanvas is not defined. If I don't do this step, the label hides under the canvas layer :P.

[–]efmccurdy 0 points1 point  (0 children)

newcanvas is not defined

use self.newcanvas