Hi. I've just registered, but I'm not exactly new to here (i've been lurking as a guest). I'm trying to make a countdown timer based on a class that I created, which accepts hours, minutes, and seconds as parameters and counts them down to zero, will displaying them in a Tkinter window.

Now, I did start on it using Tkinter, but the Tkinter window just never appears (for some reason, I suspect this has something to do with the time.sleep() i use in my aggregate function, because everything else seems fine and when I the aggregate() function call, the window runs normally.

I managed to create a temporary fix using livewires, that instead of using time.sleep(), uses the mainloop() cycles to decide when to decrement a second (mainloop in livewires do a certain amount of cycles per second). The problem with this is that it isn't always accurate. That is, sometimes it goes too fast, and sometimes it goes too slow with the exact same FPS settings (I suspect this has to do with my CPU load or something...i'm not very skilled and I don't know a lot about these things).
Another problem with the livewires method is that while in Tkinter, I could just destroy() the timer window when the timer is through and call back the main window(I want the timer to quit, and open back the start screen when it is through), with this livewires version it just locks up when i tell it screen.quit() (The destroy() function only wipes all the objects off. Heres the code (so sorry for lack of commenting...i was supposed to comment it last night, but got sidetracked and now im at work and dont have much time. I'll add comments if you cant understand the code):

#Te-je Rodgers
#Counter module

from livewires import games, color


class Counter(games.Sprite):
    """My counter is a sprite."""
    def __init__(self, screen, x, y,image, passer):
        self.screen = screen
        self.init_sprite(screen = screen, x = x, y = y, image=image)
        self.name=passer[0]
        timer=passer[1]
        self.hh=timer[0]
        self.mm=timer[1]
        self.ss=timer[2]
        self.count=0
        self.col=color.blue
        games.Text(screen=screen, x=200, y=20, text=self.name, color = color.white, size=50)
        games.Text(screen=screen, x=200, y=180, text="Press ENTER or F1 to stop",
                   color=color.white, size=20)

        
    self.display_message()


    def close_timer(self):
        
        if self.hh<0:
            import last
        else:
            self.screen.quit()
            
        
    def good(self):
        x=0



    def display_message(self):
        games.Message(screen = self.screen, x=200, y=100,
                      text=str(self.hh)+" : "+str(self.mm)+" : "+str(self.ss), size=100, after_death=self.good(),
                      color=self.col, lifetime=75)




    def decrease_seconds(self):
        self.ss-=1
        if self.hh>=0:
            if self.ss<0:
                self.ss=59
                self.mm-=1
                if self.mm<0:
                    self.mm=59
                    self.hh-=1
                    if self.hh<0:
                        self.close_timer()
                    else:
                        self.display_message()
                else:
                    self.display_message()
            else:
                self.display_message()





    def moved(self):
        self.count+=1
        if self.screen.is_pressed(games.K_RETURN) or self.screen.is_pressed(games.K_F1) or self.screen.is_pressed(games.K_KP_ENTER):
            self.close_timer()
        if self.hh==0 and self.mm==0 and self.ss==6:
            self.col=color.red
        if self.count==75:
            self.decrease_seconds()
            self.count=0
                


def start(passer):
    root32=games.Screen(400, 200)
    sprite_image=games.load_image("img.bmp")
    back=games.load_image("box2.jpg")
    root32.set_background(back)
    x=Counter(root32, 296, 139, sprite_image, passer)
    root32.mainloop(50)

the parameter "passer" in in this format:
("string",(int_hh, int_mm, int_ss))

Recommended Answers

All 12 Replies

Please use the [code=python] and [/code] tag pair to enclose your python code. Otherwise you lose all your indentations and you code becomes unusable!

With the housekeeping out of the way, "Welcome to the Python forum!"

humblest apologies.


Livewires based timer:

#Te-je Rodgers
#Counter module
from livewires import games, color

class Counter(games.Sprite):
    """My counter is a sprite."""
    def __init__(self, screen, x, y,image, passer):
        self.screen = screen
        self.init_sprite(screen = screen, x = x, y = y, image=image)
        self.name=passer[0]
        timer=passer[1]
        self.hh=timer[0]
        self.mm=timer[1]
        self.ss=timer[2]
        self.count=0
        self.col=color.blue
        games.Text(screen=screen, x=200, y=20, text=self.name, color = color.white, size=50)
        games.Text(screen=screen, x=200, y=180, text="Press ENTER or F1 to stop",
                   color=color.white, size=20)
        
 self.display_message()

    def close_timer(self):
        
        if self.hh<0:
            import last
        else:
            self.screen.quit()
            
        
    def good(self):
        x=0
    def display_message(self):
        games.Message(screen = self.screen, x=200, y=100,
                      text=str(self.hh)+" : "+str(self.mm)+" : "+str(self.ss), size=100, after_death=self.good(),
                      color=self.col, lifetime=75)

    def decrease_seconds(self):
        self.ss-=1
        if self.hh>=0:
            if self.ss<0:
                self.ss=59
                self.mm-=1
                if self.mm<0:
                    self.mm=59
                    self.hh-=1
                    if self.hh<0:
                        self.close_timer()
                    else:
                        self.display_message()
                else:
                    self.display_message()
            else:
                self.display_message()
    def moved(self):
        self.count+=1
        if self.screen.is_pressed(games.K_RETURN) or self.screen.is_pressed(games.K_F1) or self.screen.is_pressed(games.K_KP_ENTER):
            self.close_timer()
        if self.hh==0 and self.mm==0 and self.ss==6:
            self.col=color.red
        if self.count==75:
            self.decrease_seconds()
            self.count=0
                

def start(passer):
    root32=games.Screen(400, 200)
    sprite_image=games.load_image("img.bmp")
    back=games.load_image("box2.jpg")
    root32.set_background(back)
    x=Counter(root32, 296, 139, sprite_image, passer)
    root32.mainloop(50)

Tkinter timer(not working at all):

#Gamal Crichton
#Teje's Counter
#04/02/07
from Tkinter import *
import time
class Application(Frame):
    def __init__(self,master,act_name,time_):
        Frame.__init__(self,master)
        self.hh=time_[0]
        self.mm=time_[1]
        self.ss=time_[2]
        self.name=act_name
        self.grid()
        print time_
        self.disp_widgets()
        self.aggregate()
        
        
    def disp_widgets(self):
        #Uses labels to diaply time.
        Label(self,
              text=self.name, font=("Arial, 32")
              ).grid(row=0,column=0,columnspan=3,sticky=W)
        
        self.hourlbl=Label(self,
              text=self.hh, font=("Arial, 40")
              )
        self.hourlbl.grid(row=1,column=0,columnspan=1,sticky=W)
        self.minutelbl=Label(self,
              text=self.mm, font=("Arial, 40")
              )
        self.minutelbl.grid(row=1,column=1,columnspan=1,sticky=W)
                            
        
        self.secondlbl=Label(self,
              text=self.ss, font=("Arial, 40")
              )
        self.secondlbl.grid(row=1,column=2,columnspan=1,sticky=W)
        
        Button (self,
                text="Stop",
                command=self.show,
                ).grid(row=2,column=0,sticky=E, columnspan=3)
        
    def show(self):
            print "Booooooooo!"
    def aggregate(self): #This function is supposed to decrement the time
        for hours in range(self.hh, -1, -1):
            for minutes in range(self.mm, -1, -1):
                for seconds in range(self.ss, -1, -1):
                    time.sleep(1)
                    self.secondlbl["text"]=seconds
                    if self.ss==0:
                        self.ss=60
                self.minutelbl["text"]=minutes
                if self.mm==0:
                    self.mm=0
            self.hourlbl["text"]=hours
#Main
root=Tk()
root.title("Timer!")
root.geometry("250x75")
app= Application(root, "Timer", [2, 4, 5])
root.mainloop()

Hey ... I recognize that version of livewires from "Python Programming for the Absolute Beginner", yes?

I've successfully done a timer before and recall that there was a subtle trick to it. I'll try to look it up at school.

In the meantime, I want to register a major complaint with the new formatting for [ code = Python ] and [/ code] tags. The line numbers make it impossible to cut-and-paste code from the posting into IDLE. Unless I'm missing something?

Jeff

Hi!

Change your aggregate function to:

def aggregate(self): #This function is supposed to decrement the time
        for hours in range(self.hh, -1, -1):
            for minutes in range(self.mm, -1, -1):
                for seconds in range(self.ss, -1, -1):
                    time.sleep(1)
                    self.update()    # <== 
                    ...

@jrcagle: Do you see the Toggle Plain Text below the code? Click it and be happy :)

Regards, mawe

Hey mawe. I take it I need to just write an update method with all the stuff that was there in it?

And yeah Jeff, it was that book. It's the one we use in school....well it's the one the school told us to take and go learn python on our own. It's sitting open on my printer to the livewires reference page right now, incidentally.

Well thanks guys for all your help. I'll try it when I get to work, cause I'm late for school right now. Let you know how it goes.

Well that doesn't work either. The same thing happens: all i see is the console window.

A couple of things wrong with your countdown timer.
1 - don't limit the size of your root window, widgets won't fit
2 - labels take strings
3 - root.update() is needed
Look this over:

#Gamal Crichton
#Teje's Counter
#04/02/07

from Tkinter import *
import time

class Application(Frame):
    def __init__(self,master,act_name,time_):
        Frame.__init__(self,master)
        self.hh=time_[0]
        self.mm=time_[1]
        self.ss=time_[2]
        self.name=act_name
        self.grid()
        print time_
        self.disp_widgets()
        self.aggregate()
        
        
    def disp_widgets(self):
        #Uses labels to display time.
        Label(self,
              text=self.name, font=("Arial, 32")
              ).grid(row=0,column=0,columnspan=3,sticky=W)
        
        self.hourlbl=Label(self,
              text=str(self.hh), font=("Arial, 40")  # str()!!!!!!!!!!
              )
        self.hourlbl.grid(row=1,column=0,columnspan=1,sticky=W)

        self.minutelbl=Label(self,
              text=str(self.mm), font=("Arial, 40")  # str()!!!!!!!!!!
              )
        self.minutelbl.grid(row=1,column=1,columnspan=1,sticky=W)
        
        self.secondlbl=Label(self,
              text=str(self.ss), font=("Arial, 40")  # str()!!!!!!!!!!
              )
        self.secondlbl.grid(row=1,column=2,columnspan=1,sticky=W)
        
        Button (self,
                text="Stop",
                command=self.show,
                ).grid(row=2,column=0,columnspan=3,sticky=EW)
        
    def show(self):
        # needs more stuff
        print "Booooooooo!"

    def aggregate(self): #This function is supposed to decrement the time
        for hours in range(self.hh, -1, -1):
            for minutes in range(self.mm, -1, -1):
                for seconds in range(self.ss, -1, -1):
                    time.sleep(1)
                    root.update()  # needed!!!!!
                    self.secondlbl["text"]=str(seconds)  # str()!!!!!!!!!! 
                    if self.ss==0:
                        self.ss=60
                self.minutelbl["text"]=str(minutes)  # str()!!!!!!!!!!
                if self.mm==0:
                    self.mm=0
            self.hourlbl["text"]=str(hours)  # str()!!!!!!!!!!

#Main
root=Tk()

root.title("Timer!")

#root.geometry("250x75")  # do not use, too space restrictive!!!

app= Application(root, " Timer ", [2, 4, 5])

root.mainloop()

WOOHOO! THanks you guys. I now have a working timer. The problem was that I mis-interpreted mawe's post and wrote my own self.update()....that didn't work. But it was from the last post that I got egged on that Tk objects have update methods, and I used it after

self.hourlbl["text"]=self.hh
#etc....

and it works just fine now.

Thanks!

Sorry, I should have explained it a bit clearer. Next time I'll do better, I promise ;)

Good job figuring it out. I didn't find my timer program, so sorry to be unhelpful.

Jeff

Well in a couple weeks (after I finish my database project), Me and my friends are going to commence coding (or feeble attempts at) a private server and a client to go with it.

So...who wants to help? :P

and also, is python the best language for this? I am also open to learning other languages, but python and VB happen to be my languages of preference.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.