Tix Vs Pmw which is better to use?

Cimarron Taylor cimarron+google at taylors.org
Thu May 2 07:05:21 EDT 2002


I have not used Tix, but I have recently started working with Pmw. 
Overall I'm pretty happy with the result.  First the good things:

1. Pmw is easy to use and there are lots of examples!

2. Pmw has a very nice Notebook widget which makes it easy to create
   the tab-dialog interface I wanted.

Now for the things which frustrated me:

3. Not much thought seems to have been given to making the megawidgets
   support a consistant interface for reading and writing the data
   values. you often have to violate encapsulation to do something
   as mundane as setting the value of a widget.  For example, suppose 
   I create a Pmw.Counter with the following code

     counter = Pmw.Counter(
        parent, labelpos='w', label_text='Number of tests',
        entryfield_value=10, datatype='numeric',
        entryfield_validate={'validator':'numeric', 'min':0, 'max':100},
        increment=10
      ) 

   To set the value of the counter later on, I need to invoke the
   setentry() method on the internal entry widget of the counter:

     counter._counterEntry.setentry(value)

   So how did I know to do this?  The answer is, I studied the demos and 
   the source code and tried lots of things until I found something that 
   worked for this specific widget.  Now suppose somewhere else I create 
   a read-only text box with the following code:

      textbox = Pmw.ScrolledText(
         parent, borderframe=1, text_padx=5, text_pady=5, 
         text_wrap='none', vscrollmode='static', hscrollmode='static'
       )
      textbox._textbox.configure(state='disabled')

   I could find no obvious way to make the text box read-only without
   once again acessing an internal member of the widget.  Also, by trial 
   and error I have discovered that I can set the text of the widget via

      textbox._textbox.configure(state='normal')
      textbox.clear()
      textbox.settext(value) 
      textbox._textbox.configure(state='disabled')

   You get the idea.  To me, the most important thing a megawidget must do
   is manage the value shown to the user and one of the important programming
   services the megawidget layer should provide is a simple and consistent 
   way of accessing that value.  Hence I ended up rolling my own adaptor
   classes for this purpose.  Here is my own Counter:

      class Counter:
        "class providing a common get/set interface to Pmw.Counter"
        def __init__(self, parent, labeltext, init, min, max, incr=1):
           self.counter = Pmw.Counter(
             parent, labelpos='w', label_text=labeltext,
             entryfield_value=init, datatype='numeric',
             entryfield_validate={'validator':'numeric', 'min':min, 'max':max},
             increment=incr) 
           self.counter._counterEntry._entryFieldEntry.config(bg='white')
        def get(self):
           return self.counter._counterEntry.get()
        def set(self, value):
           return self.counter._counterEntry.setentry(value)

4. Pmw has a less-than-useful color abstraction.  The Pmw.Color class 
   may be useful if you want to change the entire color scheme of an
   application but it is difficult to use with a single widget.  For example,
   the Pmw.Color example suggests

	defaultPalette = Pmw.Color.getdefaultpalette(parent)
      normalcolor = Pmw.Color.changebrightness(parent, 'white', 0.85)
	Pmw.Color.setscheme(parent, normalcolor)
       .. create your widget here ..
	apply(Pmw.Color.setscheme, (parent,), defaultPalette)

    but suppose you want only the editable area of the counter to 
    have a white background and not the entire widget to be white.
    The code you see above is a dead-end.  To do what I wanted you 
    will need something like

      self.counter._counterEntry._entryFieldEntry.config(bg='white')

5.  The font system is also a little less than useful.  Suppose you
    want your text box to use a fixed width font.  Once again you 
    will need to access the internal member:

       typewriter = apply(Pmw.logicalfont, ('Typewriter', 0), {})
       textbox = Pmw.ScrolledText(
           parent, borderframe=1, text_padx=5, text_pady=5, 
           text_wrap='none', vscrollmode='static', hscrollmode='static')
       textbox._textbox.configure(font=typewriter)

6.  Be very careful about which geometry management scheme you choose.
    If you accidently mix .pack() and .grid(), you may end up with an
    application which freezes up the first time you resize it (of course,
    this is probably more of a Tkinter problem than a Pmw one).

Now a question for the group.  I would like to add to my interface a
text area which would contain the output of a separate long running make
process I need to spawn.  I can't just call system() as that would block
the entire ui (unless I setup a separate thread).  I've tried using fork()
and exec() but that seems to cause an X server error which kills the entire
application. 

The best thing I've found so far is to run the separate process in an 
xterm window by creating an instance of the following class:

  class StartMake:
     def __init__(self, target):
        os.popen('xterm -e make %s &' % target)

I know there are probably a few paths I could start down:

  a. use threads (yeah I know, but seems like overkill for this)
  b. get a window id of a Tkinter widget and have xterm use that window (yuck!)
  c. use a Tkinter alarm to poll the tail of a file containing the make output
     (this is what I might end up doing, but seems clumsy)

Any suggestions?

Cim



More information about the Python-list mailing list