[ltk-user] Another newbie question..
Peter Herth
herth at peter-herth.de
Tue Mar 11 08:46:43 UTC 2008
Hi Neil,
On Tue, Mar 11, 2008 at 5:46 AM, Neil Baylis <neil.baylis at gmail.com> wrote:
> Now I'm having trouble adding a button to my application. I'm not sure
> whether this is a lisp question, or an ltk question, so please bear
> with me. Here's a simplified version of the failing code:
It is a lisp question...
>
>
> (in-package :ltk)
> (defparameter *cvs* nil)
Here you created the dynamically scoped variable *cvs*, initializing
it with "nil" ...
>
> (defun draw-circle (x y radius color)
> (format t "B Canvas is ~a~%" *cvs*)
> (itemconfigure
> *cvs*
which is accessed here...
> (create-oval *cvs*
> (- x radius) (- y radius)
> (+ x radius) (+ y radius))
> :outline color))
>
> (defun testit ()
> (with-ltk ()
> (let* ((*cvs* (make-instance 'canvas :width 200 :height 200))
Here you rebind the variable, setting it to the canvas
> (b (make-instance 'button
> :master nil
> :text "Do it!"
> :command (lambda ()
> (draw-circle 100 100 20 :red)))))
This draw-circle is called when the button is pressed, that is *outside* the
dynamic contour of the let, and thats why you get the nil.
>
> (format t "A Canvas is ~a~%" *cvs*)
> (pack *cvs*)
> (pack b)
> (draw-circle 100 100 40 :blue))))
This draw-circle is in the dynamic contour of the let, so it succeeds..
>
> When I load this, and call the function testit from the REPL, it
> displays the blue circle correctly, but fails to display the red one.
> Here is what I see in the REPL:
>
>
> CL-USER> (load "testit.lisp")
> #P"/Users/neil/devel/lispgui/testit.lisp"
> CL-USER> (in-package :ltk)
> #<Package "LTK">
> LTK> (testit)
> A Canvas is #<CANVAS #x873D586>
> B Canvas is #<CANVAS #x873D586>
> B Canvas is NIL
>
> It prints the "B Canvas is NIL" when I click on the button, so this is
> obviously why it fails to draw the red circle. But, I don't understand
> why *cvs* is nil in this case. I'm sure this is painfully obvious, but
> not to me. Can someone point me in the right direction please?
It is quite annoying, but the event handlers are run in a different dynamic
context as where they are bound. A help would be to pass the canvas as
a parameter to the event handler like:
(defun draw-circle (canvas x y radius color) ...)
and then set up the button like:
(b (make-instance 'button
:master nil
:text "Do it!"
:command (lambda ()
(draw-circle *cvs* 100 100 20 :red)))))
As the lambda is a proper closure, it properly catches the value of *cvs* and
can pass it on to draw-circle.
HTH,
Peter
More information about the ltk-user
mailing list