On Wed, Jan 13, 2010 at 10:35 PM, Geoff Bache <geoff.ba...@gmail.com> wrote: > Hi Geoff, > > On Wed, 13 Jan 2010 20:38:53 +0100 > Geoff Bache <geoff.bache at gmail.com> wrote: > > (...) >> Hi Michael, >> >> I'm trying to write a basic GUI testing tool (in fact, I'm trying to >> add basic Tkinter support to PyUseCase, which has only worked with >> PyGTK so far) >> >> The basic plan when replaying is thus to add an idle handler that can >> generate GUI events for me. >> >> I assumed I would just do >> >> root.after_idle(self.replayEvents) >> >> as I do with PyGTK, but as discussed that failed because it tried to >> simulate events before the widgets were mapped and hence ready to >> receive the events. >> >> Instead I have now done the following: >> >> thread = Thread(target=self.addIdleHandler) >> thread.run() >> >> def addIdleHandler(self): >> root.wait_visibility() >> root.after_idle(self.replayEvents) >> >> def replayEvents(self): >> root.update_idletasks() >> # ... actually do stuff >> >> I must say I don't understand how wait_visibility would work if I >> didn't call it in a different thread. I can't call it in the main >> thread or it will cause deadlock, surely? It is that thread that is >> going to map my widgets so I can't block in it >> waiting for that to happen. >> >> As you can see, the thread is only adding the idle handler, it isn't >> actually doing anything with the widgets itself. >> > > It still looks dangerous to me, because your addidleHandler() calls the > tk methods. Maybe you could try the mtTkinter package Peter suggested > if you want to use threads (I don't know it, so I cannot tell), however > I still think there should be a simpler solution. The suggestion with > wait_visibility() was just a quick shot in the dark; maybe something > like this would do the trick for you: > > from Tkinter import * > root = Tk() > > def foo(): > print 'foo' > > b = Button(root, text='blah', command=foo) > b.pack(padx=100, pady=100) > b.focus_set() > > print root.winfo_ismapped() > b.event_generate('<space>') > > root.deiconify() > root.update() > > print root.winfo_ismapped() > b.event_generate('<space>') > > root.mainloop() > > > Here on my box the first winfo_ismapped() returns 0, the second one 1 > which seems to say that after the root.update() the window is already > visible; the first call to event_generate() seems to be lost here, too, > but after root.update() the event is triggered as expected. > If this does not work for you, another approach might be to use a > withdrawn root window and pack your widgets into a Toplevel window, > which allowed you to use wait_visibility(). >
Hi Michael, Thanks for your detailed reply. I feel also that there should be a simpler solution and I can't say I *want* to use threads exactly. What I think you're missing above is that a GUI testing tool is supposed to deal with an arbitrary application under test so I don't have any control over the widgets and how they're packed. That also makes it difficult to call root.update() because I don't know when the application would be ready for me to do so. In any case, the documentation for update() is as follows: "This method forces the updating of the display. It should be used only if you know what you're doing, since it can lead to unpredictable behavior or looping. It should never be called from an event callback or a function that is called from an event callback." makes it sound just about as risky as what I'm doing at the moment... especially as I can't really claim I know what I'm doing having looked at tkinter for the first time less than a week ago :) Regards, Geoff _______________________________________________ Tkinter-discuss mailing list Tkinter-discuss@python.org http://mail.python.org/mailman/listinfo/tkinter-discuss