On 04/06/07, Robert May <[EMAIL PROTECTED]> 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__

Reply via email to