[Tutor] please help me with after method

Alan Gauld alan.gauld at yahoo.co.uk
Thu Nov 17 17:07:49 EST 2016


Always use REply-All or Reply-List to the tutor list.

On 17/11/16 18:34, Freedom Peacemaker wrote:
> Thank you Alan for answer but i still cant make it. I have improved my
> program but it still uses root.update() and now my app looks
> professional :) It is my first program. I am self learning Python
> since july this year but still i need a lot of knowledge. Could you
> help me improve my app with root.after?

OK, I'll try.

> And there is problem - when im closing app with X button after using
> app it shows two windows. One with messagebox i wrote, and second
> blank new tk window. I dont know where im doing mistake, or it is
> caused by root.update maybe? Maybe with using root.after problem will
> be no more.

Maybe, but I'll need to look at the code more closely.
There are a couple of things that could cause this....
Having looked, I think you need to bind the window
manager close button to root.quit Take a look at
the wm_xxxx methods in the Tkinter docs.


>
> def displayCountdown():
>     lcd = "{:02d}:{:02d}".format(*divmod(t, 60))
>     timeString.set(lcd)
>     setTime -= 1
>     if setTime > 0:
>         root.after(1000,displayCountdown)
>

Where is 't' (used in the divmod) defined? Looking below I think
it should use setTime?

Otherwise it looks like it should work. All you need to do is insert
a call to displayCountdown() in your START button event handler.


> There are problems with my app but im so proud that i wrote myself

Its rare that anything is ever perfect but the buzz of getting
something to work more or less as you want it to is always good. :-)

> import sys, time, os
> import tkinter as tk
> from tkinter import *
>

You should probably only ose one of the tkinter imports.
And the first is the preferred method for production code.

> def change_1():
>     B1['state'] = tk.DISABLED
>     B2['state'] = tk.NORMAL  
>
> def change_2():
>     B1['state'] = tk.NORMAL
>     B2['state'] = tk.DISABLED
>
> def change_3():
>     B1['state'] = tk.DISABLED
>     B2['state'] = tk.DISABLED


Add the displayCountdown() definition here

>
> def startCount():
>     setTime = setMinutes.get() * 60
>     strTime = str(setTime)
>     timeSet = ("\""+"shutdown /s /f /t " +strTime+"\"")
>     os.system(timeSet)
>     change_1()
        displayCountdown()     # uses the after() method.

This removes the need for all of the code below.

>     for t in range(setTime, -1, -1):
>         lcd = "{:02d}:{:02d}".format(*divmod(t, 60))
>         timeString.set(lcd)
>         try:
>             root.update()
>         except TclError:
>             messagebox.showinfo('Info', 'Closing app wont stop timer.')
>             return
>         time.sleep(1)
>     return
>

The rest of your code is unchanged.
But note I haven't tested this! :-)

> def stopCount():
>     passwd = "science"
>     passwdGet = getPass.get()
>     if passwd != passwdGet:

