"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.