A vanilla control for drawing arbitrary custom drawings. The drawing can either be performed at will or by an on-redisplay handler function whenever a redisplay is needed. A bitmap-stream may optionally be used by the control, either to remember what currently should be drawn on the control or to draw updates with less flashing.
A drawable control allows a drawing field in a dialog. Other ways to
combine drawing with controls is to use a window with one pane a
bitmap-pane
and another a dialog
, or to use a
bitmap-window
with a toolbar (on which controls can be placed). It is also possible
to place controls directly on a bitmap-pane
, though in that case
certain features and lost, such as using the TAB key to move focus
from one control to another. (However, if that feature is less
important, putting controls directly on a bitmap-pane does allow for
faster redisplay.)
There are two issues with images on a drawable control: displaying them in the first place and refreshing them when necessary (when, for example, the control is covered and uncovered, or iconified and expanded).
If use-bitmap-stream is nil, drawing is done by the on-redisplay function. This function (an example is given on the on-redisplay page) should do all drawing necessary. Whenever redisplay is necessary, this function will be called. Redisplay is forced by a call to update-drawable. It is also forced when a drawable is covered and uncovered or when it is iconified and expanded.
Whenever a drawable control needs to be redrawn, such as when it is uncovered, redisplay-event is called on it. The default redisplay-event method essentially just calls the on-redisplay handler of the drawable if it has one, and the on-redisplay handler is the more typical place to place custom drawing code.
If use-bitmap-stream is true, there
will be a bitmap-stream
associated with the
drawable control, returned by the function bitmap-stream applied to the
drawable. Drawing should be done to this bitmap-stream, and then the
drawable should be refreshed with a call to update-drawable. The
drawable will also be updated when it is covered and uncovered, or
iconified and expanded. (Note that drawing is not done directly on the
drawable. The bitmap-stream is not visible. It must be copied to the
drawable. Note that this copying can become expensive if the image is
large and redisplays are frequent.)
The function drawable-stream returns the bitmap-stream of a drawable if there is one and the window of the drawable otherwise.
See About how to get sample code for creating controls in cgide.htm, which explains how to use the IDE to create such code.
A drawable animation example
;; An animation example ;; To run this demo, place this entire example into an ;; editor buffer and compile the definitions (typically by ;; using the File | Compile and Load command), then place a ;; drawable control on a form and set its on-redisplay ;; event-handler property to be animation-on-redisplay ;; and set its on-click event-handler to be animation-on-click. ;; Then run the form and click on the drawable control to ;; start or stop it moving across the window from left to right. ;; If you turn on the use-bitmap-stream property of the ;; drawable, then it moves much more smoothly. To test this ;; while the example is running, you can change this property ;; directly on the drawable that's on the running window, rather ;; than changing the one on the form and re-running the form. ;; To do this, invoke the Tools | Get Component command and then ;; click on the drawable on the running window when the cross ;; cursor appears. This "returns" the running drawable, and ;; you may see it printed in the Debug Window. Next invoke ;; the Tools | Inspect Returned Object command. This will inspect ;; the drawable that you just returned. Click the drawable to ;; start the arrow moving (if it's not already), then toggle its ;; use-bitmap-stream property in the inspector. You should see ;; less flashing when the property is turned on, since the ;; drawable is first drawing itself on its bitmap-stream and ;; copying the end result quickly to the visible window. ;; To speed up the movement, invoke the Tools | Inspect System ;; Data | Internal System Parameters command, find All Timers in the ;; inspected list and click its left column to inspect it. Then find ;; the timer called :animation-timer and click its left column to ;; inspect it. You can change the "interval" property even while ;; the arrow is moving to change the speed. Or toggle the "active" ;; property to start and stop the timer. (If the arrow were ;; a pixmap instead of a polygon, you could get it to go a ;; lot faster.) (in-package :cg-user) ;; Keep the master version of the arrow coordinates here. (defparameter *arrow-polygon* (list (make-position 0 -10) (make-position 20 -10) (make-position 20 -30) (make-position 50 0) (make-position 20 30) (make-position 20 10) (make-position 0 10))) ;; This is a copy of the arrow coordinates to offset for ;; each position of the arrow, in order to avoid consing ;; lots of new positions. (defparameter *arrow-polygon-2* (list (make-position 0 -10) (make-position 20 -10) (make-position 20 -30) (make-position 50 0) (make-position 20 30) (make-position 20 10) (make-position 0 10))) ;; Each time the timer fires, call update-drawable to draw the ;; current image on the bitmap-stream and then copy it quickly ;; to the visible window. (defun animate-drawable-on-timer (timer) (update-drawable (timer-info timer))) ;; Use a single timer for multiple runs of this example. ;; Find it when needed from its name. (defun animation-timer () (or (find-timer :animate-drawable-timer) (make-instance 'timer :name :animate-drawable-timer))) ;; Turn the timer on or off to start or stop the movement ;; of the arrow. (defun toggle-animation-timer (drawable &key (interval 20)) (let* ((timer (animation-timer)) (count (timer-count timer))) (setf (on-timer timer) 'animate-drawable-on-timer) (setf (interval timer) interval) (setf (timer-info timer) drawable) (setf (active timer)(not (active timer))) (setf (timer-count timer) count))) ;; Use the name of this function as the on-redisplay event-handler ;; property of the drawable control. It will draw the arrow at a ;; certain position based on how many times the timer has fired ;; so far (the timer-count) (defun animation-on-redisplay (drawable stream) (let* ((width (page-width drawable)) (half-height (floor (page-height drawable) 2)) (timer (animation-timer)) (x (- (mod (timer-count timer)(+ width 50)) 50))) (do* ((arrow1 *arrow-polygon* (rest arrow1)) (arrow2 *arrow-polygon-2* (rest arrow2))) ((null arrow1)) (ncopy-position (first arrow2)(first arrow1)) (incf (position-x (first arrow2)) x) (incf (position-y (first arrow2)) half-height)) (with-foreground-color (stream red) (fill-polygon stream *arrow-polygon-2*)) (draw-polygon stream *arrow-polygon-2*))) ;; Use the name of this function as the on-click event-handler ;; property of the drawable control. This lets you click on the ;; control to start or stop the movement of the timer (defun animation-on-click (dialog drawable) (declare (ignore dialog)) (toggle-animation-timer drawable))
Common Graphics and IDE documentation is described in About Common Graphics and IDE documentation in cgide.htm.
The documentation is described in introduction.htm and the index is in index.htm.
Copyright (c) 1998-2000, Franz Inc. Berkeley, CA., USA. All rights reserved.
Created 2000.10.5.