|
From: Mark D. <mar...@zn...> - 2007-03-21 19:41:42
|
Hi,
wxWidgets DC is drawing not my area, but you are going to have to become
familiar with the way device contexts and, I think, drag and drop work
in wxWidgets.
You'll have a fair bit of reading to do! (You need the wxWidgets help
file(s) )
I did once have occasion to have to do some drawing in MSWin, so I think
the basic concepts are as follows: Perhaps someone else more experienced
can post any errors or even point out complete misunderstanding :-)
For an example, you have your DC and you want to draw two elements on it
- a rectangle and a text string.
You need to retain the details of the elements and draw them all each
time the GUI events request that you do so.
So, every time you get an 'OnPaint' event from your Wx::PaintDC object,
call the drawing code for all your elements. At this stage, the location
on the DC that your elements get drawn to is always the same so you
would always be using
$dc->SetLogicalFunction(wxCOPY);
To select and move the elements you will need to become familiar with
responding to mouse events and probably 'drag and drop.'
Essentially all you really want to do is reset the position of your
element on the DC in response to some mouse actions.
To give user the feeling of 'dragging' the element, when the user
presses the mouse down in your window, you need to get the
xy position of the mouse from the event.
The outside bounds of each of your drawing elements can be described by
a Wx::Rect object.
You can construct this for your 'rectangle' element, simply by recording
the x,y,w,h coordinates you used to create it. The bounding rectangle of
your text can be found by calling $dc->GetTextExtent().
You would probably keep some objects of your own devising that define
each separate drawing element in an array, with each object containing
the necessary primitive information along with the bounding Wx::Rect.
So, when you get an xy position for the mouse, you can iterate through
the array checking each objects Wx::Rect member to see if the xy is
within that rect. ($rect->Contains()).
The ordering of the array is important so that if the elements on screen
overlap, you get the topmost one returned for the xy position.
Once you know which object has been selected by the mouse, you can
respond to a 'drag' operation by simply drawing its bounding rect
outline.
For this you would use $dc->SetLogicalFunction(wxINVERT);
Once that is set, repeating a drawing operation simply reverts the
affected elements to the original colour (so it would work on a
background containing many colours).
So, you would have a 'draw_dragged_object' sub that accepted a bounding
rect as a param and some flag or method of knowing if this is the start
of a dragging operation or the end of the operation.
So
sub draw_dragged_object {
my ($self, $obj, $startend, $dc) = @_;
if($startend !~ /START/) {
$self->_draw_invert_rect(elf->{_prior_rect},$dc )
}
if($startend !~ /END/) {
$self->_draw_invert_rect( $obj->Rect, $dc );
}
$self->{_prior_rect} = $obj->Rect;
}
sub _draw_invert_rect {
my($self, $rect, $dc) = @_;
my $savelogic = $dc->SetLogicalFunction(wxINVERT);
.... Do drawing
$dc->SetLogicalFunction( $savelogic );
}
When the mouse is released, you can save the position of your moved
object and then you can go for the full redraw.
(I think Update or Refresh will do this)?
Then the standard OnPaint response of simply redrawing the objects will
work
The bounding area of any irregular object can be represented by a
Wx::Region (so you can do the selection test.)
The Demo module you need to look at is wxPrinting.pm
Hope this helps get you started at least.
Regards
Mark
|