Thu, Nov 28, 3:07 PM CST

Renderosity Forums / Poser Python Scripting



Welcome to the Poser Python Scripting Forum

Forum Moderators: Staff

Poser Python Scripting F.A.Q (Last Updated: 2024 Sep 18 2:50 am)

We now have a ProPack Section in the Poser FreeStuff.
Check out the new Poser Python Wish List thread. If you have an idea for a script, jot it down and maybe someone can write it. If you're looking to write a script, check out this thread for useful suggestions.

Also, check out the official Python site for interpreters, sample code, applications, cool links and debuggers. This is THE central site for Python.

You can now attach text files to your posts to pass around scripts. Just attach the script as a txt file like you would a jpg or gif. Since the forum will use a random name for the file in the link, you should give instructions on what the file name should be and where to install it. Its a good idea to usually put that info right in the script file as well.

Checkout the Renderosity MarketPlace - Your source for digital art content!



Subject: more on: Running multiple Tkinter scripts.


tromnek ( ) posted Fri, 21 January 2005 at 3:46 PM · edited Thu, 28 November 2024 at 2:59 PM

I did some more work on this. It turns out that the real curlprit is Tkinter.mainloop(). I found some stuff on this topic and the best approach for my purpose is to hijack Tkinter's event loop. Here's what I currently have;

<br></br>class prpcdApp:<br></br>    """Your typical application class<br></br>    """<br></br>    def __init__(self, master, textMessage):<br></br>(snip..rest.of.init...)<br></br>    def Update(self):<br></br>      if self.scene: self.scene.ProcessSomeEvents()<br></br>      self.master.lift()<br></br>      self.master.after(50, self.Update)<br></br>(snip..rest.of.class...)<br></br><br></br>#--- Class to Hijack and Restore Tkinters event loops ---<br></br>class NewtMainLoop:<br></br>  """Class to hijack Tkinter and Tkinter.Misc mainloop()<br></br>  """<br></br>  import Tkinter<br></br>  def __init__(self, master):<br></br>      pass<br></br>      self.master = master<br></br><br></br>  def mainloop(self):<br></br>      if self.AmINewt():                        # Return if we are currently hijacked<br></br>       return<br></br>      self.master.after(75, self.ChangeToNewt ) # Hijack Tkinter's event loops, but wait a moment ...<br></br>      self.master.mainloop()                    #   until we run the 'real' event loop.<br></br>      self.GetBetter()                          # Restore the 'real' event loop<br></br><br></br>  def AmINewt(self):<br></br>      if hasattr( Tkinter, 'IGotBetterMainLoop' ):<br></br>        if not Tkinter.IGotBetterMainLoop == None:<br></br>          return 1<br></br>      return 0<br></br><br></br>  def ChangeToNewt(self):<br></br>      # Check if the mainloop() is currently hijacked, if so return.<br></br>      if self.AmINewt():<br></br>        print "I'm already a newt."<br></br>        return<br></br><br></br>      # Save Tkinter's default event loops for later restoration.<br></br>      Tkinter.IGotBetterMainLoop          = Tkinter.mainloop<br></br>      Tkinter.Misc.IGotBetterMiscMainLoop = Tkinter.Misc.mainloop<br></br><br></br>      # Our dummy event loops.<br></br>      def ChangeToNewtMainLoop(n=0):<br></br>        pass<br></br>        print 'call to mainloop()'<br></br>      def ChangeToNewtMiscMainLoop(self, n=0):<br></br>        pass<br></br>        print 'call to Misc.mainloop()'<br></br><br></br>      # Hijack the event loops.<br></br>      Tkinter.mainloop      = ChangeToNewtMainLoop<br></br>      Tkinter.Misc.mainloop = ChangeToNewtMiscMainLoop<br></br>      print "She turned me into a newt."<br></br><br></br>  def GetBetter(self):<br></br>      # Restore Tkinter's default event loops<br></br>      Tkinter.mainloop      = Tkinter.IGotBetterMainLoop<br></br>      Tkinter.Misc.mainloop = Tkinter.Misc.IGotBetterMiscMainLoop<br></br>      print "I Got Better."<br></br><br></br>      # Empty our stuff so we can use it for a logic test.<br></br>      Tkinter.IGotBetterMainLoop          = None<br></br>      Tkinter.Misc.IGotBetterMiscMainLoop = None<br></br><br></br>#--- Activate the loop ---------------<br></br>prpcd = prpcdApp(Tkinter.Tk(), '')      # Create our app, pass Tkinter.Tk() to self.master<br></br>prpcd.Update()<br></br>NewtMainLoop(prpcd.master).mainloop()   # Hijack and run mainloop(), pass a Tkinter.Tk() instance<br></br>print "Left mainloop() in main"         #   so it can call Tk().after() and Tk().mainloop()<br></br><br></br>#--- End Tk loop ------ --------------<br></br>

Let me know what you folks think.


duckmango ( ) posted Fri, 21 January 2005 at 4:33 PM

Tromnek: OK, I'm bringing my scale and pet duck over to see how much you weigh. I think this code proves that ... you're a witch! ;) So to try this out, do both scripts need this hijacked mainloop, or is it one 'regular' mainloop and one newtered one? And how many scripts have you tried to run simultaneously with this framework? Thanks...duckmango


