Just to follow up on how I solved my problem, here is what I did.

I have files, script_launcher.py, controller.py, view.py, model.py which implement a classic model view controller interface.  I can install this "Special Wizard" by the "Install Plugin..." menu item from the  Plugins menu. 

To call functions in model from View use the cmd.get_wizard() function.
Never call functions in View from within the Model

Let me know if you are interested in the details.

Matt O'Meara

UNC Chapel Hill

in script_launcher.py I have

import controller, view, model

def __init__( self ):
    self.menuBar.addmenuitem('wizard', 'command', 'Special Wizard',
                             label= "Special Wizard", command= lambda s=self: launch( s ) )

def launch( s ):
    controller = controller.Controller()
    view = view.View( s, controller )
    model = model.Model( controller )
    cmd.set_wizard( model )

in controller.py I have

class Controller:
    def  __init__( self ):
         self.handlers = []
         self.events = {}

     #event handling routines

in view.py I have

class View():
    def __init__( self, app, controller ):
        self.parent = Tkinter.Toplevel( app.root )
        self.controller = controller
        #register event handlers with self.controller


    def updater( self ):
        #check for events to handle in self.controller
        self.parent.after( 500, self.updater )

in model.py I have

class Model( Wizard ):
    def __init__( self, controller, _self=cmd ):
        if _self.__name__ = "pymol.cmd":  
            Wizard.__init__(self, _self )
            Wizard.__init__(self, _self.cmd )

        self.controller = controller
        #register events with self.controller

On Fri, Apr 25, 2008 at 4:15 PM, DeLano Scientific <delsci@delsci.info> wrote:
A key PyMOL concept for Tkinter developer to grasp is that Tkinter runs in a separate thread from PyMOL.  Thus, direct calls to Tkinter from a PyMOL thread will fail erratically, as observed below. 
Fortunately, PyMOL is built so that it can receive API calls asychronously from any thread.  Therefore, you can develop using Tkinter from the its own thread, and then message PyMOL from there.  The only hard part is launching your GUI, which is something you cannot do from a PyMOL script or program directly.  Instead, you add a new item in the Plugin menu or a whole new menu for your GUI as part of your initialization.
The plugin approach is the safe way to add new functionality using Tkinter.  See modules/pmg_tk/startup/__init__.py for example code to get you started.  
DeLano Scientific LLC
Subscriber Support Services

From: pymol-users-bounces@lists.sourceforge.net [mailto:pymol-users-bounces@lists.sourceforge.net] On Behalf Of Matthew O'Meara
Sent: Friday, April 25, 2008 12:46 PM
To: PyMOL-users@lists.sourceforge.net
Subject: [PyMOL] access to tkinter root for new Toplevel?

Hi All,

I would like to write a Wizard that spawns a separate window.  Right now I'm just calling Tkinter.Toplevel() with no arguments but it dies with non-deterministic tkinter errors.  I think the issue is I need to pass the Tkinter.Tk() instance into the Toplevel command. 

1) Is there a way I can get access to the main Tkinter.Tk() instance from within my Wizard?

I've made a simple version of what I would like that shows the behavior I'm seeing.  To run, copy this into a file called testWizard.py and place into the wizard directory.  Since I installed from Distutils on linux, my wizard directory is /usr/local/lib/python2.5/site-packages/pymol/wizard/.  Then fire up pymol and type into the command line 'wizard testWizard'.  If you version is <1.0 try deleting '_self=cmd' and '_self'.   For me it crashes about every third or so time, usually with different errors.

from pymol.wizard import Wizard
from pymol import cmd
import pymol
import Tkinter

class TestWizard(Wizard):

    def __init__(self,_self=cmd):
        Wizard.__init__(self, _self)

        self.res_table = Tkinter.Tk()  # <- pass app.root in here????

        for i in range( 1000 ): Tkinter.Button(self.res_table, text=str(i)).pack()

Thanks in advance!