Re: Threading and tkinter
(Sorry: replying to the wrong message here, but my newsreader somehow managed to miss the former post...) On Mar 7, 9:40 am, Jani Hakala jahak...@iki.fi wrote: After reading the docs and seeing a few examples i think this should work ? Am I forgetting something here or am I doing something stupid ? Anyway I see my yellow screen, that has to count for something :) I have been using the following scheme: - Pass the root object to the thread object when creating the object - Define a event_handler: root.bind('SomeEvent', evt_handler) in the main thread. - When the thread has done something that the GUI part should now about, signal an event in the thread: root.event_generate('SomeEvent') (no other arguments) - Call a method of the thread object in the event handler e.g. to get some data from a queue object. This ensures that only the main thread accesses Tkinter-related things. Are you sure about that? Last time I check, doing: root.event_generate('SomeEvent') without any other argument called the binding directly, in the context where it is done, so in the secondary thread. To actually switch to the thread where the bind was done, you had to do: root.event_generate('SomeEvent', when='tail') to force the event to get into the event queue... Maybe it has changed in the latest tcl/tk version (I checked this quite a long time ago on tcl/tk 8.3). BTW, with the newer tcl/tk versions this time, be sure to compile them with thread support ('configure ... --enebale-threads' on Unices and 'nmake ... OPTS=threads' on Windows) if you plan to do such things. We had a lot of problems with this trick on a tcl/tk 8.5 version not compiled with thread support, especially when a lot of events happened in a very short time: crashes, weird errors apparently caused by memory corruption, and so on... -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
On Mar 7, 9:40 am, Jani Hakala jahak...@iki.fi wrote: After reading the docs and seeing a few examples i think this should work ? Am I forgetting something here or am I doing something stupid ? Anyway I see my yellow screen, that has to count for something :) I have been using the following scheme: - Pass the root object to the thread object when creating the object - Define a event_handler: root.bind('SomeEvent', evt_handler) in the main thread. - When the thread has done something that the GUI part should now about, signal an event in the thread: root.event_generate('SomeEvent') (no other arguments) - Call a method of the thread object in the event handler e.g. to get some data from a queue object. This ensures that only the main thread accesses Tkinter-related things. Thanks :-) PS why does the first example leave a running process (dos box) open when you close the gui and yours not ? Also root.after can make the program crash if the threat is waiting for com1 response. Speaking of com1 ports, for some reason I have to start up some other serial terminal app and close it again before the device is returning data to the python app ? Do you need to send something to the com1 device first ? ---first example-- from tkinter import * from threading import Thread from time import sleep class Weegbrug(Thread): def __init__(self): Thread.__init__(self) self.x=0 def run(self): while True: self.x=self.x+1 sleep(0.5) w = Weegbrug() w.start() def display(): v.set(w.x) root.after(500, display) root = Tk() v = StringVar() txt = Label(root, textvariable=v, width=800, height=600, bg='yellow', font=('Helvetica', 300)) txt.pack(expand=YES, fill=BOTH) root.title('Weegbrug') root.overrideredirect(1) root.geometry('%dx%d+0+0' % (root.winfo_screenwidth(), root.winfo_screenheight())) root.after(500, display) root.mainloop() from tkinter import * from threading import Thread from queue import Queue from time import sleep --second example- class Weegbrug(Thread): def __init__(self, gui): Thread.__init__(self) self.gui = gui self.queue = Queue() def run(self): while True: with open('com1', 'w+') as f: for line in f: self.queue.put(line) self.gui.event_generate('LineRead') time.sleep(0.5) def get_line(self): return self.queue.get() def evt_handler(*args): v.set(w.get_line()) r = Tk() r.title('Weegbrug') r.overrideredirect(1) r.geometry('%dx%d+0+0' % (r.winfo_screenwidth(),r.winfo_screenheight ())) r.bind('LineRead', evt_handler) v = StringVar() v.set('0') t = Label(r, textvariable=v, width=100, bg='yellow', font= ('Helvetica', 300)) t.pack(expand=YES, fill=BOTH) w = Weegbrug(r) w.start() r.mainloop() -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
gert gert.cuyk...@gmail.com writes: After reading the docs and seeing a few examples i think this should work ? Am I forgetting something here or am I doing something stupid ? Anyway I see my yellow screen, that has to count for something :) I have been using the following scheme: - Pass the root object to the thread object when creating the object - Define a event_handler: root.bind('SomeEvent', evt_handler) in the main thread. - When the thread has done something that the GUI part should now about, signal an event in the thread: root.event_generate('SomeEvent')(no other arguments) - Call a method of the thread object in the event handler e.g. to get some data from a queue object. This ensures that only the main thread accesses Tkinter-related things. from Tkinter import * from threading import Thread import Queue import time class Weegbrug(Thread): def __init__(self, gui, file_name): Thread.__init__(self) self.gui = gui self.queue = Queue.Queue() self.file_name = file_name def run(self): while True: with open(self.file_name, 'r') as f: for line in f: self.queue.put(line) self.gui.event_generate('LineRead') time.sleep(0.5) def get_line(self): return self.queue.get() root = Tk() v = StringVar() v.set(0) w = Weegbrug(root, '/tmp/test.py') def evt_handler(*args): v.set(w.get_line()) root.bind('LineRead', evt_handler) tx = Label(root, textvariable=v, width=100, bg=yellow, font=(Helvetica, 20)) tx.pack(expand=YES, fill=BOTH) root.title(Weegbrug) # root.overrideredirect(1) # root.geometry(%dx%d+0+0 % (root.winfo_screenwidth(), # root.winfo_screenheight())) # Don't start before there's a handler installed w.start() root.mainloop() Jani Hakala -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
[posted and e-mailed -- please reply to the group] In article 492d5db9-3681-4ae8-827e-f2a4f66be...@v39g2000yqm.googlegroups.com, gert gert.cuyk...@gmail.com wrote: After reading the docs and seeing a few examples i think this should work ? This is a bit late, and I don't have time to review your code, but you should see a good example here: http://www.pythoncraft.com/OSCON2001/index.html -- Aahz (a...@pythoncraft.com) * http://www.pythoncraft.com/ All problems in computer science can be solved by another level of indirection. --Butler Lampson -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
On Mar 6, 7:42 pm, a...@pythoncraft.com (Aahz) wrote: [posted and e-mailed -- please reply to the group] In article 492d5db9-3681-4ae8-827e-f2a4f66be...@v39g2000yqm.googlegroups.com, gert gert.cuyk...@gmail.com wrote: After reading the docs and seeing a few examples i think this should work ? This is a bit late, and I don't have time to review your code, but you should see a good example here: http://www.pythoncraft.com/OSCON2001/index.html -- Aahz (a...@pythoncraft.com) * http://www.pythoncraft.com/ All problems in computer science can be solved by another level of indirection. --Butler Lampson Witch basically translate into stop being a smart ass and just do this :) from tkinter import * def weegbrug(): with open('com1','r') as f: for l in f: v.set(l[2:-1]) root.after(500, weegbrug) root = Tk() v = StringVar() v.set(0) txt = Label(root, textvariable=v, width=800, height=600, bg=yellow, font=(Helvetica, 300)) txt.pack(expand=YES, fill=BOTH) root.title(weegbrug) root.overrideredirect(1) root.geometry(%dx%d+0+0 % (root.winfo_screenwidth(), root.winfo_screenheight())) root.after(500, weegbrug) root.mainloop() -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
gert ger.@gmail.com Hope you do not mind ignoring part of answers, so I can figure out more why things work the way they are. This two examples work, what i do not understand is that in function display i do not have to declare root, v or x ? x is easy - it was declared outside, in module scope, and you modified it after declaring it global. The others are more subtle, and have to do with how the interpreter searches for stuff - first in the local scope, then up the stack in the callers scope, up to finally in the module global scope. That also explains why, if it is not found, you get an error message that says Global variable x not defined (try it and see) - Hendrik -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
The statement x=x+1 (which, by the way, should stylistically be written x = x + 1 yes I was wondering what x=x+1 meant until you translated it... oh, x = x + 1 of course! I thought to myself. Oh wait no I'm sarcastic. -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
On Feb 19, 3:20 am, Steve Holden st...@holdenweb.com wrote: gert wrote: Can you first explain why x stay's 0 please and how i should update x using threads ? fromtkinterimport * from _thread import start_new_thread from time import sleep x=0 def weegbrug(x): while True: x=x+1 sleep(0.5) start_new_thread(weegbrug,(x,)) root = Tk() v = StringVar() v.set(0) txt = Label(root, textvariable=v, width=800, height=600, bg=yellow, font=(Helvetica, 300)) txt.pack(expand=YES, fill=BOTH) root.title(Weegbrug) root.after(500, lambda:v.set(x)) root.mainloop() The reason x stays at zero has nothing to do withthreading. The statement x=x+1 (which, by the way, should stylistically be written x = x + 1 if you want your code to be readable) doesn't change anything outside the function. Function arguments are values: since x is a parameter of the function, it exists only inside the function call's namespace. Oeps :) Anyway will this x work in tkinter from _thread import start_new_thread from time import sleep x=0 def weegbrug(): global x while True: x=x+1 sleep(0.5) start_new_thread(weegbrug,()) while True: print(x) -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
gert gert...@gmail.com wrote: On Feb 18, 8:25 am, Hendrik van Rooyen m...@microcorp.co.za wrote: gert gert.cuyk...@gmail.comwrote: After reading the docs and seeing a few examples i think this should work ? Am I forgetting something here or am I doing something stupid ? Anyway I see my yellow screen, that has to count for something :) from tkinter import * from threading import Thread class Weegbrug(Thread): def __init__(self,v): . self.v=v Thread.__init__(self) def run(self): while True: with open('com1','r') as f: for line in f: self.v.set(line[2:-1]) It is in general not a good idea to directly access GUI variables from outside the GUI main loop. There is a recipe for doing this sort of thing, but as usual I have lost the reference. What it does is that instead of interfering directly as above, you put the data on a queue. Then, you use the after() call to set up a call to a routine that reads the queue, and configures the display, and then uses after again to call itself again after a time, thereby keeping the GUI stuff in the GUI mainloop. from tkinter import * from threading import Thread class Weegbrug(Thread): def __init__(self): self.display='0' Thread.__init__(self) def run(self): x=0 while True: x=x+1 self.display=x Still mucking around from outside the GUI. #with open('com1','r') as f: # for l in f: # self.display=l[2:-1] root = Tk() v = StringVar() v.set('0') w = Weegbrug() w.start() tx = Label(root, textvariable=v, width=800, height=600, bg='yellow', font=('Helvetica', 300)) tx.pack(expand=YES, fill=BOTH) root.title('Weegbrug') root.overrideredirect(1) root.geometry('%dx%d+0+0' % (root.winfo_screenwidth(), root.winfo_screenheight())) root.after(500, v.set(w.display)) root.after(500,displayer(q)) # You set up a stutter thread like this root.mainloop() Why does this not work ? It only shows one result ? You are only calling it once. Read my story above again. (And Again) Specially the bit about putting the values into a queue. You need to do something like this: def displayer(q): # stuff to read the queue and update the display root.after(500, displayer(q))# This makes sure it keeps on stuttering Where q is an instance of Queue.Queue There is a nice recipe by Thomas Haeller (?) but I have lost the link. - Hendrik -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
Hope you do not mind ignoring part of answers, so I can figure out more why things work the way they are. This two examples work, what i do not understand is that in function display i do not have to declare root, v or x ? -- example 1 -- from tkinter import * from _thread import start_new_thread from time import sleep x=0 def weegbrug(): global x while True: x=x+1 sleep(0.5) start_new_thread(weegbrug,()) def display(): v.set(x) root.after(500, lambda:display()) root = Tk() v = StringVar() txt = Label(root, textvariable=v, width=800, height=600, bg='yellow', font=('Helvetica', 300)) txt.pack(expand=YES, fill=BOTH) root.title('Weegbrug') root.overrideredirect(1) root.geometry('%dx%d+0+0' % (root.winfo_screenwidth(), root.winfo_screenheight())) root.after(500, lambda:display()) root.mainloop() -- example 2 -- from tkinter import * from threading import Thread from time import sleep class Weegbrug(Thread): def __init__(self): self.x=0 Thread.__init__(self) def run(self): while True: self.x=self.x+1 sleep(0.5) w = Weegbrug() w.start() def display(): v.set(w.x) root.after(500, lambda:display()) root = Tk() v = StringVar() txt = Label(root, textvariable=v, width=800, height=600, bg='yellow', font=('Helvetica', 300)) txt.pack(expand=YES, fill=BOTH) root.title('Weegbrug') root.overrideredirect(1) root.geometry('%dx%d+0+0' % (root.winfo_screenwidth(), root.winfo_screenheight())) root.after(500, lambda:display()) root.mainloop() -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
gert wrote: Hope you do not mind ignoring part of answers, so I can figure out more why things work the way they are. This two examples work, what i do not understand is that in function display i do not have to declare root, v or x ? ... x=0 def weegbrug(): global x while True: x=x+1 sleep(0.5) start_new_thread(weegbrug,()) def display(): v.set(x) root.after(500, lambda:display()) 1) Note that x, v, and root are read and manipulated, but not written. So, they do not need to be declared global (global is only needed to declare writable global names). 2) The last statement could more easily be written: root.after(500, display) ... root.after(500, lambda:display()) Again you can write this: root.after(500, display) --Scott David Daniels scott.dani...@acm.org -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
On Feb 18, 8:25 am, Hendrik van Rooyen m...@microcorp.co.za wrote: gert gert.cuyk...@gmail.comwrote: After reading the docs and seeing a few examples i think this should work ? Am I forgetting something here or am I doing something stupid ? Anyway I see my yellow screen, that has to count for something :) from tkinter import * from threading import Thread class Weegbrug(Thread): def __init__(self,v): self.v=v Thread.__init__(self) def run(self): while True: with open('com1','r') as f: for line in f: self.v.set(line[2:-1]) It is in general not a good idea to directly access GUI variables from outside the GUI main loop. There is a recipe for doing this sort of thing, but as usual I have lost the reference. What it does is that instead of interfering directly as above, you put the data on a queue. Then, you use the after() call to set up a call to a routine that reads the queue, and configures the display, and then uses after again to call itself again after a time, thereby keeping the GUI stuff in the GUI mainloop. from tkinter import * from threading import Thread class Weegbrug(Thread): def __init__(self): self.display='0' Thread.__init__(self) def run(self): x=0 while True: x=x+1 self.display=x #with open('com1','r') as f: # for l in f: # self.display=l[2:-1] root = Tk() v = StringVar() v.set('0') w = Weegbrug() w.start() tx = Label(root, textvariable=v, width=800, height=600, bg='yellow', font=('Helvetica', 300)) tx.pack(expand=YES, fill=BOTH) root.title('Weegbrug') root.overrideredirect(1) root.geometry('%dx%d+0+0' % (root.winfo_screenwidth(), root.winfo_screenheight())) root.after(500, v.set(w.display)) root.mainloop() Why does this not work ? It only shows one result ? -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
gert wrote: After reading the docs and seeing a few examples i think this should work ? Am I forgetting something here or am I doing something stupid ? Anyway I see my yellow screen, that has to count for something :) Try this: # tdh_show.py from __future__ import with_statement import time import Tkinter import Tkconstants as TK import threading class Weegbrug(threading.Thread): def __init__(self, frame, var, filename): self.frame = frame self.var = var self.filename = filename threading.Thread.__init__(self) def run(self): with open(self.filename, 'r') as f: for n, line in enumerate(f): # the tricky bit: self.frame.after(100, self.var.set, line.strip()) time.sleep(.5) def main(filename): root = Tkinter.Tk() svar = Tkinter.StringVar(root) frame = Tkinter.Frame(root, relief=TK.RIDGE, borderwidth=2) frame.pack(fill=TK.BOTH, expand=1) label = Tkinter.Label(frame, textvar=svar, bg='yellow', font=('Helvetica', 16)) label.pack(fill=TK.X, expand=1) button = Tkinter.Button(frame, text=Exit, command=root.destroy) button.pack(side=TK.BOTTOM) reader = Weegbrug(frame, svar, filename) button = Tkinter.Button(frame, text=Go, command=reader.start) button.pack(side=TK.BOTTOM) root.mainloop() if __name__ == '__main__': main(__file__) --Scott David Daniels scott.dani...@acm.org -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
Can you first explain why x stay's 0 please and how i should update x using threads ? from tkinter import * from _thread import start_new_thread from time import sleep x=0 def weegbrug(x): while True: x=x+1 sleep(0.5) start_new_thread(weegbrug,(x,)) root = Tk() v = StringVar() v.set(0) txt = Label(root, textvariable=v, width=800, height=600, bg=yellow, font=(Helvetica, 300)) txt.pack(expand=YES, fill=BOTH) root.title(Weegbrug) root.after(500, lambda:v.set(x)) root.mainloop() -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
gert wrote: Can you first explain why x stay's 0 please and how i should update x using threads ? from tkinter import * from _thread import start_new_thread from time import sleep x=0 def weegbrug(x): while True: x=x+1 sleep(0.5) start_new_thread(weegbrug,(x,)) root = Tk() v = StringVar() v.set(0) txt = Label(root, textvariable=v, width=800, height=600, bg=yellow, font=(Helvetica, 300)) txt.pack(expand=YES, fill=BOTH) root.title(Weegbrug) root.after(500, lambda:v.set(x)) root.mainloop() The reason x stays at zero has nothing to do with threading. The statement x=x+1 (which, by the way, should stylistically be written x = x + 1 if you want your code to be readable) doesn't change anything outside the function. Function arguments are values: since x is a parameter of the function, it exists only inside the function call's namespace. regards Steve -- Steve Holden+1 571 484 6266 +1 800 494 3119 Holden Web LLC http://www.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Threading and tkinter
gert gert.cuyk...@gmail.comwrote: After reading the docs and seeing a few examples i think this should work ? Am I forgetting something here or am I doing something stupid ? Anyway I see my yellow screen, that has to count for something :) from tkinter import * from threading import Thread class Weegbrug(Thread): def __init__(self,v): self.v=v Thread.__init__(self) def run(self): while True: with open('com1','r') as f: for line in f: self.v.set(line[2:-1]) It is in general not a good idea to directly access GUI variables from outside the GUI main loop. There is a recipe for doing this sort of thing, but as usual I have lost the reference. What it does is that instead of interfering directly as above, you put the data on a queue. Then, you use the after() call to set up a call to a routine that reads the queue, and configures the display, and then uses after again to call itself again after a time, thereby keeping the GUI stuff in the GUI mainloop. HTH - Hendrik -- http://mail.python.org/mailman/listinfo/python-list