On 04/06/07, Robert May <rob...@us...> wrote:
> I'll follow-up with a second example showing how to create a memory DC
> as a backing store that you only need to draw into when things change.
#!perl -w
use strict;
use warnings;
use Win32::GUI qw( CW_USEDEFAULT RDW_VALIDATE RDW_NOCHILDREN COLOR_3DFACE );
my $do_drawing = 0;
# The size of the memory DC we will create to draw into
my ($WIDTH, $HEIGHT) = (200, 200);
my $mw = Win32::GUI::Window->new(
-title => 'Draw on click example',
-left => CW_USEDEFAULT,
-size => [ 400, 300 ],
-onPaint => \&paint,
);
$mw->AddButton(
-text => _get_button_text(),
-pos => [150,150],
-onClick => \&click,
);
# Create a memory DC to act as a buffer into which we'll
# do our drawing; then in the paint handler we'll just bitblt()
# from the memory DC to the screen.
my $memDC;
my $mem_bitmap;
{
my $dc = $mw->GetDC();
$memDC = $dc->CreateCompatibleDC();
$mem_bitmap = $dc->CreateCompatibleBitmap($WIDTH, $HEIGHT);
}
my $memDC_orig_state = $memDC->Save();
$memDC->SelectObject($mem_bitmap);
# Draw into the memory DC
MyDraw($memDC);
$mw->Show();
Win32::GUI::Dialog();
$mw->Hide();
# Tidy up
$memDC->Restore($memDC_orig_state);
Win32::GUI::DC::DeleteObject($mem_bitmap);
Win32::GUI::DC::DeleteDC($memDC);
exit(0);
sub paint {
my ($self, $dc) = @_;
# This Save() and the final Restore() are one way
# to ensure the DC is returned to Win32 in the same
# state as when we got it.
my $saved = $dc->Save();
# Win32::GUI doesnt use BeginPaint()/EndPaint() for the
# DC it passes to its Paint handler. Here we approximate
# what BeginPaint does:
# (1) Calling GetUpdateRect with FLAG=1 causes the background
# of the invalidated area t be cleared (WM_ERASEBKGND sent),
# and invalid non-client area to be repainted (WM_NCPAINT sent).
# (2) Convert the update rect to a region and select it into the
# DC - set up the correct clipping area for us (this is not strictly
# necessary, but will help reduce re-draw flicker
# (3) We validate the DC. We do this using Window->Redraw() rather than
# DC->Validate(), as validating the entire DC validates child windows,
# stopping them being repainted (unless we give the main window
# the WS_CLIPCHILDREN style).
{
# Erase background, repaint non-client area and get update rect
my($l, $t, $r, $b) = $dc->GetUpdateRect(1);
# GetUpdateRect can return undef if there is no update region -
# generally a Paint event only happens if there is a non-empty
# update region, but it can happen if there are 'internal' paint
# events being generated.
if(defined $l) {
my $clip_rgn = Win32::GUI::Region->CreateRectRgn($l, $t, $r, $b);
$dc->SelectClipRgn($clip_rgn);
}
# Validate the whole window
$self->Redraw(RDW_VALIDATE | RDW_NOCHILDREN);
}
# Eventually .... do our drawing
$dc->BitBlt(0,0,$WIDTH,$HEIGHT, $memDC, 0,0);
# An alternative strategy would be to only BitBlt the
# area of the update rect - might reduce flicker, but
# difficult to tell with this simple example
#$dc->BitBlt($l, $t, $r-$l, $b-$t, $memDC, $l, $t);
# Restore the DC to the state it was in before we got it
$dc->Restore();
return 1;
}
sub click {
my ($self) = @_;
$do_drawing = !$do_drawing;
$self->Text(_get_button_text());
MyDraw($memDC);
$self->GetParent->InvalidateRect(1);
return 1;
}
sub _get_button_text {
return $do_drawing ? 'Hide ...' : 'Draw ...';
}
sub MyDraw {
my ($dc) = @_;
# Erase the background - COLOR_3DFACE is the window
# background color
$dc->FillRect( 0,0,200,200,
Win32::GUI::Brush->new( -system => COLOR_3DFACE ) );
# Do our (complex) drawing
if ($do_drawing) {
$dc->Rectangle(10,10,100,100);
}
return;
}
__END__
|