468,537 Members | 1,827 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,537 developers. It's quick & easy.

Simple TK Question - refreshing the canvas when not in focus

Hey everyone!
I'm not very good with Tk, and I am using a very simple canvas to
draw some pictures (this relates to that nokia screen emulator I had a
post about a few days ago).

Anyway, all is well, except one thing. When I am not in the program,
and the program receives a draw command (from a FIFO pipe), the canvas
does not refresh until I click into the program. How do I force it to
refresh, or force the window to gain focus? It seems like pretty
common behavior, but a few things that I've tried have not worked.

Class screen():
def __init__(self):
self.root = Tkinter.Tk()
self.root.title('Nokia Canvas')
self.canvas = Tkinter.Canvas(self.root, width =130,
height=130)
self.canvas.pack()
self.root.mainloop()

Then somewhere a long the line I do:
self.canvas.create_line(args[0], args[1], args[2],
args[3], fill=color)
self.canvas.pack()

I've tried self.root.set_focus(), self.root.force_focus(),
self.canvas.update(), etc. but I can't get it.
Thanks!
Blaine
Jun 27 '08 #1
10 6587
On Tue, 29 Apr 2008 15:22:12 +0200, blaine <fr*****@gmail.comwrote:
Hey everyone!
I'm not very good with Tk, and I am using a very simple canvas to
draw some pictures (this relates to that nokia screen emulator I had a
post about a few days ago).

Anyway, all is well, except one thing. When I am not in the program,
and the program receives a draw command (from a FIFO pipe), the canvas
does not refresh until I click into the program. How do I force it to
refresh, or force the window to gain focus? It seems like pretty
common behavior, but a few things that I've tried have not worked.

Class screen():
def __init__(self):
self.root = Tkinter.Tk()
self.root.title('Nokia Canvas')
self.canvas = Tkinter.Canvas(self.root, width =130,
height=130)
self.canvas.pack()
self.root.mainloop()

Then somewhere a long the line I do:
self.canvas.create_line(args[0], args[1], args[2],
args[3], fill=color)
self.canvas.pack()
Unrelated question: why are you doing a .pack() again here? Packing the
widget just inserts it at the right place in its container, so you only
have to do it once. So the one you did in __init__ is enough.
I've tried self.root.set_focus(), self.root.force_focus(),
self.canvas.update(), etc. but I can't get it.
IIRC:
- self.root.set_focus() will only work if your application already has the
focus, so it's not what you need here.
- self.root.force_focus() is usually considered as evil: it'll give the
focus to your application whatever the user is doing, which is usually
*really* annoying. So I guess a lot of window managers just refuse to do
it; this may be what happens here.

But self.canvas.update() should work. If it doesn't, then there are
probably limitations on your platform that prevents it to work... Do you
happen to have other applications that can update their display while they
don't have the focus? Do they have the same problem? If they do, it's
probably a limitation on the platform and I guess you won't be able to do
anything about it... BTW, what platform are you on?
Thanks!
Blaine
HTH
--
python -c "print ''.join([chr(154 - ord(c)) for c in
'U(17zX(%,5.zmz5(17l8(%,5.Z*(93-965$l7+-'])"
Jun 27 '08 #2
On Apr 29, 10:36 am, "Eric Brunel" <see.signat...@no.spamwrote:
On Tue, 29 Apr 2008 15:22:12 +0200, blaine <frik...@gmail.comwrote:
Hey everyone!
I'm not very good with Tk, and I am using a very simple canvas to
draw some pictures (this relates to that nokia screen emulator I had a
post about a few days ago).
Anyway, all is well, except one thing. When I am not in the program,
and the program receives a draw command (from a FIFO pipe), the canvas
does not refresh until I click into the program. How do I force it to
refresh, or force the window to gain focus? It seems like pretty
common behavior, but a few things that I've tried have not worked.
Class screen():
def __init__(self):
self.root = Tkinter.Tk()
self.root.title('Nokia Canvas')
self.canvas = Tkinter.Canvas(self.root, width =130,
height=130)
self.canvas.pack()
self.root.mainloop()
Then somewhere a long the line I do:
self.canvas.create_line(args[0], args[1], args[2],
args[3], fill=color)
self.canvas.pack()

Unrelated question: why are you doing a .pack() again here? Packing the
widget just inserts it at the right place in its container, so you only
have to do it once. So the one you did in __init__ is enough.
I've tried self.root.set_focus(), self.root.force_focus(),
self.canvas.update(), etc. but I can't get it.

IIRC:
- self.root.set_focus() will only work if your application already has the
focus, so it's not what you need here.
- self.root.force_focus() is usually considered as evil: it'll give the
focus to your application whatever the user is doing, which is usually
*really* annoying. So I guess a lot of window managers just refuse to do
it; this may be what happens here.

But self.canvas.update() should work. If it doesn't, then there are
probably limitations on your platform that prevents it to work... Do you
happen to have other applications that can update their display while they
don't have the focus? Do they have the same problem? If they do, it's
probably a limitation on the platform and I guess you won't be able to do
anything about it... BTW, what platform are you on?
Thanks!
Blaine