tromnek ( ) posted Fri, 21 January 2005 at 5:27 PM

It works best if this code loads first. Then run as many scripts as you want. Close and reopen them in any order. You can even close this code before others and things will work fine closeing what ever you like in any order, but don't run any new ones. There are some combinations that will make it 'crash', I need to enumerate them in the doc text.


tromnek ( ) posted Fri, 21 January 2005 at 5:55 PM

The main thing to watch out for are foreign scripts where the main function performs some kind of cleanup after it's regular 'mainloop()'. This is because the hijacked mainloop() returns immediately. So scripts should do all their cleanup in their class, not in main.

There are also the standard issues of global() pollution.
This can have some disasterous effects when scripts are running at the same time.


tromnek ( ) posted Sat, 22 January 2005 at 6:10 PM

fixed the premature newted mainloop(). in 'def ChangeToNewtMiscMainLoop(self, n=0)' after the print statement add self.master.wait_window( self ) that should keep us in the newterd mainloop until the foreign script destroy()s itself. Just like expected. I also got rid of the self.master.lift(),(duh!), in my Update method. I also cancel the self.master.after(...) when my apps cleanup code. With this done. You can quit your app before other running 'newtered' scripts and everybody stays happy (I think).


tromnek ( ) posted Sun, 23 January 2005 at 10:54 PM

Oops, self.master.wait_window(self) doesn't help. I guess the newterd scripts will have to be able to handle an immediate return from their mainloop(). Sorry, I thought it was working because all the GUI stuff seemed to be working. Also, I noticed an oddity with Tkinter stuff that relies on 'variable changes', like Radiobutton's 'variable=foo, value=bar'. I had to change my stuff and add a 'command=' to those things.


duckmango ( ) posted Mon, 24 January 2005 at 11:07 AM

More on 'variable changes': I've also noticed a problem with StringVar variables in foreign scripts, as in the widgets don't display them anymore. I'll experiment to try to id this further.


duckmango ( ) posted Mon, 24 January 2005 at 3:26 PM

Follow up: In P5, the textvariable setting in the Label widget stops displaying after running the hijack script. Tkinter snippet: self.myMessage = StringVar() self.myMessage.set("How do you know she's a ...") Label(parent, textvariable=self.myMessage).grid(row=0) This bug appears only in P5. It's OK in PP, as well as in standalone python.


tromnek ( ) posted Mon, 24 January 2005 at 7:49 PM

Looks like I'm going to have to newter Tkinter.Tk() also. Maybe add to
def ChangeToNewt():

<br></br>      Tkinter.IGotBetterTk = Tkinter.Tk<br></br>      def ChangeToNewtTk():<br></br>        return Tkinter.Toplevel()<br></br><br></br>      Tkinter.Tk = ChangeToNewtTk<br></br>

and add to def IGotBetter():

<br></br>      Tkinter.Tk = IGotBetterTk<br></br>

But now the script that does this must run before any other scripts. Like a 'Protecter of the Realm' script.
KingArthur = NewtMainLoop( Tkinter.Tk() )
It will also need to schedule time for poser.ProcessSomeEvents(),
KingArthur.Update()

It seems to work, but I spoke too soon before. I'll test some more when I get a chance thursday.


tromnek ( ) posted Mon, 24 January 2005 at 11:10 PM

file_172909.txt

Here's the beginning of a 'Protector of the Realm'. It should work well enough as it is. It needs to be run before any other scripts are loaded.


tromnek ( ) posted Fri, 28 January 2005 at 1:41 PM

file_172910.txt

Ok. I think this has everything I want. You can create a standalone 'judge/protector' (now named Sir Bedevere) with;
NewtTk().mainloop()

or your app can create a separate 'Sir Bedevere' along with itself by;

root = NewtTk().Tk()<br></br>(snip...)<br></br>root.mainloop()

or your app can keep 'Sir Bedevere' all to itself by;

root = NewtTk().Tk(newtoplevel=0)<br></br>(snip...)<br></br>root.mainloop()

Let me know if there are any problems with this approach (or any suggestions).
duckmango, I renamed a bunch of symbols from earlier versions you saw, hope it isn't too confusing.


tromnek ( ) posted Sun, 30 January 2005 at 9:47 AM

file_172911.txt

Ok. Last beta version 0.14 (I hope).

I had to hijack Tkinter.Misc.quit() also. I added some tracking of newtered (hijacked) scripts so that confirmation of closing can warn a user that other scripts will also close.

I'm releasing the code under the GNU 'Lesser' public license so that this class can be used in commercial scripts.

If I don't hear any complaints or problems within the next week or two, I'll release a non-beta version 1.15 back to this thread.

Duckmango, thanks for the help.
Now I can get back to my 'poser remote procedure call daemon' which is what started all of this stuff.


Privacy Notice

This site uses cookies to deliver the best experience. Our own cookies make user accounts and other features possible. Third-party cookies are used to display relevant ads and to analyze how Renderosity is used. By using our site, you acknowledge that you have read and understood our Terms of Service, including our Cookie Policy and our Privacy Policy.