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 065

FontPrinter: Part Four

Last time we got started handling the printing system for our program, and we're almost done. The first thing we want to finish is our print preview feature. This might seem a little tedious to create, but the cool thing is that once we've created this window, we can easily reuse it in other programs simply by dragging in a copy from our hard disk (to export the finished window, drag it from REALbasic to a Finder window).

Building the Print Preview Window

The reason PrintPreview window is reusuable is because it's extremely self-contained. It only needs a couple global properties to function. It needs p, a picture, and gPrintOkay, a boolean, which it uses to tell us if the user clicked Cancel or Okay. By adding those global properties to other programs you create you can easily use this same PrintPreview window in other projects. Even if you just use it to debug and test a program's printing routines and don't use the feature in the final version of your program, it's a useful resource to keep handy. I use it all the time.

In Detail

Note that this version of Print Preview is limited to a single page of printing -- but it isn't especially difficult to expand it to support multiple pages. The main change you'd need to make is to change the global property p to a dynamic array and fill it with all the pages of the printed document. Then you'd need to add support within Print Preview to let the user move through those pictures (either with arrow keys, pushButtons, or both).

As usual, we begin by building the interface. The Print Preview window only has a few elements, so this isn't difficult. We'll start by adding a canvas with these properties:

Since preview, where we draw the printing graphics, has its "lock" properties checked (lockLeft, lockTop, etc.), preview will grow or shrink with printWindow.

Next, we'll add two scrollBars, one vertical, one horizontal. Here are their specs:


Finally, we'll need two pushButtons, called cancelButton and printButton respectively, with the latter set as the default button. The completed window should look something like this:

Now we add some code!

Coding the Print Preview Window

We'll begin coding the events that our window will encounter. There really are only two that concern us, the Open event, where we'll initialize things, and the Resize event, which is needed if the window size is adjusted.

Here's the code for the Open event:

  
dim xDif, yDif, w, h as integer

xDif = me.width - preview.width
yDif = me.height - preview.height

w = p.width + xDif
h = p.height + yDif

if w < screen(0).width - 30 and h < screen(0).height - 50 then
// small enough to fit on screen
me.width = w
me.height = h
else
// too big for screen -- resize to max
me.height = screen(0).height - 50
me.width = (me.height / h) * w
end if

gPrintOkay = false

Basically all we're doing here is adjusting the size of the preview window to fit the current screen. We want it as large as possible, but not too big (we leave room for the menubar and the window's titlebar).

The first two variables, xDif and yDif, are used to tell us the amount of space between the edge of the window and the start of the drawing area (preview, the canvas where we draw the printing graphics). Then we set w and h to the size of the picture plus the extra area we need for the window's interface elements. (The cool benefit of calculating this on the fly is if you moved the elements or added new ones, this would still work.)

