Re: [MacPerl-Toolbox] Re: [MacPerl-Modules] one last time
[email protected] ((Kevin Reid)) Sat, 5 May 2001 17:32:00 -0400
| Newsgroups | perl.macperl.toolbox |
|---|---|
| Organization | Reid & Hoffman |
| Message-ID | <1esxlq2.n19raz13to81sM%[email protected]> |
"Bill S." <[email protected]> wrote: > I agree with Peter in that I have never seen an annotated example of a > program that creates a window and defines its associated mouse and > keyboard event handling routines. The Window and Pane object methods > implement some fairly intricate protocols which are not easy to puzzle out > by reading the code. The "Power and ease' book does not touch on this > subject. Annotated example? Sure, here's one. #!perl -w use strict; # In any Toolbox-using program, one must use Mac::Events to enable # explicit event handling, or you will have reentrancy problems. use Mac::Events; use Mac::QuickDraw; use Mac::Windows; use Mac::Controls; my $thing = "world"; my @items = qw( continent country state city street house ); # An important distinction is that of the Toolbox window structure # (seen as a GrafPtr object) and the MacPerl window object (seen # as a MacWindow or MacColorWindow object). Toolbox routines # expect the window structure, which you can get from the window # object by calling $the_object->window. # Here we create the window object, which handles a lot of the # details of managing a window for us. my $window = MacColorWindow->new( Rect->new(30, 50, 130, 150), # position and size of window # (left, top, right, bottom) "Example Window", # title of window 1, # is window initially visible? zoomDocProc, # window definition procedure ID 1, # does window have close box? ); # There are two optional additional arguments, known as REFCON # and BEHIND. REFCON is an integer value associated with the window # which you can access and change; you can use it for whatever you # like, but probably won't need it. BEHIND is another window to # create this one behind. # There are two important ways to put something in a window. One is # to draw it yourself, and handle click events for it. This is the # more flexible, but more trouble than creating a control. A # control handles its own drawing and clicks. In this example, we'll # do both. # Let's arrange to draw something in the window. Because a window # may be covered by other windows, it is necessary to provide a way # to redraw the window whenever necessary. This is done by adding a # "redraw" hook. # Here we use an anonymous subroutine, sub {...}; this expression # returns a reference to the subroutine. You could also define a # subroutine elsewhere and get a reference to it by \&sub_name. $window->sethook('redraw', sub { # Okay, if this code is executing, then it's time to draw the # contents of the window. The "current graphics port" has been # set to the window before the redraw hook was called, so we can # now start drawing. # Here we find out how big the window is. GetPort() returns # the current graphics port, and the portRect field is the # bounding rectangle of the port. $window->window would return # the same structure, but this way the redraw routine doesn't # care what variable you're keeping the window object in. my $box = GetPort()->portRect; # Note that coordinates 0, 0 are always the top left corner of # the window, no matter where it is on the screen. MoveTo(5, 20); # move the pen to where we want to draw DrawString("Hello, $thing!"); # draw some text # the pen is now at the end of the text # This draws a rectangle using the current pen color and size. FrameRect( Rect->new( 1, 1, $box->right - 1, $box->bottom - 1 ) ); }); # Because the things we're drawing in the window depend on the size # of the window, we need to make sure they're redrawn when the # window's resized. For this, we use the "invalgrowarea" hook, which # is called both before and after the window is resized. $window->sethook('invalgrowarea', sub { my $box = GetPort()->portRect; # InvalRect() marks an area as needing redrawing. # Redraw the bottom line InvalRect( Rect->new( 1, $box->bottom - 2, $box->right, $box->bottom ) ); # Redraw the right line InvalRect( Rect->new( $box->right - 2, 1, $box->right, $box->bottom ) ); }); # Now we add a control to the window. new_control is a method that # is added to the MacWindow class by Mac::Controls. my $button = $window->new_control( Rect->new(5, 50, 95, 70), # bounding rectangle "Click Me!", # title 1, # visible at creation? 0, 0, 0, # current/min/maximum value, irrelevant to buttons pushButProc, # control definition procedure ID ); # Of course, a button ought to do something. $button->sethook('hit', sub { $thing = shift @items; InvalRect( Rect->new(5, 9, GetPort->portRect->right, 25 ) ); if (not @items) { # if we're out of items, disable the button # The MacControl class ought to have a "control" method (like # MacWindow's "window" method), but it doesn't. Oh well. HiliteControl($button->{control}, kControlInactiveControlPart); } }); # Let's keep the button centered in the window. To do this, we'll # use the "layout" hook, which is called after the window is # resized. $window->sethook('layout', sub { my $box = GetPort()->portRect; MoveControl($button->{control}, $box->right / 2 - 45, 50); }); # Now, we call WaitNextEvent, which handles all event processing # for us. The default behavior of the window object is to dispose # the window when the close box is clicked, so we know when it's # time to quit when the window object no longer has a reference # to the window record. WaitNextEvent() while $window->window; # END blocks are executed when the program exits, even if it # die()d. Here we tell the window object to close the window (if # the object has been created); if you don't do this, you will # have a window hanging around that you can't get rid of except # by quitting MacPerl. END { $window->dispose if $window } __END__ -- Kevin Reid: | Macintosh: "I'm me." | Think different.