LISP GUI Examples
I recently ran across Matthew D. Miller’s “Survey of the State of GUI
Programming in Lisp” series on implementing a small GUI
application across various LISP implementations. The first
article in that series uses racket/gui
, so I figured I’d
take a stab at porting that implementation to gui-easy. You can
find my port here.
Porting the code was straightforward, but it uncovered a common
problem with bidirectional input
s: updating the field’s value
observable on every change meant that the text (and cursor position)
changed as the user typed because every change would trigger an update
(and thus a re-rendering of the text) to the underlying text field.
To work around those sorts of problems, I introduced the #:value=?
and #:value->text
arguments in commit ce190608
. Input views
with a #:value=?
function only re-render the text field’s contents
when the current value of the input observable is different (according
to the #:value=?
function) from the previous one. This means that
you can use that argument to control whether or not partial edits end
up triggering a re-rendering of the text, so instead of:
|
|
You can write:
|
|
In the first example, typing a .
after 42
re-renders the text as
42.0
and places the cursor at the end. In the second, it doesn’t
re-render the text at all since 42.0
and 42
are =
. Still, the
second example isn’t perfect since string->number
parses 42.
to
42.0
so, if you type 42.5
into the text field and then delete the
5
, it will re-render the value as 42.0
. You can work around this
problem by avoiding partial updates in the input’s action:
|
|
Perhaps a better way to handle this would be to make the
#:value->text
argument smarter and have it pass the current text to
the rendering function when it has an arity of two. That way the
rendering function can decide whether or not it needs to change the
text. I’ll have to experiment with that.