#This example creates a scrolling bitmap within another window. This example uses
#a hooked event to paint to the window directly, rather than using a Graphic
#Control.
use strict;
use warnings;
use Win32::GUI qw(WS_CLIPCHILDREN WS_CAPTION WS_SIZEBOX
WS_CHILD WS_EX_CLIENTEDGE
SB_ENDSCROLL SB_THUMBPOSITION);
#create a new class which stops the WM_ERASEBKGND message from erasing the background
#this stops the flicker of the window on resize.
my $WC = new Win32::GUI::Class(
-name => "NoFlicker",
-style => 0,
);
#Create the window and child controls.
my $mainwin = new Win32::GUI::Window (
-pos => [100, 100],
-size => [330, 235],
-name => "Window",
-text => "Bitmap Scroll demo",
-pushstyle => WS_CLIPCHILDREN,
-class => $WC,
#NEM Events for this window
-onResize => \&MainResize,
-onTerminate => sub {return -1;}
);
$mainwin->AddButton (
-name => 'Open',
-pos => [205, 20],
-size => [110, 20],
-text => 'Open Bitmap',
-onClick => \&FindAndOpenBitmap,
);
#Define global variables
my $memdc;
my $bitmap; #will hold the bitmap
#Create a child window with a scroll bars.
my $ChildWin = new Win32::GUI::Window (
-parent => $mainwin,
-name => "ChildWin",
-pos => [0, 0],
-size => [200, 200],
-popstyle => WS_CAPTION | WS_SIZEBOX,
-pushstyle => WS_CHILD | WS_CLIPCHILDREN,
-pushexstyle => WS_EX_CLIENTEDGE,
-class => $WC,
-hscroll => 1,
-vscroll => 1,
-onScroll => \&Scroll,
-onResize => sub {&Resize($bitmap,@_)},
-onPaint => sub {&Paint($memdc,@_)},
);
#Create a memory DC compatible with the child window DC
$memdc=$ChildWin->GetDC->CreateCompatibleDC();
#show both windows and enter the Dialog phase.
$mainwin->Show();
$ChildWin->Show();
Win32::GUI::Dialog();
sub Paint {
#Paint event handler, called when ever the window needs to be redrawn/painted
#get the window that needs to be repainted, in this case it is the child window
my $mdc=shift;
my $win=shift;
my $dc=shift;
#Perform a bit block transfer of the memory DC into the window DC
#The cordinates are based upon the position of the scroll bars
$dc->BitBlt($win->GetClientRect,$mdc,$win->ScrollPos(0),$win->ScrollPos(1));
$dc->Validate();
return 0;
}
sub AdjScroll
{ my $bmap = shift;
my $cwin = shift;
# Set the scroll bar page of each scroll bar.
# This has the effect of increasing/decreasing the size of the bar within
# the scroll bar as the window is resized.
if ( $bmap )
{ my ( $width, $height ) = $bmap->Info();
my ( $cwid, $chei ) = ( $cwin->GetClientRect )[ 2 .. 3 ];
my ( $sx, $sy ) = ( $cwin->ScrollPos( 0 ), $cwin->ScrollPos( 1 ));
while ( 1 )
{ # the ScrollPage calls might trigger a Resize event, so this code might
# run reentrantly. To be sure we don't use old data later and overwrite
# newer data, we reobtain the ClientRect after each operation that might
# change it.
$cwin->ScrollPage( 0, $cwid );
my ( $cwidA, $cheiA ) = ( $cwin->GetClientRect )[ 2 .. 3 ];
$cwin->ScrollPage( 1, $cheiA );
my ( $cwid2, $chei2 ) = ( $cwin->GetClientRect )[ 2 .. 3 ];
last if $cwid == $cwid2 && $chei == $chei2;
( $cwid, $chei ) = ( $cwid2, $chei2 );
}
if ( $sx != $cwin->ScrollPos( 0 ) || $sy != $cwin->ScrollPos( 1 ))
{ $cwin->InvalidateRect( 0 );
}
}
}
sub MainResize {
my $win=shift;
my ($width, $height) = ($win->GetClientRect)[2..3];
$win->Open->Left($width-120);
$win->ChildWin->Resize($width-150,$height);
return 1;
}
sub Resize
{ # Resize handler, get the window
AdjScroll( $_[ 0 ], $_[ 1 ] );
return 1;
}
my ( %state );
sub OpenBitmap
{ my ( $bmap, $mdc, $cwin ) = @_;
if ( $bmap )
{ # if we have a valid bitmap, get the dimensions
my ( $width, $height ) = $bmap->Info();
# select the bitmap into the memory DC so it can be manipulated later.
$mdc->SelectObject( $bmap );
# set the scroll bars to 0, unless same size as before
if ( ! exists $state{ $cwin }
|| $state{ $cwin }[ 0 ] != $width
|| $state{ $cwin }[ 1 ] != $height )
{ $state{ $cwin } = [ $width, $height ];
$cwin->ScrollRange( 0, 0, $width - 1 );
$cwin->ScrollRange( 1, 0, $height - 1 );
$cwin->ScrollPos( 0, 0 );
$cwin->ScrollPos( 1, 0 );
}
AdjScroll( $bmap, $cwin );
# invalidate the child window so windows triggers the paint event
$cwin->InvalidateRect( 1 );
}
return 1;
}
sub FindAndOpenBitmap {
#Function to load in the bitmap
my $file = Win32::GUI::GetOpenFileName(
-owner => $mainwin,
-hidereadonly => 0,
-title => "Open an bitmap file",
-filter => ['Bitmaps' => '*.bmp',
'All files' => '*.*',
],
);
$bitmap=new Win32::GUI::Bitmap($file);
if ($bitmap) {
OpenBitmap($bitmap,$memdc,$ChildWin);
}
return 1;
}
sub Scroll {
# Scroll event handler. We have to explicitly "move" the scroll bars.
# Once they have been moved, we repaint the window.
my( $win, $scrollbar, $operation, $position ) = @_;
if ( $operation != SB_ENDSCROLL && $operation != SB_THUMBPOSITION )
{ $win->Scroll( $scrollbar, $operation, -1, 1 );
$win->InvalidateRect( 0 );
}
return 1;
}