Discussion:
[Tutor] cannot get a label message to display immediately
Bill Allen
2015-08-14 16:32:59 UTC
Permalink
I am working in Tkinter. The scenario is that I click a button that
starts a function running. No problem there. However, the function may
take some time to run and I do not want the user to be worried. I am
wanting to immediately set a label when the function starts to say "Please
Wait". However, the label does not show up until the function completes.
How do I get both actions to happen essentially at the same time, the
writing of the label and the execution of the function? I have no code to
show on this one because I am lost in the weeds, not sure of the general
way to go on this.


Thanks,
--Bill Allen
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Alex Kleider
2015-08-14 16:50:31 UTC
Permalink
Post by Bill Allen
I am working in Tkinter. The scenario is that I click a button that
starts a function running. No problem there. However, the function may
take some time to run and I do not want the user to be worried. I am
wanting to immediately set a label when the function starts to say "Please
Wait". However, the label does not show up until the function
completes.
How do I get both actions to happen essentially at the same time, the
writing of the label and the execution of the function? I have no code to
show on this one because I am lost in the weeds, not sure of the general
way to go on this.
Thanks,
--Bill Allen
Might it be possible to insert the code that posts the 'label' into the
beginning of the function's code block?
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Alan Gauld
2015-08-14 20:08:39 UTC
Permalink
Post by Alex Kleider
Might it be possible to insert the code that posts the 'label' into the
beginning of the function's code block?
That doesn't work because the GUI won't redraw itself until
the event handler finishes and returns control to the Tkinter
event loop. That's why you must avoid long running event
handlers.

You can force a redraw periodically from within the handler
but that doesn't really help much - the GUI is still frozen
for the user which is the biggest issue!.
--
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


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
boB Stepp
2015-08-14 16:56:23 UTC
Permalink
Post by Bill Allen
I am working in Tkinter. The scenario is that I click a button that
starts a function running. No problem there. However, the function may
take some time to run and I do not want the user to be worried. I am
wanting to immediately set a label when the function starts to say "Please
Wait". However, the label does not show up until the function completes.
How do I get both actions to happen essentially at the same time, the
writing of the label and the execution of the function? I have no code to
show on this one because I am lost in the weeds, not sure of the general
way to go on this.
I am on the path to learning myself, but couldn't you, as part of the
function, have it either set the label itself or call another function
that does this, and then execute the main part of your function?
Also, just before your function returns its result, it could
clear/rewrite the label.

Additionally, tkinter has the ability to change the cursor to an
hourglass. You could handle this analogously to what I already said.

HTH,
--
boB
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Laura Creighton
2015-08-14 17:19:42 UTC
Permalink
Post by Bill Allen
I am working in Tkinter. The scenario is that I click a button that
starts a function running. No problem there. However, the function may
take some time to run and I do not want the user to be worried. I am
wanting to immediately set a label when the function starts to say "Please
Wait". However, the label does not show up until the function completes.
How do I get both actions to happen essentially at the same time, the
writing of the label and the execution of the function? I have no code to
show on this one because I am lost in the weeds, not sure of the general
way to go on this.
Thanks,
--Bill Allen
Have you ever used threads before?

The standard way to handle this problem is to run your gui in one thread
(the main thread) and then spawn a separate thread to handle any real
work that needs doing.

http://code.activestate.com/recipes/82965-threads-tkinter-and-asynchronous-io/

is one way to handle it, but if you've never used threads before, I
suspect it will be hard to understand. I'm going to be busy for
several hours -- maybe somebody else here can explain.

Laura

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Alan Gauld
2015-08-14 20:06:18 UTC
Permalink
Post by Bill Allen
I am working in Tkinter. The scenario is that I click a button that
starts a function running. No problem there. However, the function may
take some time to run
That's the problem right there. You should never kick of an event
handler that takes a long time to run. Either:
1) Kick of a separate thread to do the back end processing
2) break the function into short chunks and use a timer
(after() in Tkinter) to repeatedly fire the function
(this is the traditional GUI approach)
3) In Python 3.4 use asyncore to create an asynchronous event
loop and feed the functions into that.

Any of these will stop the GUI hanging and enable intermediate
updates (eg a progress bar or countdown) to happen.
Post by Bill Allen
How do I get both actions to happen essentially at the same time, the
writing of the label and the execution of the function?
Using the simplest (but least efficient) timer approach convert
code like:

