Brian Ton
Brian Ton

Reputation: 377

Label Is Not Shown When Called From Other Tkinter Program

I was writing a program with a start page, and two programs that are called from that start page. Both of the subprograms work by themselves. However, when I put them into my start page, the stopwatch timing label doesn't show up. If you are wondering, I put them into my program by doing:

import program
program.function()

Here is my start page program:

from Tkinter import *
class start_page:
    def __init__(self,master):
        self.master = master
        self.frame = Frame(self.master)
        self.countdown = Button(master, text = "Timer", command = self.c).pack()
        self.stopwatch_butt = Button(master,text="Stopwatch",command=self.g).pack()
    def g(self):
        import stopwatch
        stopwatch.f()
    def c(self):
        import timer_prog
        timer_prog.timer()
        self.master.after_cancel(timer_prog)
def main():
    root = Tk()
    s = start_page(root)
    root.title("Timer Suite: Brian Ton")
    root.mainloop()
main()

If I run this program, the timer program works fine, but the stopwatch doesn't show its label, only its buttons. I tried to clear all Tk after functions, and that didn't work, and I also tried to run the stopwatch program first, to no avail.

Here is my stopwatch program:

from Tkinter import *
import datetime

def s():
    start.config(state='disabled')
    stop.config(state="normal")
    reset.config(state='disabled')
    Start()
def Start():
    if reset['state'] == 'disabled' and stop['state'] == 'normal':
        hidden.set(str(int(hidden.get())+1))
        root.update()
        root.after(1000,Start)
        curr = hidden.get()
        g.set(str(datetime.timedelta(seconds=int(curr))))
        print g.get()
    else:
        return None
def Stop():
    start.config(state='disabled')
    stop.config(state='disabled')
    reset.config(state="normal")
def Reset():
    start.config(state="normal")
    stop.config(state="disabled")
    reset.config(state='disabled')
    hidden.set('0')
    g.set(str(datetime.timedelta(seconds=0)))
def f():
    global root,frame,master,hidden,g,timelabel,start,stop,reset
    root = Tk()
    frame = Frame(root)
    master = root
    hidden = StringVar()
    g = StringVar()
    hidden.set('0')
    timelabel = Label(master,textvariable=g)
    g.set(str(datetime.timedelta(seconds=int(0))))
    timelabel.grid(row=1,column=2)
    start = Button(master,text="Start",command = s,state="normal")
    stop = Button(master,text="Stop",command = Stop,state = "disabled")
    reset = Button(master,text="Reset",command = Reset,state = "disabled")
    start.grid(row=2,column=1)
    stop.grid(row=2,column=2)
    reset.grid(row=2,column=3)
    root.update()
    root.mainloop()


And here is my timer program:

from Tkinter import *
import datetime

def get_seconds(h,m,s):
    hr_sec = h * 3600
    m_sec = m * 60
    return hr_sec+m_sec+s
def timerstartstop():
    hours = hour_entry.get()
    minutes = minute_entry.get()
    sec = second_entry.get()
    if hours == "":
        hours = 0
        hour_entry.insert(0,"0")
    if minutes == "":
        minutes = 0
        minute_entry.insert(0,"0")
    if sec == "":
        sec = 0
        second_entry.insert(0,"0")
    c = get_seconds(int(hours), int(minutes), int(sec))
    global s
    s = StringVar(master)
    s.set(c)
    if startstop['text'] == 'Stop':
        global curr
        curr = shown
        s.set(-1)
    if startstop['text'] == 'Reset':
        startstop.config(text="Start")
        s.set(c)
        root.update()
        shown.set(str(datetime.timedelta(seconds=int(s.get()))))
        return None
    countdown()
import winsound
def countdown():
    startstop.config(text="Stop")
    global shown
    good = True
    shown = StringVar(master)
    shown.set(str(datetime.timedelta(seconds=int(s.get()))))
    L = Label(master,textvariable=shown).grid(row=1,column=2)
    if int(s.get()) == 0:
        startstop.config(text="Reset")
        while startstop['text'] != "Start":
            root.update()
            winsound.Beep(500,500)
    elif int(s.get()) < 0:
        good = False
        shown.set(curr.get())
        startstop.config(text="Reset")
    else:
        if good:
            s.set(str(int(s.get())-1))
            root.after(1000,countdown)
