REALbasic University Resources:

RBU: Glossary Defines common REALbasic programming terms
  Archives Previously published columns
Translations: Dutch Courtesy of Floris van Sandwijk
  Japanese Courtesy of Kazuo Ishizuka
  Chinese Courtesy of Dong Li
  RBU Translation Guide Information on Translating RBU into other languages
Books: Matt's Book (2nd Edition!) Ideal for experienced programmers
  Erick's Book Best for beginning programmers
Websites: Mother Ship The publisher of REALbasic
  RB Webring Links to hundreds of REALbasic websites
  RESExcellence Another REALbasic programming column
  REALbasic Developer Magazine The premiere source for REALbasic instruction.

REALbasic University is Sponsored by

Make your Mac do what YOU want it to. Create games, utilities, cool Mac OS X tricks. Download REALbasic now and create your own software.


Print This Article

REALbasic University: Column 089

OOP University: Part Thirteen

I hope you're enjoying creating our little SuperDraw project. When I began this "OOP University" series I envisioned a handful of columns focused on object-oriented programming, but once I actually began to write the columns I realized they were becoming mere lectures. Practical examples of OOP in the real world seem much more valuable to me, so I developed SuperDraw.

SuperDraw was originally going to stop after just a couple lessons, but as I wrote it, I discovered a couple things. First, I had an itch to improve it by making it do sophisticated things like allowing the resizing of drawing elements. Second, the object-oriented design SuperDraw made it remarkably easy to add these features.

Nothing demonstrates the latter as well as today's lesson, where we'll expand SuperDraw by adding several new object types. Adding these new objects just takes a few lines of code and, remarkably, the new drawing objects automatically inherit the behaviors of the parent object, shapeClass! It's totally sweet.

Adding a Polygon Object

The first object we'll add is a simple polygon object. A polygon is a multi-sided closed figure, and I just arbitrarily chose the shape I chose. Of course you could program your polygon object to draw a different shape that you prefer. Or, if you wanted to get extremely sophisticated, you could create a way for the user to edit and customize the number of sides and the shape of the polygon. In fact, based on how we've designed SuperDraw, it would be possible for each polygon to have a unique shape! (You'd simply store the polygon's array of drawing points within the polygon object -- the tough part would be supporting editing the shape.)

Let's get started by opening the SuperDraw project from last time and adding a new class (File menu, "New Class"). Rename the class polygonClass and set its super to shapeClass (on the properties palette).

Open polygonClass (double-click on it) and in the events area, you should find a paint event. Put this code inside paint:

  
dim points(0) as integer
dim i, n, n2 as integer
dim data, p as string

data = "l,t w,h w,t l,h l,t"

data = replaceAll(data, "l", str(left))
data = replaceAll(data, "t", str(top))
data = replaceAll(data, "w", str(left + width))
data = replaceAll(data, "h", str(top + height))
data = replaceAll(data, "cx", str(left + (width/2)))
data = replaceAll(data, "cy", str(top + (height/2)))

// Number of coordindate pairs
n2 = countFields(data, " ") * 2
redim points(n2)
n = 0
n2 = uBound(points) - 1
for i = 1 to n2 step 2
n = n + 1
p = nthField(data, " ", n)
points(i) = val(nthField(p, ",", 1))
points(i + 1) = val(nthField(p, ",", 2))
next // i

g.drawPolygon points

This is polygonClass' drawing routine. This builds an array of horizontal and vertical coordinates and passes that to the graphic object's drawPolygon method.

In Detail

Notice the (clever?) way I've initialized the points array. The first line, data = defines the actual drawing shape. I use characters to represent the boundaries of the object (top, left, width, height, etc.). These are then replaced by the actual numbers that correspond to those concepts. So "l" (left) might actually become "33" (assuming the object's left side is 33 pixels from the left of our drawing area).

Note there are a couple unused here: "cx" and "cy" represent the half-way point (center) of a direction (cx is the center of the horizontal direction and cy is the center of the vertical dimension). I don't use these for my x-wing shape, but they're useful when doing other shapes (see below).

Then I build the array through a loop. Since we're dealing with coordinate pairs, my loop has a step of 2, meaning it skips every other number. We use n to count where we are in the proceedings.

You'll note that the data line is made of up pairs of letters separated by a comma, and each pair is separated by a space. So we can grab a single pair by isolating a field separated by spaces. We assign that to p (the current coordinate pair). Then from p we grab the first and second parts (separated by a comma) and assign those (as numbers) to our points array. Simple!

The result means that we can easily create a different kind of shape simply by changing the data string. Experiment with this. For instance, this creates an astrix:

