[plt-scheme] MrEd: how can I _cleanly_ keep the states of various widgets in sync?

From: Eric Hanchrow (offby1 at blarg.net)
Date: Thu Nov 29 18:53:24 EST 2007

I'll let the comments in my example program speak for themselves:

#! /bin/sh
#| Hey Emacs, this is -*-scheme-*- code!
#$Id: gui-constraints.ss 5286 2007-11-29 23:51:36Z erich $
exec mred --no-init-file --mute-banner --version --require "$0"
|#
(module gui-constraints mzscheme
(require (lib "class.ss")
         (lib "mred.ss" "mred"))

;; Trying to use MrEd to solve a problem that is easily solved in
;; Delphi 6, and presumably other sophisticated GUI builders: we have
;; a couple of widgets, and we'd like the state of each of those
;; widgets to be determined by the states of some of the others.
;; Imagine a button and a radio-box, where the button is enabled if
;; and only if certain items are selected in the radio box.  Now, we
;; could certainly add code to the callback for _the radio box_ that
;; fiddles the enabled state of the button, but imagine that we
;; actually have lots of widgets, not just two, and their
;; interrelationships are complex.  It seems to me that it's easier to
;; put the code that enables a widget right "next to" that widget, and
;; have that code refer to all the things that affect it, than the
;; other way around, namely, having each widget "know" about those
;; that it -affects-.

;; So my solution is to write a background thread that runs all the
;; "update me" processes.  This code here does just that, for a very
;; simple case.  Alas the background thread burns up all the CPU
;; without that ugly "sleep" call; I haven't yet figured out how to
;; make it run only when it needs to run (i.e., when some state in the
;; GUI has changed).

;; * I think Kenny Tilton's "Cells"
;;   (http://common-lisp.net/project/cells/) are a sophisticated way
;;   to solve this problem (probably without threads)

;; * Java's "Swing" GUI thingy has something called "Actions" that
;;   might solve the same problem:
;;   http://java.sun.com/docs/books/tutorial/uiswing/misc/action.html;
;;   "hotblack23" on #scheme suggests that
;;   java.beans.PropertyChangeListener is the relevant class

;; * C-sharp has some documentation on "Event-based Asynchronous
;;   Pattern", which _might_ be relevant (but in typical M$ style,
;;   it's very hard to understand):
;;   http://msdn2.microsoft.com/en-us/library/wewwczdw.aspx

(define frame (new frame% (label "Constraint Testing")))

(define button
  (new button% (parent frame) (label "Click me!")
       (callback (lambda (item event)
                   (message-box "OK" "Now what?")))))

(define radio-box
  (new radio-box% (label "Pick one")
       (choices '("Disable that button there" "Let it be enabled"))
       (parent frame)))

(thread
 (lambda ()
   (let loop ()
     (sync (system-idle-evt))
     (send button enable
           (not (zero? (send radio-box get-selection))))
     (sleep 1/10)
     (loop))))

(send frame show #t)

)


-- 
If you're trying to choose between two theories and one gives
you an excuse for being lazy, the other one is probably right.
        -- Paul Graham


Posted on the users mailing list.