You could make this more secure.
You should probably do some reading about best [practice
for handling passwords. But for now it probably meets your needs.


>         messagebox.showinfo('Wrong', 'It wasnt correct password')
>         change_3()
>     else:
>         messagebox.showinfo('Good', 'Shutdown canceled')
>         os.system("shutdown /a")
>         change_2()
>     return
>
> root = tk.Tk()
> setMinutes = IntVar()
> getPass = StringVar()
> timeString = StringVar()
> label_font = ('Verdana', 30)
> root.geometry('260x150+200+200')
> root.title('Timer v1.4')
> root.resizable(0, 0)
>
> L1 = tk.Label(root, text='How much time you have?')
> L1.grid(row=0, columnspan=3, sticky='WE')
>
> L2 = tk.Label(root, textvariable=timeString, font=label_font, bg='white',
>          fg='orange', relief='raised', bd=3)
> L2.grid(row=1, columnspan=3, sticky='WE', padx=5, pady=5)
>
> E1 = tk.Entry(root, textvariable=setMinutes, bg='lightgreen')
> E1.grid(row=2, column=1, padx=5, pady=5)
>
> B1 = tk.Button(root, text='S T A R T', fg='green', bg='black',
> command=startCount)
> B1.grid(row=2, rowspan=2, sticky='NS', column=0, padx=5, pady=5)
>
> E2 = tk.Entry(root, textvariable=getPass, bg='red')
> E2.grid(row=3, column=1, padx=5, pady=5)
>
> B2 = tk.Button(root, text='S T O P', fg='red', bg='black',
> command=stopCount,
>             state=tk.DISABLED)
> B2.grid(row=2, rowspan=2, sticky='NS', column=2, padx=5, pady=5)
>
> root.mainloop()
>
>
>
> 2016-11-17 1:03 GMT+01:00 Alan Gauld via Tutor <tutor at python.org
> <mailto:tutor at python.org>>:
>
>     On 16/11/16 18:48, Freedom Peacemaker wrote:
>     > Hi, i need help. I am using Python 3.4 and I have wrote little
>     app for
>     > windows only ( windows 7 and higher). Its timer and my app
>     working but not
>     > good. Some people said that i should use after method instead of
>     update()
>
>     after() executes a function after a delay.
>     In your case you could use it to trigger an
>     immediate shutdown after the delay elapses.
>     But I'm not sure that would be much better
>     than doing what you are doing.
>
>     The other use of after is to avoid loops in
>     event handlers such as the one you have here.
>     This allows control to return to the GUI window.
>
>     See below...
>
>     > When you run app first enter minutes in entry then press start.
>     If you
>     > first press start your pc will shutdown with no time to stop it
>
>     You can fix that by setting a default value for the time.
>     But you still need to write some code to cancel the shutdown
>     (by killing the process perhaps?)
>
>     > def startCount():
>     >     setTime = setMinutes.get() * 60
>     >     strTime = str(setTime)
>     >     timeSet = ("\""+"shutdown /s /f /t " +strTime+"\"")
>     >     os.system(timeSet)
>
>     Up to here is fine but you don't want a long running loop
>     inside an event handler. Although, in this case, it probably
>     doesn't run for long, it just counts down very quickly.
>
>     Instead you want it to count down  every second or so.
>
>     So you want to call a function that displays the time
>     remaining then calls after() with a delay of 1 second.
>     The call to after should have the same function in it.
>     Like so:
>
>     def displayCountdown():
>         # display the time here
>         # decrement the time by 1 second
>         # if any time remains:
>         #    call after(1000,displayCountdown) # 1000ms = 1s
>
>     Note that after only needs the function name, don't
>     include any parentheses.
>
>     >     for t in range(setTime, -1, -1):
>     >         lcd = "{:02d}:{:02d}".format(*divmod(t, 60))
>     >         timeString.set(lcd)
>     >         try:
>     >             root.update()
>     >         except TclError:
>     >             messagebox.showinfo('Info', 'Closing app wont stop
>     timer.')
>     >             return
>     >         time.sleep(1)
>     >     return
>
>
>     HTH
>     --
>     Alan G
>     Author of the Learn to Program web site
>     http://www.alan-g.me.uk/
>     http://www.amazon.com/author/alan_gauld
>     <http://www.amazon.com/author/alan_gauld>
>     Follow my photo-blog on Flickr at:
>     http://www.flickr.com/photos/alangauldphotos
>     <http://www.flickr.com/photos/alangauldphotos>
>
>
>     _______________________________________________
>     Tutor maillist  -  Tutor at python.org <mailto:Tutor at python.org>
>     To unsubscribe or change subscription options:
>     https://mail.python.org/mailman/listinfo/tutor
>     <https://mail.python.org/mailman/listinfo/tutor>
>
>


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



More information about the Tutor mailing list