data = "l,t cx,cy cx,t cx,cy w,t cx,cy w,cy cx,cy w,h cx,cy cx,h cx,cy l,h cx,cy l,cy, cx,cy l,t"

Obviously to create more complex shapes, you might need the ability to refer to more than just the four corners and center of an object, but you can easily enhance the data string parser to add features if you wanted.

Now we've added a new object, but our program doesn't know to do anything with that object yet. There are two simple steps we need to take to actually implement the new drawing element as part of SuperDraw.

First, we need to modify our interface to give us a way to add this kind of object to our drawing. So double-click on window1 and select the third (bottom) pushButton. Press Command-D (or choose "Duplicate" from the Edit menu). Since this control is part of a control array, REALbasic will automatically number it index 3. Perfect! Now change its text to "New Polygon" and just drag the button to where you want it on the window. We're done with this step!

The next thing we need to do is tell drawCanvasClass how to add this new shape. Open drawCanvasClass and go to the addObject method. After the case 2 code and before the else line, put in this:

  
case 3 // polygon
objectList.append new polygonClass

Guess what? That's it! Our object is added. Amazingly, this object is movable and resizable right off the bat without adding any more code!

But we're not done there. Since that was so easy, let's add some more objects! We're going to move a little quicker this time, so pay attention.

Adding a Picture Object

Wouldn't it be cool if SuperDraw supported placing existing pictures? Well, why not? How hard could it be to add that?

It's actually not difficult, though there is an obstacle to overcome. But we'll deal with that in a minute. First, let's create the object class (File menu, "New Class") and name it pictClass and give it a super of shapeClass.

Open pictClass and add a property of image as picture. In its paint event, put this code:

  
if image <> nil then
// Draw the picture
g.drawPicture(image, left, top, width, height, 0, 0, image.width, image.height)
else
// Draw empty picturebox
g.foreColor = rgb(255, 255, 255) // White
g.fillRect(left, top, width - 1, height - 1)
g.foreColor = rgb(0, 0, 0) // Black
g.drawRect(left, top, width - 1, height - 1)
g.drawLine(left, top, left + width - 1, top + height - 1)
g.drawLine(left, top + height - 1, left + width - 1, top)
end if

This simply draws the picture if there is one. If not, it draws an empty picturebox frame.

We'll need to do as before and add another pushButton on window1, and we'll add another case line in drawCanvasObject's addObject method:

  
case 4 // picture
objectList.append new pictClass

That's all there is to getting the picture object working. However, we don't as yet have a way to install a picture there. The simplest interface to add a picture would be to double-click on a picture box and have it prompt for a picture file to select, so let's do that.

First, we need to add a way to detect a double-click. We do that within drawCanvasObject. Open it and let's add a property: startClick as double.

Then go to mouseDown and at the very beginning (after the dim statement) add this:

  
dim doubleClicked as boolean

// Check for double-click
if ticks - startClick < 15 then
doubleClicked = true
else
startClick = ticks
end if

This will check to see if the current click is within 15 ticks (a quarter second) of the previous tick and if so, decide it's double click.

Now we need to do something with that double click. Look through mouseDown and find the code that scans through every object. It begins with the line for i = n downTo 1. Within that loop, after the yStart = y line, insert this:

  
if doubleClicked then
currentObject.doubleClicked
end if

What this does is pass the double click on to the current object.

But wait! If you run this now, you'll generate an error: our object doesn't know the doubleClicked event. We need to add that!

Open shapeClass and add a new event (Edit menu, "New Event") called doubleClicked. We need a way to call that event as well, so let's add a method by the same name and for its code put in the single line doubleClicked (this triggers the doubleClicked event).

Now open pictClass and find the suddenly available doubleClicked event. Put this code there:

  
dim f as folderItem

// Prompt for picture
f = getOpenFolderItem("image/pict;image/gif;image/jpeg")
if f <> nil then
image = f.openAsPicture
end if

You'll note that for this to work our app must have defined several file types, so do that next. Choose "File types..." from the Edit menu and use the "Add..." button to add the graphic file formats you want to support. I limited mine to PICT, GIF, and JPEG, but feel free to add more if you want (these standard types are available within the "Add" dialog box's popup menu of predefined file types).

That's it! You should be able to run SuperDraw now, and if you place a new picture on the drawing area, it will initially be an empty box. But double-click on it and it will prompt you to choose a graphic file. Once you've selected one, the graphic will be displayed a drawing element within the drawing area!

Best of all, you'll notice that you can move and resize the graphic and it works perfectly! You can add as many picture objects as you want (limited only by available memory, of course). Cool, eh?

