Re: [Tutor] Tkinter, widgets not displaying...
Hugo González Monteverde wrote: Hi All, I wrote a small turn delivering graphical app that is supposed to display turns in a queue. def insert(self, turn_string): Insert a new turn into the queue, move the rest upwards, delete oldest. This is overly complicated: current_values = [self.read_panel(i) for i in range(len(self.canvases))] You are going to throw away the first value, there is no need to read it. next_values = current_values[:] There is no need to copy current_values since it is a brand new list already. next_values[:-1] = current_values[1:] next_values[-1] = turn_string This works but you could just copy the part of current_values you want and append turn_string. Taking all this together, you can write just next_values = [self.read_panel(i) for i in range(1, len(self.canvases))] next_values.append(turn_string) But there is a deeper issue here. You seem to be writing some kind of simulation. You might want to consider separating your model - the data and mechanics of the simulation - from the GUI - the visual representation. The way you have it now, the data is stored in the GUI itself. This leads to tight coupling between the model and the GUI. It will be hard to test the model or to put a different front-end on it, and hard to have a clean conceptual model of the simulation. For example, you could have this model class: class QueueModel(object): def __init__(self, length=4): self.data = [None * length ] def insert(self, item): self.data.pop() # remove the first item self.data.append(item) Then in your GUI, your insert() method would become update(self, model). Or maybe instantiate the GUI giving it an instance of the model. Your main program would drive them both. Oversimplifying by leaving out the threading, it would look like model = QueueModel(length=4) gui = TurnQueue(model, pw=200, ph=100) for i in range(100): model.insert(str(i)) gui.update() sleep(0.2) As the model develops, this separation from the GUI will make it much easier to work with. Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Tkinter, widgets not displaying...
John Fouhy wrote: If you want to do multithreaded programming with a GUI, one good way is to use .after_idle. ie, instead of myturns.insert(str(i)), do top.after_idle(myturns.insert, str(i)) (I think this is the right syntax). This will cause the mainloop thread to run the code instead. Another way to do this without a separate thread is to use top.after() to schedule the inserts. Schedule the first one before calling mainloop(), and have each insert schedule the next one. Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Tkinter, widgets not displaying...
Hi Kent and John, Thanks a lot for the advice on how to improve my program. I will look into separating the data and model as John suggests here. I didn't know about after_idle() and after(); seems that dir()'ing the classes sometimes gives out a lot more information than you can chew at any given time :) Thanks, Hugo ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
[Tutor] Tkinter, widgets not displaying...
Hi All, I wrote a small turn delivering graphical app that is supposed to display turns in a queue. If I instantiate the class and call its methods, thus displaying strings in several canvases, from the interactive prompt, everything works fine. If I do it when running the script as a programs, nothing gets displayed. If I call mainloop() at the end of my program, everything gets displayed, but then I cannot use my own function classes. This program will never respond to events, but just get called from a queue manager script for display... Here's the code: #!/usr/bin/env python from __future__ import division import Tkinter import tkFont from Tkconstants import * from time import sleep class TurnQueue(Tkinter.Frame): def __init__(self, master=None, pw=60, ph=60, panels=4): self.ph = ph self.pw = pw self.panels = panels Tkinter.Frame.__init__(self, master) self.createWidgets() self.pack() def createWidgets(self): Create four canvases and a warning window. self.canvases = [Tkinter.Canvas(height=self.ph, width=self.pw, borderwidth=1, background = '#FF') for i in range(self.panels)] self.textbox_ids = [] # display them all, initialized for i in self.canvases: id = i.create_text(self.pw//2, self.ph//2, text='', font=('bitstream charter', self.ph, 'bold'), fill='red') self.textbox_ids.append(id) i.pack() def write_panel(self, panel_no, newtext): writepanel(self, panel, newtext) Set panel panel to text newtext self.canvases[panel_no].itemconfigure(self.textbox_ids[panel_no], text=newtext) def read_panel(self, panel_no): textcontents - read_panel(self, panel_no) Read panel text contents return(self.canvases[panel_no].itemcget(self.textbox_ids[panel_no], 'text')) def insert(self, turn_string): Insert a new turn into the queue, move the rest upwards, delete oldest. current_values = [self.read_panel(i) for i in range(len(self.canvases))] next_values = current_values[:] next_values[:-1] = current_values[1:] next_values[-1] = turn_string # update all panel values for i in range(len(self.canvases)): self.write_panel(i, next_values[i]) if __name__ == __main__: myturns = TurnQueue(pw=200, ph=100, panels=4) for i in range(100): myturns.insert(str(i)) sleep(0.2) ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Tkinter, widgets not displaying...
Sorry for replying to myself, but I found a page that says that it can be done without threads... so it hit me: use threads!!! (duh) Ok, for future reference, this is the part where I use the classes I defined: if __name__ == __main__: top = Tkinter.Tk() myturns = TurnQueue(top, pw=200, ph=100, panels=4) #importing here is ugly, but just for testing. from thread import start_new_thread start_new_thread(Tkinter.Tk.mainloop, (top,)) for i in range(10): myturns.insert(str(i)) sleep(0.2) So now I see my line of canvases displaying numbers going upwards.. Hugo ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] Tkinter, widgets not displaying...
On 10/02/06, Hugo González Monteverde [EMAIL PROTECTED] wrote: Sorry for replying to myself, but I found a page that says that it can be done without threads... so it hit me: use threads!!! (duh) Yes, this will be what you need. Your GUI won't do anything until you run mainloop, and mainloop won't exit until you close your GUI. So if you want to programmatically feed data in, you need to do it from a different thread. One caveat, though --- if __name__ == __main__: start_new_thread(Tkinter.Tk.mainloop, (top,)) for i in range(10): myturns.insert(str(i)) sleep(0.2) By doing this, you are changing the GUI from a different thread from the one running mainloop. This is a BAD IDEA. It can easily lead to weird bugs that you will struggle to understand. If you want to do multithreaded programming with a GUI, one good way is to use .after_idle. ie, instead of myturns.insert(str(i)), do top.after_idle(myturns.insert, str(i)) (I think this is the right syntax). This will cause the mainloop thread to run the code instead. HTH! -- John. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor