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

Reply via email to