Frame initialization
Paolo Amoroso
amoroso at mclink.it
Mon Aug 9 18:32:30 CEST 2004
Paolo Amoroso <amoroso at mclink.it> writes:
> In a frame, I am trying to automatically initialize the value of a
> gadget based on the value of a frame slot at creation time. I use
> code like this:
>
> (in-package :clim-user)
>
> (define-application-frame frame-init ()
> ((default-value :initarg :default :accessor default-value :initform nil))
> (:panes
> (text :text-field :value " "))
> (:layouts
> (default
> (labelling (:label "Text field")
> text))))
>
> (defun init-default (frame)
> (when (default-value frame)
> (setf (gadget-value (find-pane-named frame 'text))
> (default-value frame))))
>
> (defmethod run-frame-top-level :before ((frame frame-init) &key)
> (init-default *application-frame*))
[...]
> also been created. Instead, when evaluating a form such as:
>
> (run-frame-top-level (make-application-frame 'frame-init :default "Paolo"))
>
> I get this error (from the sldb buffer):
>
> No matching method for the generic function
> #<STANDARD-GENERIC-FUNCTION GOATEE::BUFFER (2) {2834A229}>, when called with
> arguments (NIL).
> [Condition of type PCL::NO-APPLICABLE-METHOD-ERROR]
>
> Restarts:
> 0: [CONTINUE] Retry call to :FUNCTION.
> 1: [ABORT] Abort handling SLIME request.
> 2: [ABORT] Return to Top-Level.
>
> Backtrace:
> 0: ("DEFMETHOD NO-APPLICABLE-METHOD (T)" #<#1=unused-arg> #<#1#>
> #<STANDARD-GENERIC-FUNCTION GOATEE::BUFFER (2) {2834A229}> (NIL))
> 1: ((METHOD (SETF GADGET-VALUE) (:AFTER) (T TEXT-FIELD-PANE)) (#(67) . #())
> #<unused-arg> "Paolo" #<TEXT-FIELD-PANE TEXT {580047ED}> ...)
[...]
In gadget.lisp, the (setf gadget-value) after method on
text-field-pane is:
(defmethod (setf gadget-value) :after (new-value (gadget text-field-pane)
&key invoke-callback)
(declare (ignore invoke-callback))
(let* ((area (area gadget))
(buffer (goatee::buffer area))
(start (goatee::buffer-start buffer))
(end (goatee::buffer-end buffer)))
(goatee::delete-region buffer start end)
(goatee::insert buffer new-value :position start)
(goatee::redisplay-area area)))
Area is a text-field-pane slot defined like this:
(area :accessor area :initform nil
:documentation "The Goatee area used for text editing.")
The area slot is initialized by this method:
;; Is there really a benefit to waiting until the first painting to
;; create the goatee instance? Why not use INITIALIZE-INSTANCE?
(defmethod handle-repaint :before ((pane text-field-pane) region)
(declare (ignore region))
(unless (area pane)
(multiple-value-bind (cx cy)
(stream-cursor-position pane)
(setf (cursor-visibility (stream-text-cursor pane)) nil)
(setf (area pane) (make-instance 'goatee:simple-screen-area
:area-stream pane
:x-position cx
:y-position cy
:initial-contents (slot-value pane
'value))))
(stream-add-output-record pane (area pane))))
But when my code in init-default calls (setf gadget-value), the text
field may not have had a chance to handle a repaint event yet, and the
area slot may still contain nil as per its initform. Hence the nil
passed to goatee::buffer in the let* form of (setf gadget-value).
Is this a McCLIM bug? If so, the comment before handle-repaint may
hint at how to fix it.
Paolo
--
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
More information about the mcclim-devel
mailing list