Daniel Fernandez wrote:
Hi,
Sorry by my last mail. I sent you a wrong script. This it's my modified MDI script with your code. The problem is that the new child window is not visualized but the activate/deactivate events works when the window is created.
Is there are any wrong in my code?
I'll appreciate your comments about this.
Best regards.

I think this is close to what you want (this is the first time I've played with the MDI classes, so there may be better ways). The tricks I used were:
(1) The class needs to use the MDIFrame message loop, so I added
  -widget => "MDIFrame" to the class definition.
(2) MDIFrame sets WM_CLIPCHILDREN by default, but as the MDIClient window fill the MDIFrame window, nothing is ever drawn; so I removed the WM_CLIPCHILDREN from the MDIFrame with
  -popsyle => WM_CLIPCHILDREN
(3) Now that we've removed the WM_CLIPCHILDREN from the MDIFrame, when we draw on the whole of the MDIFrame's client area, we overwrite the MDIChild windows, causing very nasty flickering, so I extended the paint() function to clip the MDIChild windows from the MDIFrame's DC that we are drawing into. (4) Finally the MDIClient does not invalidate the regions exposed by an MDIChild when it moves or is terminated, as it assumes that we want it to paint the background, so I invalidate the regions in explicit handlers for termination and moving (See NewChild(), -onTerminate handler for the window and Hook(WM_MOVE ... ).

Really we want to do exactly what I did with a single window in the MDIClient's WM_PAINT handler. But I can't see any way to get at that with the current Win32::GUI codebase.

Regards,
Rob.

#!perl -w
#
#  MDI sample
#

use strict;
use warnings;

use Win32::GUI;
use Win32::GUI::BitmapInline();

# My child counter for unique name.
my $ChildCount = 0;

my $Window;


# Load our bitmap
#my $bm = Win32::GUI::Bitmap->new("sail.bmp") or die "Creating Bitmap";
my $bm = get_bitmap();
# Store the width and height, as we'll use them a lot
my($bmw, $bmh) = ($bm->Info())[0..1];

# create a class without a background brush: this prevents
# defFrameWindowProc erasing the window background, as we want to
# paint it ourselves to avoid flicker
my $class = Win32::GUI::Class->new(
   -name => 'noflicker',
   -brush => 0,
   -widget => "MDIFrame",   # use the MDIFrame windowproc
);


# Create Main menu.
my $Menu = Win32::GUI::MakeMenu(
   "&File"         => "File",
   "   > &New"     => { -name => "File_New",  -onClick => \&NewChild },
   "   > -"        => 0,
   "   > E&xit"    => { -name => "File_Exit", -onClick => sub { -1; } },
   "&Window"       => "Window",
" > &Next" => { -name => "Next", -onClick => sub { $Window->{Client}->Next; } }, " > &Previous"=> { -name => "Prev", -onClick => sub { $Window->{Client}->Previous; } },
   "   > -"        => 0,
" > &Cascade" => { -name => "Cascade", -onClick => sub { $Window->{Client}->Cascade(); 0; } }, " > Tile &Horizontally" => { -name => "TileH", -onClick => sub { $Window->{Client}->Tile(1); } }, " > Tile &Vertically" => { -name => "TileV", -onClick => sub { $Window->{Client}->Tile(0); } },
   "&Help"         => "Help",
   "   > &About"   => { -name => "About", -onClick => sub { 1; } },
);

# First we create an MDIFrame window.
$Window = new Win32::GUI::MDIFrame (
   -title  => "Win32::GUI MDI Sample",
   -left   => 100,
   -top    => 100,
   -width  => 280,
   -height => 280,
   -name   => "Window",
   -menu   => $Menu,
   -class => $class,
-popstyle => WS_CLIPCHILDREN, # So that the MDIClient's window is not clipped
   -onPaint => \&paint,
   -onTerminate => sub {print "Terminate\n"; -1},   ) or die "Window";

# We add an MDIClient window, This window manage Child Window.
$Window->AddMDIClient(
     -name       => "Client",
-firstchild => 100, # Define Child ID for menu item -windowmenu => $Menu->{Window}->{-handle}, # Define Menu Handle where Add Window Child name
 ) or die "Client";


# Create a memory DC, compatible with our window's
# DC, containing our bitmap.  Do this once, here, to speed
# up the painting routine.  Use a local block, so that $dc
# goes out of scope, and $dc gets released (could call
# $dc->ReleaseDC() instead).
my $memDC;
{
   my $dc = $Window->GetDC();
   $memDC = $dc->CreateCompatibleDC();
   $memDC->SelectObject($bm);
}

# We need a brush to paint the window background
# with, select a grey one.  We don't need to worry
# about freeing stock objects when we're done with them
my $bkBrush = Win32::GUI::GetStockObject(1);


# Show main window and go to event loop
$Window->Show;
Win32::GUI::Dialog();

# We've got some closures on $Window in the
# functions below, which appear to be the cause of
# a 'Can't call Delete .. in global clean up' warning,
# udefining $Window here stops that.
undef $Window;
exit(0);

# Our window painting routine.  To avoid flicker we will
# paint the whole of the window, taking care not to draw any
# pixel more than once.
sub paint
{
   print "Painting...\n";
   my($window, $dc) = @_;

   # I will add StretchBlt to the next release so that we can stretch the
   # image to fit the window, but it's not there right now.
#$dc->StretchBlt(0, 0, ($window->GetClientRect())[2..3], $memDC, 0, 0, $bmw, $bmh);

   # clip each of the MDIChild windows, to avoid us drawing over them
   # and so removing flicker
   # $clip_rgn is the rgion into which we can draw, initialise
   # it to the client window
my $clip_rgn = Win32::GUI::Region->CreateRectRgn($window->GetClientRect());
   while (my ($name, $value) = each %{$window->{Client}}) {
        next unless $name =~ /^Child\d+/;
        my($l, $t, $r, $b) = $value->GetWindowRect();
        # $child_rgn is the MDI child's region in our window's client
        # co-ordinates
        my $child_rgn = Win32::GUI::Region->CreateRectRgn(
                $Window->ScreenToClient($l, $t), $Window->ScreenToClient($r, 
$b));
        # remove $child_rgn from the area we can draw
        $clip_rgn->CombineRgn($clip_rgn, $child_rgn, 4);
   }
   # selct the clip region into our DC.
   $dc->SelectClipRgn($clip_rgn) if $clip_rgn;

   #calculate the image position to center it in the window
   my ($ww, $wh) = ($window->GetClientRect())[2..3];

   my $l = ($ww - $bmw)/2;
   my $t = ($wh - $bmh)/2;
   my $r = $l + $bmw;
   my $b = $t + $bmh;

   # copy the image from the memory DC to the window's DC
   $dc->BitBlt($l, $t, $bmw, $bmh, $memDC, 0, 0);

   # fill the spaces around the image with our background brush.
   # We should probably not draw when it is not necessary (i.e. when
   # the image meets the side(s), but we can get away with not checking,
   # as the DC is always clipped to the window's client rect.
   $dc->FillRect(0,  0,  $ww, $t,  $bkBrush);
   $dc->FillRect(0,  $b, $ww, $wh, $bkBrush);
   $dc->FillRect(0,  $t, $l,  $b,  $bkBrush);
   $dc->FillRect($r, $t, $ww, $b,  $bkBrush);

# We've drawn the background, so inform windows that there is nothing left
   # to draw.
   $dc->Validate();

   # we've processed the message, so return 0.
   return 0;
}


# This function create a new child window.
sub NewChild {
     # Create a child window.
   my $Child = $Window->{Client}->AddMDIChild (
     -name         => "Child".$ChildCount++,
     -onActivate   => sub { print "Activate\n"; },
     -onDeactivate => sub { print "Deactivate\n"; },
-onTerminate => sub { $Window->InvalidateRect(0); print "Terminate\n";},
     -onResize => \&ChildSize,
   ) or die "Child";

   $Child->Hook(WM_MOVE, sub { $Window->InvalidateRect(0); return 1;});

   # Add a text filed into child window.
   $Child->AddTextfield (
       -name => "Edit",
       -multiline => 1,
       -pos => [0,0],
       -size => [100,100],        );

   # Force a resize.
   ChildSize($Child);
}

# This function manage child window resize.
sub ChildSize {
    my $self = shift;
    my ($width, $height) = ($self->GetClientRect())[2..3];
    # TextField take all client aera
    $self->{Edit}->Resize($width, $height) if exists $self->{Edit};
}

sub get_bitmap
{
return Win32::GUI::BitmapInline->new(
[bitmap data removed to save size]
);
}


Reply via email to