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__