On 30/05/07, George <sir...@ya...> wrote:
> thanks for the response, but where should we insert the invalidate
> function,
> i am lost completely. and many discussions in the forum are complicated and
> for experts only, i have tried many variations with no success. the
> available examples in the forum are calling a sub paint which includes the
> drawing functions inside it ,and it happend the drawing functions are
> speedy, but suppose a function are drawing a fractal and this is a time
> consuming, then we will see that this approach is unpractical, we just want
> to refresh the points of color ,and not to recalculate the code everytime we
> move or hide the window.
Unfortunately drawing using the Win32 API, and understanding all the
gotchas is not trivial. This is not helped by the way that Win32::GUI
exposes the 'Paint' event. I've had it on my list of things to
investigate further for some time, and you've spurred me into looking
at it in a bit more detail. As a result, I'm not sure how to improve
things in a backewards-compatible way. While I think about it some
more, here's the first of 2 examples. This example takes the
traditional approach of doing all the painting in the 'Paint' handler,
determining what to draw, and drawing it, each time the handler is
called.
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.
Hope it is useful.
Regards,
Rob.
#!perl -w
use strict;
use warnings;
use Win32::GUI qw( CW_USEDEFAULT RDW_VALIDATE RDW_NOCHILDREN );
my $do_drawing = 0;
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,
);
$mw->Show();
Win32::GUI::Dialog();
$mw->Hide();
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
if($do_drawing) {
$dc->Rectangle(10,10,100,100);
}
# 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());
$self->GetParent->InvalidateRect(1);
return 1;
}
sub _get_button_text {
return $do_drawing ? 'Hide ...' : 'Draw ...';
}
__END__
|