| |||||||||||||||||||||||||||||
|
| |||||||||||||||||||||||||||||
Print This Article REALbasic University: Column 066
FontPrinter: Part FiveIn our previous lesson we added a Print Preview window feature. But right now FontPrinter doesn't do what it was designed to do: print out lists of fonts. Today we'll finish the program by finalizing the drawing routine.
Drawing the PrintingThe core of FontPrinter is the drawIt routine, which does the actual drawing. This is a somewhat complex routine, so we'll step through it carefully. First, let's consider what we want to do. Our goal is to display all the "typeable" characters of a font. So that means we need to show each character on the keyboard the way it normally appears (no modifiers pressed), show it as it looks with the Shift key down, with the Option key down, and with the Shift and Option keys keld down. That's four different versions of the same thing, so a sensible way to display that would be four columns of letters. Now since the user might be printing a symbol font (a font with pictures instead of letters), we have to make sure to print the "normal" (no modifier) character in a normal font. I chose Helvetica, but you could use any standard font (ideally, choose one that's installed on all Macs). The solution I came up with is to print, in small type, enclosed in parenthesis, the normal character. Then to the right of that, in large type, the letter in the user's font. Here I ran into another problem. To get all the letters to fit on a single page, I can't double-space the lines of type: they need to be close together. But then the larger letters overlap each other. I quickly came up with a simple solution: stagger the larger letters. By not printing them directly on top of each other, there's room for each letter but the line spacing of the entire grid can still be tight enough to fit all the letters on a single page.
A Unicode ProblemNow in the original version of this program, written back in Mac OS 9 days, I didn't have to worry about text conversion. If I specified a particular ASCII number that's what I got (i.e. chr(65) would be a capital "A" in Helvetica, or a six-pointed star in Zapf Dingbats). But Mac OS X is more sophisticated: it's actually intelligent about font characters and if I specify I want a capital "A" but in the Zapf Dingbats font, it will give me a capital A in a default font that has a capital A, but it won't be in Zapf Dingbats. That's because Mac OS X knows that Zapf Dingbats doesn't have a capital A and Mac OS X assumes that's what I want since ASCII 65 is supposed to be a capital A. The Mac OS X solution is to use Unicode and specify the actual character I'm wanting.
Our problem is that Mac OS X's Unicode support will prevent us from displaying the symbol characters in unusual fonts. What we want is a return to the old way: a way to display fonts in their actual font and not be overridden by Mac OS X's automatic font replacement system. In other words, if we don't do something, when the user picks Zapf Dingbats as the font, our program won't display the six-pointed star for ASCII 65: it'll display a captial A in some replacement font. That's not what we want. (Sharp readers might remember we ran into this problem while creating RBU Pyramid. We originally used the Symbol font to draw the symbols for the various playing card suits, but later had to change that routine to use imported graphics because Mac OS X overrode our Symbol request thinking we wanted normal letters.) Fortunately, REALbasic gives us the tools to solve this problem. REALbasic is aware of Unicode (and other encodings) and can convert from one to another. The basic principle is this: you tell REALbasic what you're converting from (the input encoding) and what you want that converted to (the output encoding) and then tell it to convert the text. In principle, that's simple enough. However, REALbasic's object-oriented approach to things actually makes this a bit confusing. Remember, in object-oriented programming, an object knows how to manipulate itself. That's the whole idea. So instead of a procedural approach like this:
we must instead do a couple steps, like this:
That's not that hard, once you see it like this. However, you also have to get your inputEncoding and outputEncoding objects. You can do that with the getFontTextEncoding command like this:
What this does is tell REALbasic that both our input and output fonts are Zapf Dingbats, meaning that that's what we want it to use (no automatic substitution). Once we convert the text (the previous bit of code), REALbasic makes sure that our symbols are the Zapf Dingbat ones. The result of all this is we have multiple objects: text encoding objects (which contain the info about the specific encoding type) and a text converter object (which actually does the conversion). It's not that bad, but just trying to figure that out from the built-in documentation can be tough (not to mention learning about all the encoding types, something I avoid in this situation by using the GetFontTextEncoding function). There are also differences in how this works between the various versions of REALbasic. The above code is how it works for REALbasic 4.5, but REALbasic 4 seems to act a little differently, and earlier versions of REALbasic supported Unicode incompletely. Your best bet is to use the latest version of REALbasic and test your code thoroughly to make sure what you think is happening is really happening.
The DrawIt CodeBut enough of all this lecturing. Let's take a look at the code for drawIt and see if you understand how it works:
As usual, we begin by defining the variables (properties) our method will use. You'll note there are some unusual objects here: tcon as textConverter and t as textEncoding. We'll need those to convert our text to make sure we output the proper symbols. Next, you'll note that we define a local constant. This is the name of the "normal" (non-symbol) font we'll use for displaying the characters to type. I chose Helvetica, but you could use Arial, Monaco, System, or whatever. Right at the beginning we set our textEncoding object, t, to the proper encoding by passing the getFontTextEncoding function the name of the font we're using (which happens to be the text of fontPopup). Then we create our textConverter object, tcon. Note that we haven't converted anything yet: all we're doing here is preparation. Now we're ready to draw. We begin by drawing the name of the font we'll be drawing in large letters at the top of the page. We draw it in our default font, not the user font, so we can be sure it will be readable. Then we set up a loop. We'll have four columns of info, so we need a 4x loop. For each step through the loop we establish different text for the column's label. We draw that label at the top of each column. Now, a couple lessons ago, we created a routine to fill the array gTheString with text from a TEXT resource in FontPrinter's resource fork. That method is called init and it's in globalsModule, if you'd like to reexamine it. Each index of gTheString contains a different set of characters obtained by typing with or without various modifiers pressed (Shift, Option, etc.). So for each step through the i loop, we use a different index of gTheString. Because we're going to be drawing letter-by-letter, we need to step through each character in gTheString. So we do that with another loop, j. For each letter, we first draw (using defaultFont) the standard letter enclosed in parenthesis. Note that after every letter we advance the value of x (x and y are basically our cursor point, the coordinates of where we are drawing, with x being the horizontal direction and y the vertical). Then we have an interesting line of code: if j / 2 = j \ 2 then. What does that mean? Well, the / operator divides, of course. So does the \ operator: but it does an integer divide, meaning that it always returns a whole number, never a fraction. By comparing the two divide-by-two operations, we can easily tell if j is an odd or even number. If j is an odd number, like 5, the two operations won't equal (since 5 / 2 is 2.5 and 5 \ 2 is 2). So the code after this if statement will only be executed if j is an even number! And what does that code do? We'll, it draws a horizontal gray box. The box is as tall as a line of text and as wide as one column. That's it. The effect of this will be to put a horizontal light gray line across every other line of text, making the grid of letters much easier to read (see the sample image at the end of this article). Next, we get ready to draw the large character in the user's font choice. We set our font and font size, and then we try to convert our text to the proper encoding. I say try, because I found that in REALbasic 4 tcon would always equal nil (the tcon object failed to be created by our getTextConvert command), while in REALbasic 4.5, it would be a valid object. Obviously there's some difference in how the text encoding stuff works between 4 and 4.5. But in REALbasic 4 we don't experience the font substitution problems we do in 4.5, so all we have to do is only convert the text if tcon is a valid object. In RB 4 (or any time the tcon object isn't there), the program will just use the text as it is without any conversion. Finally, we have our code that actually draws the character in the large font. Note that we have staggered it: on even lines the letter appears 36 points to the right. If it's bigger than the height of our line, that's okay, since there's plenty of room above and below it. Our last line is to add 114 (one column width) to x. You'll see that at the start of the i loop, y is reset to 48, the top margin of the column. That moves our cursor over to the right one column, and back at the top of the page ready to draw the next column. On subsequent trips through the loop, the entire process is repeated, but each time a different set of letters is used (each of the four gTheString elements). And that's it! FontPrinter is now done and should work for you. You should end up with a preview window that looks something like this (using Zapf Dingbats): ![]() If you hit print, the same page should be produced by your printer. Enjoy, and I hope this was a helpful tutorial. Feel free to expand on it. You could make Print Preview support multiple pages, and you could even add a feature where FontPrinter prints out a page for every installed font. Let me know how you get along improving the program. If you would like the complete REALbasic project file for this week's tutorial (including resources), you may download it here.
Next WeekA mini-review of REALbasic 4.5.
LettersOur letter this week is from Paul, who has a quick tip about a potential problem in FontPrinter under Mac OS X 10.2:
Thanks for the info, Paul! I, sadly, do not yet have my copy of Jaguar. I pre-ordered it but it has yet to arrive. I'm not sure why Jaguar wouldn't like 8-bit depth pictures, but that's good to know. I only chose 8-bit to make it use less memory, but under Mac OS X that isn't an issue anyway. The line to change, if you're wondering, is in the printIt method. The old line:
The new line:
That should work fine, now. 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 See the REALbasic University Archives
REALbasic University contents ©2001-2004 by Marc Zeedar and REALbasic Developer. All Rights Reserved.
| |||||||||||||||||||||||||||||