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
self.updater()
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 )
else:
Wizard.__init__(self, _self.cmd )
self.controller = controller
#register events with self.controller
On Fri, Apr 25, 2008 at 4:15 PM, DeLano Scientific <[email protected]>
wrote:
> Matt,
>
> 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.
>
> Cheers,
> Warren
>
> --
> DeLano Scientific LLC
> Subscriber Support Services
> mailto:[email protected] <[email protected]>
>
>
> ------------------------------
> *From:* [email protected] [mailto:
> [email protected]] *On Behalf Of *Matthew O'Meara
> *Sent:* Friday, April 25, 2008 12:46 PM
> *To:* [email protected]
> *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!
> Matt
>
>
>