HTH
--
python -c "print ''.join([chr(154 - ord(c)) for c in
'U(17zX(%,5.zmz5(17l8(%,5.Z*(93-965$l7+-'])"
Thanks a lot for the response! To answer your first question - I'm
using pack() there because I didn't mean to slip it in - this is
something I wrote very quickly and was playing around with... and
pack() should not be there, heh.

I'm just using OS X with Python 2.5. For the record - I don't mind if
the application forces focus. The only time I will be running this
emulator is when I'm trying to use it.

I'll try the update() again. I would want to use that on the canvas
itself right? Not the root window?

Blaine
Jun 27 '08 #3
On Tue, 29 Apr 2008 17:09:18 +0200, blaine <fr*****@gmail.comwrote:
[snip]
I'll try the update() again. I would want to use that on the canvas
itself right? Not the root window?
Well, in fact, there is no difference at all... In tcl/tk, update is a
function, and isn't applied to a particular widget. Any call to the update
method on any widget should refresh the whole GUI.

HTH
--
python -c "print ''.join([chr(154 - ord(c)) for c in
'U(17zX(%,5.zmz5(17l8(%,5.Z*(93-965$l7+-'])"
Jun 27 '08 #4
blaine wrote:
Hey everyone!
I'm not very good with Tk, and I am using a very simple canvas to
draw some pictures (this relates to that nokia screen emulator I had a
post about a few days ago).

Anyway, all is well, except one thing. When I am not in the program,
and the program receives a draw command (from a FIFO pipe), the canvas
does not refresh until I click into the program. How do I force it to
refresh, or force the window to gain focus? It seems like pretty
common behavior, but a few things that I've tried have not worked.

Class screen():
def __init__(self):
self.root = Tkinter.Tk()
self.root.title('Nokia Canvas')
self.canvas = Tkinter.Canvas(self.root, width =130,
height=130)
self.canvas.pack()
self.root.mainloop()

Then somewhere a long the line I do:
self.canvas.create_line(args[0], args[1], args[2],
args[3], fill=color)
self.canvas.pack()

I've tried self.root.set_focus(), self.root.force_focus(),
self.canvas.update(), etc. but I can't get it.
Thanks!
Blaine
When you read the pipe, do you generate an event? Probably not , and Tk
is event-driven and should never update the canvas if there is no event.
This is how I understand Tk.

I have a Tk program who reads a audio signal (from an RC transmitter) .
I generate a event every 100 msec , and "process" refresh the canvas.
Starting the sequence:
id = root.after(100,process) will call "process" after 100 msec
At the end of "process", repeat:
id = root.after(100,process)
Robert
Jun 27 '08 #5
On Wed, 30 Apr 2008 10:58:06 +0200, Robert.Spilleboudt
<ro*************************@skynet.bewrote:
blaine wrote:
>Hey everyone!
I'm not very good with Tk, and I am using a very simple canvas to
draw some pictures (this relates to that nokia screen emulator I had a
post about a few days ago).
Anyway, all is well, except one thing. When I am not in the program,
and the program receives a draw command (from a FIFO pipe), the canvas
does not refresh until I click into the program. How do I force it to
refresh, or force the window to gain focus? It seems like pretty
common behavior, but a few things that I've tried have not worked.
Class screen():
def __init__(self):
self.root = Tkinter.Tk()
self.root.title('Nokia Canvas')
self.canvas = Tkinter.Canvas(self.root, width =130,
height=130)
self.canvas.pack()
self.root.mainloop()
Then somewhere a long the line I do:
self.canvas.create_line(args[0], args[1], args[2],
args[3], fill=color)
self.canvas.pack()
I've tried self.root.set_focus(), self.root.force_focus(),
self.canvas.update(), etc. but I can't get it.
Thanks!
Blaine
When you read the pipe, do you generate an event? Probably not , and Tk
is event-driven and should never update the canvas if there is no event.
This is how I understand Tk.

I have a Tk program who reads a audio signal (from an RC transmitter) ..
I generate a event every 100 msec , and "process" refresh the canvas.
Starting the sequence:
id = root.after(100,process) will call "process" after 100 msec
At the end of "process", repeat:
id = root.after(100,process)
Robert
Your method actually works and is in fact even clearer: you explicitely
give back the control to the main event loop by sending the event. But the
call to 'update' should also work, since it also gives back the control to
the main event loop, implicitely however. BTW, the pending events *are*
treated by a call to update, which can cause some surprises...
--
python -c "print ''.join([chr(154 - ord(c)) for c in
'U(17zX(%,5.zmz5(17l8(%,5.Z*(93-965$l7+-'])"
Jun 27 '08 #6
Still doesn't work. I'm looking into using wx instead...

This is the full code - does it work for anyone else? Just do a echo
'line 0 0 10 10' dev.file
import sys, os, time, Tkinter, threading

