Hi Neil,
On Tue, Mar 11, 2008 at 5:46 AM, Neil Baylis neil.baylis@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