That's all we have time for today. Next week we'll make some more additions, including the ability to add text as a drawing element!

If you would like the complete REALbasic project file for this week's tutorial (including resources), you may download it here.

Next Week

More super-easy SuperDraw enhancements!

News

In case you missed it, REAL Software announced that REALbasic 5 for Macintosh is finally shipping! This is the most significant rewrite of REALbasic ever (it includes a new compiler), and promises a bright future for the product. Some of the new features include better Jaguar (Mac OS X) support, new communication protocols (email, http, etc.), and new language features.

You can read more about REALbasic 5 on the REAL Software website. Upgrades start at $29.95.

If you're curious about the new REALbasic 5 features, the upcoming April/May issue of REALbasic Developer magazine features not one, but two in-depth articles on this significant upgrade.

Letters

Today we've got a note from a new REALbasic user who writes:

Hi there,

I enjoy most of your columns, but some things are not well defined for me. I am a newbie to the REALBasic environment. I have decided to start learning programming again and to make myself a devoted apple NUT.

So I chose REALBasic as the starting point, now in doing so I came across your RBU columns, I have completed the first project and I am now reviewing my notes and I have a few questions.

1. the Module.. define this a little better for me and why we would create one for the arrays

2. explain each part of the module that we created in the first project.

3. give me a better understanding of the differents between a NewClass and a NewModule

Thanks

S C Rollins

Thanks for the note, Christopher. Good luck in your learning adventure!

As to your questions, I'll do my best. You don't specify which project you completed: the first one we did on RBU was GenderChanger, so I'll assume that's what you're talking about.

Question 1: A module is simply a collection of code (methods), variables, and constants. The idea is that you group related routines together so that they're all in a single module, then you can reuse that module in other projects simply by dragging it into the project window.

For example, I run my own shareware company, and I want all my programs to have the same look and feel. I also want to reuse as much code as I can. By putting common code into modules and reusuing the modules, I accomplish both goals: the programs use the same code, saving me time, and because they use the same code they also look and function in the same manner.

The other significant reasons to use modules are that modules can have constants (a named "variable" that doesn't change it's value) and that any variables (properties) added to a module are global (that is, they are available to every part of your program).

Question 2: If it's GenderChanger you're talking about, the globalsModule has five items: kPrefName, which is a text constant representing the name of the preference file; openFile and SaveFile, which are methods which load and save the program's preferences; gDialogReturn, a string property which we use to pass data to and from our dialog boxes (and thus needs to be global: we can't use a property of window1 since that would only be available within window1); and gTheFileList(), an array of a our custom class, fileTypeClass. Again, since we needed our data structure to be global, we put it in a module.

Question 3: For a good explanation of classes, read the "OOP University" series I'm currently writing from the beginning. Briefly, a new class is a blueprint (template) for an object type. A new module is simply a collection of code. Modules make it easy to group related code together for reuse.

Classes also allow code reuse because you can create objects based on them and reuse the classes in other projects, but a class is just a definition of an object: it's not an object itself. Without an instance of the object to interact with, a class by itself does nothing.

In other words, if you add a module and a class to your project, give them methods called beepbeep and myBeep respectively, beepbeep will work immediately, but myBeep will only work if you create an object of type class you created, and then tell that object to myBeep.

Make sense? Does that help answer your questions?

Don't be surprised if it takes a little time to get used to the distinctions. I can write explanations until my keyboard gives out, but nothing replaces practical experience. Just try things, experiment, and one day a light bulb will go off as you suddenly understand the difference in a deep way. But that rarely happens when you're just starting out.


About the Column
REALbasic University is a weekly instructional column on programming with REALbasic and is brought to you by REALbasic Developer, the magazine for REALbasic programmers.

Each week we answer select reader questions, and we're always open to ideas for future columns. Send your questions to . (Keep your questions simple and specific. General queries like "How do I write my own web browser?" will be neglected.) Your question won't be answered immediately, but will be answered in a future column. (If you don't want your correspondence published, just be sure to indicate that when you write. Otherwise it's fair game.)

About the Author
is an author, philosopher, graphic designer, photographer, film director, soccer fanatic, and programmer (among other things). He writes for MacOpinion, runs his own software company, Stone Table Software, which sells the revolutionary Z-Write word processor, and is Publisher and Editor of REALbasic Developer. He lives in Northern California with his cats, Mischief and Mayhem, and is rapidly running out of free time.

See the REALbasic University Archives


REALbasic University contents ©2001-2004 by Marc Zeedar and REALbasic Developer. All Rights Reserved.

.

.