| |||||||||||||||||||||||||||||
|
| |||||||||||||||||||||||||||||
Print This Article REALbasic University: Column 052
Zoomer: Part IMany times I've been asked, "How did you learn all this REALbasic stuff?" My answer is simple: I taught myself. How do you teach yourself programming? You experiment, that's how. You play. You try things. It takes patience, perhaps some research, maybe even some assistance from someone else. But eventually you figure things out and get your program to work. Sometimes these experiments are real programs you want or need. Sometimes they're just learning projects, like my little Shooting Gallery game, which I wrote simply to learn about sprites. Sometimes these projects are rather useless on their own: they don't do anything but help you learn a particular technique. I've got literally hundreds of REALbasic projects like that. That's how I learned. I'd try to get RB to do something, or test a particular feature. So that's your word of warning: what we're going to do today is rather useless. But hopefully you'll learn something.
DrawIntoREALbasic includes an unusual command, drawInto. In earlier versions of REALbasic, it didn't work very well, but most of the bugs seem to be fixed in RB 4. The online help describes the command like this: ![]() When I first noticed this, it intrigued me. Apparently this would draw the contents of a window into a graphics object. What good is that? Well, since a picture object includes a graphics object, you could draw a window into a picture! But what good is that? The first thing I thought of was that once you've got the window as a picture, you could draw it larger: basically zooming into the window! This could be cool, I thought. I could have a floating window that acts as a magnifier to a text field. That way you could keep your text at a reasonable size (10 or 12 points) but be able to read it in the zoomed window. To test this, I wrote Zoomer, a simple experiment. It works pretty good, though I don't know how practical it would be in a real program. But it was good for learning.
Creating ZoomerStart a new blank project. On the default window, drag on an editField, a Slider control, and several staticText objects. Arrange them to look something like this: ![]() Set the properties of editField1 like this: ![]() If you'd like, put some default text into the editField. That will make testing easier, since it's rather pointless to zoom in on an empty editField! zoomSlider should have these characteristics: ![]() Now here's a little tip. StaticTexts are rather useless as controls. After all, they just display some information. But if you add each staticText as a separate control, they clutter up your Code Editor window: ![]() But if we give all the StaticTexts the same name, making them a control array, only a single object is displayed in the Controls list, which is easier on the brain. ![]() So I've named all the statics "Label" and let them be numbered in a control array. (Since we're not doing anything with these staticText objects, the actual numbers are irrelevant, except for the bottom one [which has a default text of "4"] since that one we'll change dynamically as the user drags zoomSlider. That staticText needs these properties (especially note that the array index needs to be 3): ![]() Next, we need to create a window for our zoomed view. Go to the File menu and choose "New Window." Give it the following settings: ![]() Guess what? That's all we need to do for zoomWindow! It doesn't even contain any code! How is that possible? It's possible because everything happens in window1. From there we'll control what's displayed by zoomWindow. The negative side effect of this is that zoomWindow won't redraw properly since it doesn't know how to draw itself. (In a real program you'd want to do this differently, but today we're just experimenting, so this behavior is okay.)
Adding CodeLet's start by adding a couple methods to window1. First, let's create a method called zoomAmount. This method will simply return the current zoom level (set via the zoomSlider control). Go to the Edit menu and choose "New Method" and give it the name zoomAmount and a return type of Double. Then put in this code:
What we are doing here is adjusting the value of zoomSlider. We do this because a slider control cannot move in fractions, only whole integers. By setting zoomSlider's minimum and maximum values to double what we want and then dividing the current value by two, we end up with the range we want but with the ability to zoom to odd levels like 1.5x, 3.5x, etc. The first line sets the staticText display to show to current zoom amount. The second line returns the current zoom amount after calculating it. Simple. But now we need to make the core of the program. This method is the one that draws the zoomed area. For now, let's just put in an empty method. Choose "New Method" from the Edit menu and call it drawZoom, with x as integer, y as integer as the parameters. Leave the method blank for now: we'll finish it next lesson. For now, let's go to the Events list within the window1 Code Editor. Find the event called mouseMove and put in this line: drawZoom(x, y) We've just told the program that every time the mouse is moved within window1, to redraw the zoomed window! But if the user's typing in the editField, they wouldn't be moving the mouse, right? So let's go to the Controls area, expand the editField1 tab, and go to the selChange event. There we're going to put in this:
Eek -- what is all that? Okay, first a quick lesson in coordinates. Coordinates are horizontal (x) and vertical (y) values that represent individual pixels on the screen. But there are different kinds of coordinate systems. There's what's known as the global coordinate system: that's the entire screen, including multiple monitors. Then there are various local coordinate systems: those are the coordinates that represent a single window or object. For example, in the following diagram, the yellow area represents the screen (obviously, a very small screen ;-). ![]() All the x and y values are in global coordinates. But inside the window, the white box, which represents a canvas object, the lx and ly values are local coordinates. In this case, they are local to the window. (Note that this is just the drawing area of the window: the window's title bar is not part of the coordinate area.) However, within the canvas, if you wanted to draw that red circle, you'd draw at local coordinates relative to the canvas: g.drawOval(10,10,30,30) would draw a circle 30 pixels square at ten pixels in and ten pixels over from the upper left edge of the canvas. Note that the canvas itself is on the window and thus canvas position info, like canvas1.left, would be window coordinates. All this just means you have to be careful where you get your coordinate information, and be aware of what type of coordinates you are wanting. You may have to translate from one coordinate system to another. That's what's happening on our situation. Our drawZoom routine, which asks for two coordinates, wants window coordinates. With mouseMove that wasn't a problem: the x and y values passed to the mouseMove event were in window coordinates, so we just passed them right on. But now, within the selChange event, we don't have window coordinates to work with. Instead, we use the system.mouseX and system.mouseY functions, which return global coordinates. So we must translate those to window coordinates. The translation is easy: we just subtract the window's left and top properties from the global x and y coordinates. Look back at that diagram. See how the upper left of the window is 42, 77? Subtract that from a global coordinate, like the 240 that's the width of the window. 240 - 42 is 198. So 198 would be the rightmost pixel of the window (in window coordinates)!
So all we're doing in the selChange event is translating global coordinates to window coordinates and passing those to our drawZoom routine. Whew! That's enough of a lesson today. Next week we'll get into the actual drawing of the zoomed area (which is somewhat complicated). To give you a taste of what to expect, here's what our program will look like in action: ![]() If you would like the complete REALbasic project file for this week's tutorial (including resources), you may download it here.
Next WeekWe finish Zoomer.
REALbasic Developer Magazine UpdateA few weeks ago I officially announced REALbasic Developer, the new printed magazine I'm launching this summer. Quite a few of you chose to become Charter subscribers, and I'm immensely grateful and pleased by your support. Charter subscriptions were higher than I projected, which is wonderful. While the Charter membership offer has expired, we are now offering "Early Bird" subscriptions at a 25% discount. If you're interested in suscribing, you can save money and support the magazine by buying a subscription now. Once we begin publishing in July, subscriptions will be full price. In other news, we're making great strides forward in this mammoth venture. Authors are turning in some great articles, and we're working hard to make this not just the best REALbasic publication, but a great magazine period. I'll post further updates in this column as we progress.
LettersLast week, in response to Dr. Ribnik's quest for an RB class that would display info similar to Mac OS X's Column View, I mentioned I wasn't aware of one. As I suspected, one does exist, as Owen revealed to me:
Thanks, Owen. Anyone who quotes Douglas Adams in his sig can't be all bad! ;-) Next, we've got some puzzles from Sven:
About my sprite lesson not working: I've heard there are problems with sprites in Mac OS X, so that could be it. There may also have been changes to sprites in more recent versions of RB that cause problems with my older code. I'll revisit sprites again one of these days and get those projects working again. To your questions: you first ask about pre-buffering and bringing in pictures. I had a detailed answer to a question along similar lines regarding pictures from an external source recently. It was not for sprites, but the principals are the same (since sprites just need a picture object to define what they look like). Read my answer to Charles, in Lesson 043 and see if that helps get you going. Next, can masks be applied to sprites? You can either set whites to be transparent, or you can apply a mask to a picture and the assign the picture to the sprite. (See the picture.mask in online help for more on masking.) Finally, your question about controlling the screen settings of a user. You can do this via a Declare statement, but you're probably better off using a plug-in. I don't know where one of these is off the top of my head, but I know I've seen them, so they're available. I'd do a Google search and see what you can come up with. (If another reader knows of a plug-in that does this, let me know and I'll post it here next week.) As to your future questions on collision detection and such, you're getting mighty sophisticated, and beyond the scope of REALbasic University. I suggest you subscribe to REALbasic Developer magazine, which will have room to cover more advanced topics than I can do here. RBD has a question-and-answer column which will be perfect for those kinds of issues. 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.
|
. |
| |||||||||||||||||||||||||||