def ex():
    root.after_cancel(countdown)
    root.destroy()
def timer():
    global root
    global master
    global frame
    root = Tk()
    master = root
    frame = Frame(master)
    global hour_entry
    hour_entry = Entry(master,width=3)
    hour_entry.grid(row=0,column=0)
    colon_l = Label(master,text=':').grid(row=0,column=1)
    global minute_entry
    minute_entry = Entry(master,width=2)
    minute_entry.grid(row=0,column=2)
    colon_l2 = Label(master,text=':').grid(row=0,column=3)
    global second_entry
    second_entry = Entry(master,width=2)
    second_entry.grid(row=0,column=4)
    global startstop
    startstop = Button(master,text="Start",command=timerstartstop)
    e = Button(master,text="Exit",command=ex).grid(row=1,column=3)
    startstop.grid(row=0,column=5)
    root.mainloop()

In addition, I tried to run these two programs from a different starting menu that used the console, which worked.
The console program is:

import timer_prog
timer_prog.timer()
raw_input('next')
import stopwatch
stopwatch.f()

Attached are some screenshots of what the stopwatch program should look like vs what it does look like when called from the starting program.


Note: I can tell the program is running from the starting page, as it prints the current time each second. Also, I attached some screenshots

Stopwatch Program Run Directly
Stopwatch Program Run From The Start Page

Upvotes: 1

Views: 58

Answers (1)

furas
furas

Reputation: 143097

Tkinter program should use only one Tk() - to create main window - and one mainloop() - to control all windows and widgets. If you use two Tk() and two mainloop() then it has problem - for example get()/set() may not work.

Subwindows should use Toplevel() instead of Tk().

Function which starts program (ie. run()) could run with parameter window (def run(window)) and then you can execute it as standalone program with

root = Tk()
run(root)
root.mainloop()

or after importing

run(Toplevel())

(without maniloop())

You can use if __name__ == "__main__" to recognize if program starts as standalone.

Example

main.py

from Tkinter import *

class StartPage:

    def __init__(self, master):
        self.master = master
        master.title("Timer Suite: Brian Ton")
        Button(master, text="Timer", command=self.run_timer).pack()
        Button(master, text="Stopwatch", command=self.run_stopwatch).pack()

    def run_stopwatch(self):
        import stopwatch
        window = Toplevel()
        stopwatch.run(window)

    def run_timer(self):
        import timer_prog
        window = Toplevel()
        timer_prog.timer(window)
        self.master.after_cancel(timer_prog)

def main():
    root = Tk()
    StartPage(root)
    root.mainloop()

main()

stopwatch.py

from Tkinter import *
import datetime

def pre_start():
    start_button.config(state='disabled')
    stop_button.config(state='normal')
    reset_button.config(state='disabled')
    start()

def start():
    global current_time

    # stop_button['state'] can be 'normal' or 'active' so better use ` != 'disabled'`
    if reset_button['state'] == 'disabled' and stop_button['state'] != 'disabled':
        current_time += 1
        time_var.set(str(datetime.timedelta(seconds=current_time)))
        print(time_var.get())
        master.after(1000, start)

def stop():
    start_button.config(state='disabled')
    stop_button.config(state='disabled')
    reset_button.config(state='normal')

def reset():
    global current_time

    start_button.config(state='normal')
    stop_button.config(state='disabled')
    reset_button.config(state='disabled')
    current_time = 0
    time_var.set(str(datetime.timedelta(seconds=0)))

def run(window):
    global master
    global current_time, time_var
    global start_button, stop_button, reset_button

    master = window
    current_time = 0

    time_var = StringVar()
    time_var.set(str(datetime.timedelta(seconds=0)))

    time_label = Label(window, textvariable=time_var)
    time_label.grid(row=1, column=2)

    start_button = Button(master, text='Start', command=pre_start, state='normal')
    stop_button  = Button(master, text='Stop',  command=stop,      state='disabled')
    reset_button = Button(master, text='Reset', command=reset,     state='disabled')
    start_button.grid(row=2, column=1)
    stop_button.grid(row=2, column=2)
    reset_button.grid(row=2, column=3)

if __name__ == '__main__':
    # it runs only in standalone program
    root = Tk()    
    run(root)
    root.mainloop()

Upvotes: 1

Related Questions