links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
Programming morphs - page 5 - drawing
Last updated at 9:19 pm UTC on 1 January 2019
 drawOn: aCanvas
 	| dotBounds |
 		fillOval: self bounds
 		color: self color.
 	dotBounds :=
 		(self bounds scaleBy: 1/2)
 			center: self center.
 		fillOval: dotBounds
 		color: Color red
 		borderWidth: 1
 		borderColor: Color black.

 containsPoint: aPoint
 	^(EllipseMorph new bounds: self bounds) containsPoint: aPoint

Often you can get by composing new morphs by sticking old morphs together. Sometimes, however, you want to create a morph that really looks different. You can override drawOn: to do this.

On this page, joe (the circulare morph at the top left) is a BullsEyeMorph, a newly created class for this example. The reason joe looks different than other morphs is because his class has a custom drawOn: method, shown to the left.

drawOn: takes one parameter which is a Canvas to draw on. Morphs don't draw directly to the screen, but instead draw to a Canvas instance as requested; this is how, for example, any morph may be rotated even if the morph doesn't contain rotation code – the morph is drawn onto an off-screen bitmap and then the bitmap is rotated before being displayed.

Canvas's respond to many different drawing commands – try highlighting the word Canvas and pressing alt-b, and you can see some of them. BullsEyeMorph, as you can see, only uses the commands for drawing ovals. There are also commands for text, lines, rectangles, polygons, and bitmap images.

Now you try! jane, the morph on the right, is an instance of CrossMorph. Give CrossMorph a custom drawOn: method so that jane ends up looking like this:

One thing to be aware of when changing a morph's appearance, is that the morph might gain visual holes – places where the morph seems to be nothing but air. For example, after jane has been modified, you should still be able to pick up jane by clicking in the top-left corner area of the cross, even though there is apparently nothing there.

To fix this, you can implement a containsPoint: method. containsPoint: takes a point as an argument, and returns true or false depending on whether the point is considered inside the morph or not. By default, any point within the rectangular bounds of a morph is considered part of the morph, but that isn't the best choice for joe and jane. BullsEyeMorph's containsPoint: implementation is shown to the left, and you'll notice that clicking on the airy parts of joe doesn't do anything. Can you make a reasonable containsPoint: method for CrossMorph?

 "joe := BullsEyeMorph new openInWorld.
 jane := CrossMorph new openInWorld.