The variables w and h tell us the maximum size of window we need (bigger than that would be pointless since the preview area would be bigger than the picture we're drawing). So we next compare w and h with the size of the main screen, screen(0), minus a little for menubar and such. If the picture fits, we're all set: we just make the window the size of w and h.

If the picture doesn't fit (the picture is bigger than the main screen), we set the window to as big as we can. Since most printed pages are vertical, we set the window to be as tall as possible (the screen height minus 50 pixels) and set the width to be proportional (the same percentage of the height smaller).

Our final initalization is to make sure that gPrintOkay is set to false (our default response is that the user cancelled the printing).

Next, we must add code for the Resize event:

  
horzScrollBar.maximum = p.width - preview.width
vertScrollBar.maximum = p.height - preview.height
horzScrollBar.value = 0
vertScrollBar.value = 0

All this does is adjust the scrollBars. Since the width and height of the window (i.e. the preview area) effects the amount (if any) we need to scroll, we must be sure we do this any time the window size changes.

In point of fact, there's no way for the user to adjust the size of the window, so this only can happen when we adjust the size of the window during initialization (the Open event). Therefore we could have added this into the Open routine, but doing it this way is more logical and is the proper way to do it.

In this routine we set the maximum properties of each of our scrollbars to the difference between the picture size and the preview area size. If there is a difference, therefore, that's the amount we need to scroll to see.

The final two lines just sets the "thumb" of the scrollbars to a starting point. (You could set it to center, if you prefer, by calculating the center point: .maximum / 2.)

Speaking of our scrollbars, let's add the code they need. It's very simple. In the ValueChanged event of each scrollBar put this:

  
preview.refresh

That's it: all it does is tell preview to redraw whenever the scrollbars have been moved.

And how does preview draw? Well, that's painfully easy. Go to preview's Paint event and put in this line of code:

  
g.drawPicture p, -horzScrollBar.value, -vertScrollBar.value

All this does is draw the picture, p, at the location specified by the scrollbar values. Note that we make them negative, so if they are postive, the starting drawing point is off the canvas.

In other words, if the horizontal scrollbar position is 100, it becomes -100, meaning that p will be drawn starting at -100 in the horizontal direction, meaning that we won't see the first 100 pixels of p. That, effectively, means that p has been scrolled to the left, revealing more of the right side of p. The bigger the value of the horizontal scrollbar, the more to the left the picture shifts. (The same principle works for the vertical scrollbar, except in the up/down direction.)

Finally, we need to define what happens when the user clicks the buttons. Both have minimal code. CancelButton's Action event looks like this:

  
gPrintOkay = false
self.close

PrintButton's Action event is the opposite:

  
gPrintOkay = true
self.close

In both cases the result of the click is saved in the boolean gPrintOkay global property, and the window is closed.

Our Print Preview window is finished now. If you want to use the Print Preview window in another program, just drag it out of the project window to a Finder window. That will create a window file on disk you can drag into other projects.

You can try to run the program, and it should compile, but if you're wondering why the program isn't working -- nothing happens when you click the Print button -- there's a very simple explanation. While we have a printing method defined, we never call it!

Go to both the filePrint menu handler and printButton's Action event and put in this:

 printIt 

That will call the printing routine and the program should work now.

However, since drawIt is completely empty, nothing will be drawn in the preview window. Just for now, put in this in drawIt:

  
g.drawString "This is a test", 100, 100

That should give you something to look at -- feel free to play around with this, adding other drawing commands to see what they do. Remember, printing is just like drawing to the screen. Try the drawline command, change the drawing color, draw boxes or circles. Anything you draw should also print, though while you're just experimenting you can just use the Print Preview to see it.

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

Next Week

We'll finish FontPrinter by adding the routine to draw the fonts.

Letters

Today we have a couple responses to a letter published a couple columns ago regarding the content of REALbasic University.

First, from George Bate:

Dear Marc

Your correspondent, Mr Gravely, tells us he has been trying for a year and a half to understand the structure of object oriented programs. The ideas, as you say, are hard to grasp. It seems that Mr Gravely is trying to move directly from "sphagetti code" to object oriented code. That, in historical terms, is roughly a jump from 1965 to 1990. It's a tall order. Even having taught the Structured Programming methods of the 70s and 80s for about 15 years, I myself spent a fruitless couple of years trying to master programming with a MacApp-like class library. I finally gave it up and turned with relief to the procedurally oriented Tools Plus. When RealBasic came along I recognised that object oriented programming for Mac applications had been tamed at last.

Now Mr Gravely is a practical man who needs to get results as opposed to a dilettante like me who is just interested in exploring programming methods. He has to ask himself how much more effort it is sensible to invest when, as he says, the available books and tutorials are useless to him. I know from experience with students that there are those who seem constitutionally blind to the concept of program structure. It is possible that Mr Gravely has just such a mental block and, if so, he could be wasting his time.

A colleague of mine used to maintain that a student who copied his program from another student deserved at least a few marks. This was on the grounds that "getting someone else to do it" was, in the practical world, one legitimate way of getting a program written. Some people are compulsive programmers and once interested in a problem are helpless to resist solving it. Perhaps Mr Gravely should consider this possibility. Certainly he needs a re-think as he cannot expect to suddenly see the light.

George Bate

Interesting response, George. I'm not sure I agree that "you can't teach an old dog new tricks." Just because Mr. Gravely may be used to a certain method of programming doesn't mean that OOP can't be learned. The time involved may be more than he can afford, in which case, for practical purposes, he might be better off not bothering, but I believe anyone is capable of learning.

I have decided that this is an important subject and I'm going to do a series of columns on it in the very near future: I hopefully will be able to explain OOP in such a way that people from a traditional programming viewpoint will be able to understand it.

Next, we hear from Scott, who writes:

Marc,

I'm new to RB and am a charter subscriber to your magazine. I'm enjoying the first issue now and will send comments as necessary.

I just finished Ben Gravely's letter and couldn't agree with him more. My interests are astronomy, ham radio, and photography. As a result I'm not too interested in games, and a lot of the other topics we see in beginning programming circles today. I would love to see a short series on algorithm development. It could be quite simple and maybe follow up with something more complex in another issue. I'd also like to see a repository for code snippets that we could download and learn from.

I strongly agree with your move to programs that can be completed in a short time. Six months is a long time for a beginner so let's have more of the shortened programs. I noticed that there are many plugin/shareware/freeware developers using RB. Maybe you could tap some of them to help with small learning programs.

My personal desire is to write a ham radio contest program. This program would increment a serial number every time a new line is created, automatically enter the time and date, show duplicates based on one particular field, and output in a format as required by contest rules. This last sentence has at least four good topics for how to.

Keep up the great work and I'll keep subscribing.

Thanks for your time.

Scott Clausen

Thanks for your letter, Scott. I'm certainly always open to specific suggestions on what I should cover on RBU, and I'll keep your contest program in mind (I'd need more details to create it, of course).

As to the code snippet library, it's interesting you mention that. That was discussed at the REALbasic Users meeting at Macworld in July, and I think it would be perfect for REALbasic Developer to do that. It's definitely something I'd like to see happen. Unfortunately, right now I'm a little busy getting the magazine off the ground, but at some point in the future it's something I'm going to do.

Meanwhile, back to your comments on coding. There are two types of beginning programmers: the "recipe" programmer who can program if given specific instructions, and concept person who gets inspired by an idea and just needs help over a few humps.

The first type does fine as long as there's a tutorial that does exactly what he or she wants to do. The second has the abilty to take concepts from one lesson and apply them to a completely different project. Let me give you an example of the latter in action.

Last year we did a series creating a card game, RBU Pyramid. I received some flack (not much, but a little ;-), about covering a mere game. (I will admit I spent way too much time on it.) My thinking was that there were many parts of that game that could teach other concepts.

For instance, in that game we created a deck of playing cards on the screen. Each card was a canvas object, created programmatically as a control array each time the program ran. Since all the cards were very similar to each other, this made a lot of sense and the program was easier to write and maintain.

Now let's say you were going to do something completely different. Perhaps you're interested in music, and you want to write your own piano keyboard program. Well, you could do it the exact same way. Start with an initial canvas object, duplicate it programmatically (via code) as a control array, and you've got a music keyboard. All you have to do is program the initial object to play a note based on the number object it is so that each key would play a different note. Simple!

But let's say you're not into music. However, you mentioned photography in your letter. Well, what if you wanted to write your own iPhoto-like program? You want the screen to display a series of thumbnail pictures, right? Well, do it the same way: duplicate a series of canvas objects, each containing a reference to a different imported picture.

You see how this works? Many of the basic ideas you use in one program can be useful in another. In fact, much of the most sophisticated software in the world today was based on technology that originated in "mere" games.

I'm just saying this to encourage you to try the tutorials even if you think they won't interest you simply because that's not the kind of thing you are creating. You will learn something, even if you don't realize how important that is at the time.

I wish I had the resources to create a tutorial of every kind of program wanted, and eventually, maybe, there'll be a library of instructional material to cover just about everything, but for now, your best bet is to learn as much as you can from one tutorial and apply it to others.


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.

Email This Article - Comment On This Article

.

Reader Specials

Server Racks Online:
Apple Xserve CompatibleServer Racks and Universal Network Racks
42U KVM Switch Solutions:
High-End Mac and Multi-Platform KVM Matrix switching solutions!
Digital Camera Online:
Great prices on Digital Cameras and accessories!
KVM Switches Online:
Great prices on Mac KVM Switches from the leading manufacturers!
LCD Monitors Online:
Great prices on LCD Monitors from the leading manufacturers!
LCD Projectors Online:
Shop online for LCD Projectors from the leading manufacturers!
USB 2.0 Online:
Great prices on USB 2.0 products from the leading manufacturers

Serious Business Software:
Accounting, Sales, Inventory, CRM, Shipping, Payroll & more!

KVM Switch solutions for MACs:
DAXTEN is a KVM switch, KVM extender and monitor splitter specialist for PC, SUN and MAC applications from name brand manufacturers - offices worldwide.

The "Think Different Store: The iPod Accessories Store - iPod cases, iPod mini, iPod photo, speakers, itrip, inMotion, Soundstage and all other iPod accessories

Earn Cash with the ThinkDifferent Store Affiliates Program

Need A Web Site?
Applelinks Web Hosting Starting at 19.95 a Month

iTunes_RGB_9mm

.

iTunes_RGB_9mm

Cool Mac Gear


iPod 1G-2G
iPod 3G
iPod 4G
iPod Mini
PowerBook-iBook
Keyboard Skins
Garageband