class nokia_fkscrn(Tkinter.Toplevel):
fp=None
def __init__(self, file):
self.fname = file
# Create the FIFO pipe (hopefully /dev/screen or similar)
if not os.path.exists(self.fname): os.mkfifo(self.fname)
self.readthread = threading.Thread(target=self.read)
self.readthread.start()
self.init_canvas()

def init_canvas(self):
# Set up our canvas
self.root = Tkinter.Tk()
self.root.title('Nokia Canvas')
self.canvas = Tkinter.Canvas(self.root, width =130,
height=130)

self.canvas.pack()
self.root.mainloop()
def read(self):
while 1:
self.fp = open(self.fname, 'r')
while 1:
st = self.fp.readline()
if st == '': break
self.process(st)
self.fp.close()

def process(self, line):
cmd = line.split()
if cmd[0] == 'line':
# Draw Line
args = map(int, cmd[1:])
try:
color=args[4]
except:
color='black'
if self.canvas:
print 'Drawing Line:', args
self.canvas.create_line(args[0], args[1], args[2],
args[3], fill=color)
self.canvas.update()
self.canvas.focus_force()

nokia = nokia_fkscrn('dev.file')
Jun 27 '08 #7
blaine wrote:
Still doesn't work. I'm looking into using wx instead...

This is the full code - does it work for anyone else? Just do a echo
'line 0 0 10 10' dev.file
Haven't tried it, but I think that the problem is that you are updating the
UI from the "readthread". A good example to model your app after is here:

http://effbot.org/zone/tkinter-threads.htm

Peter
Jun 27 '08 #8
On Apr 30, 10:41 am, Peter Otten <__pete...@web.dewrote:
blaine wrote:
Still doesn't work. I'm looking into using wx instead...
This is the full code - does it work for anyone else? Just do a echo
'line 0 0 10 10' dev.file

Haven't tried it, but I think that the problem is that you are updating the
UI from the "readthread". A good example to model your app after is here:

http://effbot.org/zone/tkinter-threads.htm

Peter
I had a feeling thats what the problem is. Thank you for that link -
I am in need of a good model.

Thanks for answering both of my questions today, Peter. :)
-Blaine
Jun 27 '08 #9
On Apr 30, 10:41 am, Peter Otten <__pete...@web.dewrote:
blaine wrote:
Still doesn't work. I'm looking into using wx instead...
This is the full code - does it work for anyone else? Just do a echo
'line 0 0 10 10' dev.file

Haven't tried it, but I think that the problem is that you are updating the
UI from the "readthread". A good example to model your app after is here:

http://effbot.org/zone/tkinter-threads.htm

Peter
Update: Not only is that a good model, its exactly what I'm trying to
do. Thanks again!
Jun 27 '08 #10
On Wed, 30 Apr 2008 20:19:32 +0200, blaine <fr*****@gmail.comwrote:
On Apr 30, 10:41 am, Peter Otten <__pete...@web.dewrote:
>blaine wrote:
Still doesn't work. I'm looking into using wx instead...
This is the full code - does it work for anyone else? Just do a echo
'line 0 0 10 10' dev.file

Haven't tried it, but I think that the problem is that you are updating
the
UI from the "readthread". A good example to model your app after is
here:

http://effbot.org/zone/tkinter-threads.htm

Peter

Update: Not only is that a good model, its exactly what I'm trying to
do. Thanks again!
BTW, instead of reading the queue periodically, you can also use the event
loop for that: in the secondary thread, generate a custom event using the
event_generate method. Custom events are enclosed in '<<...>>', the '...'
can be whatever you like. Be sure to generate the event with the
when='tail' option or the event might get handled immediatly. To treatthe
event, do a binding on it: it will be called in your main thread. It's a
common trick to switch threads so that GUI events are treated in the main
thread and not in secondary ones.

Example:

------------------------------------------
import threading
import time
import Queue
from Tkinter import *

root = Tk()

q = Queue.Queue()

def thread_action():
i = 1
while 1:
time.sleep(1)
q.put(i)
root.event_generate('<<Ping>>', when='tail')
i += 1

v = StringVar()

def ping_received(event):
v.set(q.get())

Label(root, textvariable=v, width=10).pack()
root.bind('<<Ping>>', ping_received)

th = threading.Thread(target=thread_action)
th.setDaemon(1)
th.start()

root.mainloop()
------------------------------------------

HTH
--
python -c "print ''.join([chr(154 - ord(c)) for c in
'U(17zX(%,5.zmz5(17l8(%,5.Z*(93-965$l7+-'])"
Jun 27 '08 #11

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

reply views Thread by Mickel Grönroos | last post: by
4 posts views Thread by Jamie Jackson | last post: by
1 post views Thread by Eric Wong | last post: by
2 posts views Thread by Peter Michaux | last post: by
2 posts views Thread by Linda Liu[MSFT] | last post: by
reply views Thread by NPC403 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.