def long_handler():
for item in data:
processItem(item)
# wait..... for the loop to end

to

def long_handler()
update_status() # change the GUI
getItem(data) # fetch one item from data
processItem(item) # process one item,
if data: # is there any more?
after(20, long_handler) # then go again after 20ms


This then processes the data items at a rate of 50/second until they
complete. You can reduce the delay but there reaches a limit where
the returns reduce.

Using threads and/or asyncore should allow you to process the
data in one go in the background with control still returning
to the GUI. But its more complex to set up and test and asyncore
is very new and network focused (Py3.4 only) although in principle
is generic . At this point I'd recommend threads if you have
large data loads to process and asyncore if yuu have a lot of networking
to do.

HTH
--
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


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Bill Allen
2015-08-15 05:44:58 UTC
Permalink
That's the problem right there. You should never kick of an event handler
1) Kick of a separate thread to do the back end processing
2) break the function into short chunks and use a timer
(after() in Tkinter) to repeatedly fire the function
(this is the traditional GUI approach)
3) In Python 3.4 use asyncore to create an asynchronous event
loop and feed the functions into that.
...
def long_handler()
update_status() # change the GUI
getItem(data) # fetch one item from data
processItem(item) # process one item,
if data: # is there any more?
after(20, long_handler) # then go again after 20ms
http://www.flickr.com/photos/alangauldphotos
Alan and everyone that responded,
Excellent information! It was the concepts that I was falling short on an
this helped me a great deal. In my particular situation, I found using the
after() method indeed worked just fine and was quite simple to implement.
In my case, as simple as this:

def processing(*args): #my initial button click calls this
''' display messages in the information message_frame while the data
is processed '''
info.set('PROCESSING, PLEASE WAIT...') #the label message I was
wanting to get out there to the user
root.after(1000, process_part) #the long running data process


Thanks again!
Bill Allen
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Alan Gauld
2015-08-15 07:21:36 UTC
Permalink
Post by Bill Allen
def processing(*args): #my initial button click calls this
info.set('PROCESSING, PLEASE WAIT...') #the label message I was
root.after(1000, process_part) #the long running data process
That works for getting the message printed but it still leaves
the problem that your UI locks up during the long process.
If its only for a couple of seconds it might be a mild hiccup
but if your processing took, say 5s or longer, the user is
likely to think the program is broken and may force kill
the window or process or take similarly drastic action.

That's why it's important to break the long process into
chunks and call after() from within it. (or run it in the
background) To do otherwise is to risk having your process
cut short in mid flow with the data potentially only
half processed - and you won't know which half!
--
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


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Bill Allen
2015-08-15 15:31:26 UTC
Permalink
On Sat, Aug 15, 2015 at 2:21 AM, Alan Gauld <***@btinternet.com>
wrote:
That works for getting the message printed but it still leaves
Post by Alan Gauld
the problem that your UI locks up during the long process.
If its only for a couple of seconds it might be a mild hiccup
but if your processing took, say 5s or longer, the user is
likely to think the program is broken and may force kill
the window or process or take similarly drastic action.
That's why it's important to break the long process into
chunks and call after() from within it. (or run it in the
background) To do otherwise is to risk having your process
cut short in mid flow with the data potentially only
half processed - and you won't know which half!
Yes, I see. I will start working on reorganizing the code with that in
mind. One other thing that I have found that is quite interesting is that
with my current code the use of after() works as expect with the message to
the user showing up in the UI - if I run it through the IDLE editor.
However, when I run the program from the command line or compile (package)
the program with pyinstaller and run it as a standalone executable the
message to the user does not show up in the UI!
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Bill Allen
2015-08-15 15:44:40 UTC
Permalink
Post by Bill Allen
Yes, I see. I will start working on reorganizing the code with that in
mind. One other thing that I have found that is quite interesting is that
with my current code the use of after() works as expect with the message to
the user showing up in the UI - if I run it through the IDLE editor.
However, when I run the program from the command line or compile (package)
the program with pyinstaller and run it as a standalone executable the
message to the user does not show up in the UI!
Correction! That was not what was happening. Simple mistake in my code
was bypassing the call to the fuction with the after() statement and
running my main data processing routine directly. I had forgot to bind
<Return> to the routine with after() in it. So, program worked OK when I
clicked the button but not when I hit Return!. Dumb...
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

Continue reading on narkive:
Loading...