[previous] [up] [next]     [index]
Next: Drawing Class Reference Up: Drawing Toolbox Previous: Drawing Toolbox

Drawing Toolbox Overview

Drawing in MrEd requires a device context (DC), which is an instance of the dc<%> interface. For example, the get-dc method of a canvas returns a dc<%> instance for drawing into the canvas window. Other kinds of DCs draw to different kinds of devices:

Tools that are used for drawing include the following: pen% objects for drawing lines and shape outlines, brush% objects for filling shapes, and bitmap% objects for storing bitmaps.

The following example creates a frame with a drawing canvas, and then draws a round, blue face with square, yellow eyes and a smiling, red mouth:

  ; Make a 300  tex2html_wrap_inline66617  300 frame 
  (define frame (make-object frame% "Drawing Example" #f 300 300)) 
  ; Make the drawing area 
  (define canvas (make-object canvas% frame)) 
  ; Get the canvas's drawing context 
  (define dc (send canvas get-dc))

; Make some pens and brushes (define no-pen (make-object pen% "BLACK" 1 'transparent)) (define no-brush (make-object brush% "BLACK" 'transparent)) (define blue-brush (make-object brush% "BLUE" 'solid)) (define yellow-brush (make-object brush% "YELLOW" 'solid)) (define red-pen (make-object pen% "RED" 2 'solid))

; Define a procedure to draw a face (define (draw-face dc) (send dc set-pen no-pen) (send dc set-brush blue-brush) (send dc draw-ellipse 50 50 200 200)

(send dc set-brush yellow-brush) (send dc draw-rectangle 100 100 10 10) (send dc draw-rectangle 200 100 10 10)

(send dc set-brush no-brush) (send dc set-pen red-pen) (let ([pi (atan 0 -1)]) (send dc draw-arc 75 75 150 150 (* 5/4 pi) (* 7/4 pi))))

; Show the frame (send frame show #t) ; Wait a second to let the window get ready (sleep/yield 1) ; Draw the face (if the window is ready) (draw-face dc)

The sleep/yield call is necessary under X because drawing to the canvas has no effect when the canvas is not shown. Although the (send frame show #t) expression queues a show request for the frame, the actual display of the frame and its canvas requires handling several events. The sleep/yield procedure pauses for a specified number of seconds, handling events while it pauses.

One second is plenty of time for the frame to show itself, but a better solution is to create a canvas with an on-paint method. Using on-paint is better for all platforms; when the canvas in the above example is resized or temporarily covered by another window, the face disappears. To ensure that the face is redrawn whenever the canvas itself is repainted, we override the canvas's on-paint method:

  ; Make a 300  tex2html_wrap_inline66617  300 frame 
  (define frame (make-object frame% "Drawing Example" #f 300 300))

; Derive a class for a canvas that calls draw-face to repaint itself (define face-canvas% (class canvas% (frame) (inherit get-dc) (override [on-paint (lambda () (draw-face (get-dc)))]) (sequence (super-init frame)))) ; Make the drawing area (define canvas (make-object face-canvas% frame))

; ... pens, brushes, and draw-face are the same as above ...

; Show the frame (send frame show #t)

Suppose that draw-face creates a particularly complex face that takes a long time to draw. We might want to draw the face once into an offscreen bitmap, and then override on-paint to copy the cached bitmap image onto the canvas whenever the canvas is updated. To draw into a bitmap, we first create a bitmap% object, and then we create a bitmap-dc% to direct drawing commands into the bitmap:

  ; ... pens, brushes, and draw-face are the same as above ...

; Create a 300 tex2html_wrap_inline66617 300 bitmap (define face-bitmap (make-object bitmap% 300 300)) ; Create a drawing context for the bitmap (define bm-dc (make-object bitmap-dc%)) ; Direct the drawing context to the bitmap (send bm-dc set-bitmap face-bitmap) ; A new bitmap's initial content is undefined, so clear it before drawing (send bm-dc clear)

; Draw the face into the bitmap (draw-face bm-dc)

; Make a 300 tex2html_wrap_inline66617 300 frame (define frame (make-object frame% "Drawing Example" #f 300 300))

; Derive a class for a canvas that copies the bitmap to repaint itself (define bitmap-face-canvas% (class canvas% (frame) (inherit get-dc) (override [on-paint (lambda () (send (get-dc) draw-bitmap face-bitmap 0 0))]) (sequence (super-init frame)))) ; Make the drawing area (define canvas (make-object bitmap-face-canvas% frame))

; Show the frame (send frame show #t)

For all types of DCs, the drawing origin is the top-left corner of the DC. When drawing to a window or bitmap, DC units initially correspond to pixels, but the set-scale method changes the scale. When drawing to a PostScript or printer device, DC units initially correspond to points (1/72 of an inch).

Drawing effects are not completely portable across platforms or across types of DC. The drawing toolbox provides tools to draw images precisely and portably, but also provides convenience tools for occasions when precision or portability is not necessary. For example, drawing with a pen of width 0 or 1 produces reliable results for all platforms and unscaled DCs, but a pen width of 2 or drawing to a scaled DC looks slightly different depending on the platform and destination.


[previous] [up] [next]     [index]
Next: Drawing Class Reference Up: Drawing Toolbox Previous: Drawing Toolbox

PLT