472,119 Members | 1,516 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,119 software developers and data experts.

Mouse Dragging and drawing a rectangle


I am drawing a rectangle on a picture that has already been drawn
on the graphics area (a user control). It works something like this:

//in the MouseDown event
m_isDragging = true;
m_oldX = e.X; //save original positions
m_oldY = e.Y;

//in the MouseMove event
if (m_isDragging)
{
m_newX = e.X;
m_newY = e.Y;
int firstX = (m_newX < m_oldX) ? m_newX : m_oldX;
int firstY = (m_newY < m_oldY) ? m_newY : m_oldY;
m_diffX = Math.Abs(m_oldX - m_newX);
m_diffY = Math.Abs(m_oldY - m_newY);
Graphics g = Graphics.FromHwnd(this.Handle);
Rectangle myRectangle =
new Rectangle(firstX, firstY, m_diffX, m_diffY);
g.DrawRectangle(m_myPen, myRectangle);
g.Dispose();
Invalidate(myRectangle);
}

//in the MouseUp event
if (m_isDragging)
{
m_isDragging = false;
//save the position and size of the rectangle (code snipped)

//invalidate the whole usercontrol (which is just the panel
// on which the picture was already painted)
this.Invalidate();

}

This works great when you keep drawing the rectangle bigger.

But if you backtrack while dragging, it leaves the remnants
of the rectangles you have already drawn behind.

How do I handle that?

I've tried saving thd old rectangle and invalidating that
when drawing the new rectangle, like this:

Rectangle m_oldRectangle;
//in the MouseMove event
if (m_isDragging)
{
m_newX = e.X;
m_newY = e.Y;
int firstX = (m_newX < m_oldX) ? m_newX : m_oldX;
int firstY = (m_newY < m_oldY) ? m_newY : m_oldY;
m_diffX = Math.Abs(m_oldX - m_newX);
m_diffY = Math.Abs(m_oldY - m_newY);
Graphics g = Graphics.FromHwnd(this.Handle);
Rectangle myRectangle =
new Rectangle(firstX, firstY, m_diffX, m_diffY);

g.DrawRectangle(m_myPen, myRectangle);
g.Dispose();

//I'd probably want to use whichever rectangle is larger here,
// but I'm just trying this to see what it does.
Invalidate(m_oldRectangle); //instead of myRectangle

//save the old rectangle
m_oldRectangle =
new Rectangle(firstX, firstY, m_diffX, m_diffY);
}

This doesn't work either.

Any other ideas? I'd appreciate any help you can provide.

Thanks in advance,
Robin S.
Aug 24 '07 #1
4 26384
RobinS wrote:
This works great when you keep drawing the rectangle bigger.

But if you backtrack while dragging, it leaves the remnants
of the rectangles you have already drawn behind.

How do I handle that?
The biggest thing wrong that I see with your code is that you are
drawing the rectangle in the MouseMove event handler. You should only
be drawing anything, selection rectangle included, in your Paint event
handler. (replace "XXX event handler" with "OnXXX override method" as
appropriate :) ).

The second version of MouseMove handling you posted appears to me that
it would have the opposite problem, erasing the newly-drawn rectangle
just after you've drawn it. Sticking as closely to the code you've
posted, I think this would be better:

Rectangle m_oldRectangle;
//in the MouseMove event
if (m_isDragging)
{
m_newX = e.X;
m_newY = e.Y;
int firstX = (m_newX < m_oldX) ? m_newX : m_oldX;
int firstY = (m_newY < m_oldY) ? m_newY : m_oldY;
m_diffX = Math.Abs(m_oldX - m_newX);
m_diffY = Math.Abs(m_oldY - m_newY);
Rectangle myRectangle =
new Rectangle(firstX, firstY, m_diffX, m_diffY);

// Invalidate the combined rectangles, to ensure that
// the old rectangle is erased and the new one is drawn
Invalidate(Rectangle.Union(m_oldRectangle, myRectangle));

//save the old rectangle
m_oldRectangle = myRectangle;
}

Then in the Paint event:

e.Graphics.DrawRectangle(m_myPen, m_oldRectangle);

Of course, you probably would want to rename m_oldRectangle so that it
more accurate reflects the "current" nature of the rectangle. :)

Pete
Aug 24 '07 #2

"Peter Duniho" <Np*********@NnOwSlPiAnMk.comwrote in message
news:13*************@corp.supernews.com...
RobinS wrote:
>This works great when you keep drawing the rectangle bigger.

But if you backtrack while dragging, it leaves the remnants
of the rectangles you have already drawn behind.

How do I handle that?

The biggest thing wrong that I see with your code is that you are drawing
the rectangle in the MouseMove event handler. You should only be drawing
anything, selection rectangle included, in your Paint event handler.
(replace "XXX event handler" with "OnXXX override method" as appropriate
:) ).

The second version of MouseMove handling you posted appears to me that it
would have the opposite problem, erasing the newly-drawn rectangle just
after you've drawn it. Sticking as closely to the code you've posted, I
think this would be better:

Rectangle m_oldRectangle;
//in the MouseMove event
if (m_isDragging)
{
m_newX = e.X;
m_newY = e.Y;
int firstX = (m_newX < m_oldX) ? m_newX : m_oldX;
int firstY = (m_newY < m_oldY) ? m_newY : m_oldY;
m_diffX = Math.Abs(m_oldX - m_newX);
m_diffY = Math.Abs(m_oldY - m_newY);
Rectangle myRectangle =
new Rectangle(firstX, firstY, m_diffX, m_diffY);

// Invalidate the combined rectangles, to ensure that
// the old rectangle is erased and the new one is drawn
Invalidate(Rectangle.Union(m_oldRectangle, myRectangle));

//save the old rectangle
m_oldRectangle = myRectangle;
}

Then in the Paint event:

e.Graphics.DrawRectangle(m_myPen, m_oldRectangle);

Of course, you probably would want to rename m_oldRectangle so that it
more accurate reflects the "current" nature of the rectangle. :)

Pete
Thanks for your quick response.

1) The events are actual events. I just didn't want to put the
signature in there because I was re-typing rather than copying
and pasting. I keep trying to drag text over from my desktop
(work) machine to my laptop (personal) machine, but it just won't
go past the edge of the desktop, dang it.

2) Ah, the paint event. So here's the deal. I have a picture,
and I have a bunch of attributes that are applied to the picture.
(This is all part of an image editor.) So the user can add text,
rotate, draw rectangles, crop, etc. All of those attributes are
stored, and when the picture is displayed, there is a routine
called by the Paint event that loads the picture, applies the
attributes, and returns a finished bitmap, which is displayed
by the Paint event. In this way, we can allow the user to go
back and edit the attributes w/o losing any clarity or anything
else about the original picture.

The MouseDown draws the rectangle "temporarily". After the user
lets go of the mouse, the panel is invalidated, invoking the
Paint event, which calls the routine to load the picture
and apply the attributes, one of which is the newly stored
rectangle (storing X, Y, width, and height % in case they
change the size of the image).

All of that is working great. I'm just having trouble
with the interim MouseMove drawing of the rectangle on the
picture.

Despite what you think it might do, the code in my original
post works except when you reverse direction when drawing
the rectangle.

I tried changing Invalidate(myRectangle)
or Invalidate(oldRectangle)
to
Invalidate(Rectangle.Union(m_oldRectangle, m_Rectangle));
but it didn't help.

Any other ideas? Is there a way to invalidate just that area
so the entire thing doesn't repaint? Am I really going to
have to rewrite my Paint event to handle this, and how would
I invoke it from MouseMove? I don't really want to invalidate
the whole panel if I can help it.

Thx,
Robin S.
Aug 24 '07 #3

"RobinS" <Ro****@NoSpam.yah.nonewrote in message
news:zN******************************@comcast.com. ..
>
"Peter Duniho" <Np*********@NnOwSlPiAnMk.comwrote in message
news:13*************@corp.supernews.com...
>RobinS wrote:
>>This works great when you keep drawing the rectangle bigger.

But if you backtrack while dragging, it leaves the remnants
of the rectangles you have already drawn behind.

How do I handle that?

The biggest thing wrong that I see with your code is that you are
drawing the rectangle in the MouseMove event handler. You should only
be drawing anything, selection rectangle included, in your Paint event
handler. (replace "XXX event handler" with "OnXXX override method" as
appropriate :) ).

The second version of MouseMove handling you posted appears to me that
it would have the opposite problem, erasing the newly-drawn rectangle
just after you've drawn it. Sticking as closely to the code you've
posted, I think this would be better:

Rectangle m_oldRectangle;
//in the MouseMove event
if (m_isDragging)
{
m_newX = e.X;
m_newY = e.Y;
int firstX = (m_newX < m_oldX) ? m_newX : m_oldX;
int firstY = (m_newY < m_oldY) ? m_newY : m_oldY;
m_diffX = Math.Abs(m_oldX - m_newX);
m_diffY = Math.Abs(m_oldY - m_newY);
Rectangle myRectangle =
new Rectangle(firstX, firstY, m_diffX, m_diffY);

// Invalidate the combined rectangles, to ensure that
// the old rectangle is erased and the new one is drawn
Invalidate(Rectangle.Union(m_oldRectangle, myRectangle));

//save the old rectangle
m_oldRectangle = myRectangle;
}

Then in the Paint event:

e.Graphics.DrawRectangle(m_myPen, m_oldRectangle);

Of course, you probably would want to rename m_oldRectangle so that it
more accurate reflects the "current" nature of the rectangle. :)

Pete

Thanks for your quick response.

1) The events are actual events. I just didn't want to put the
signature in there because I was re-typing rather than copying
and pasting. I keep trying to drag text over from my desktop
(work) machine to my laptop (personal) machine, but it just won't
go past the edge of the desktop, dang it.

2) Ah, the paint event. So here's the deal. I have a picture,
and I have a bunch of attributes that are applied to the picture.
(This is all part of an image editor.) So the user can add text,
rotate, draw rectangles, crop, etc. All of those attributes are
stored, and when the picture is displayed, there is a routine
called by the Paint event that loads the picture, applies the
attributes, and returns a finished bitmap, which is displayed
by the Paint event. In this way, we can allow the user to go
back and edit the attributes w/o losing any clarity or anything
else about the original picture.

The MouseDown draws the rectangle "temporarily". After the user
lets go of the mouse, the panel is invalidated, invoking the
Paint event, which calls the routine to load the picture
and apply the attributes, one of which is the newly stored
rectangle (storing X, Y, width, and height % in case they
change the size of the image).

All of that is working great. I'm just having trouble
with the interim MouseMove drawing of the rectangle on the
picture.

Despite what you think it might do, the code in my original
post works except when you reverse direction when drawing
the rectangle.

I tried changing Invalidate(myRectangle)
or Invalidate(oldRectangle)
to
Invalidate(Rectangle.Union(m_oldRectangle, m_Rectangle));
but it didn't help.

Any other ideas? Is there a way to invalidate just that area
so the entire thing doesn't repaint? Am I really going to
have to rewrite my Paint event to handle this, and how would
I invoke it from MouseMove? I don't really want to invalidate
the whole panel if I can help it.

Thx,
Robin S.
I tried out what you recommended. If I add it to the paint event,
I'm going to have to repaint the picture under the rectangle
every time, because if I don't, it only shows a black square.

I believe this will make it difficult (if not impossible) for
the user to draw a rectangle around something on the picture. ;-)

I'm afraid if I repaint the entire image as they drag, it will
flicker, and I suspect I did that first and then changed it to
do this. This is a long-standing bug that I have managed to
avoid fixing for a couple of months, but now I've fixed all
the other ones, and have only this one (that I know of) left.

Thanks,
Robin S.
Aug 24 '07 #4
"RobinS" <Ro****@NoSpam.yah.noneha scritto nel messaggio
news:EN******************************@comcast.com. ..

Any other ideas? I'd appreciate any help you can provide.
Try my graphic library:
http://www.codeproject.com/useritems...hic_engine.asp
It already does all what you need and much more.

--
Help The New .Net Site! http://www.devbox4.net
Aug 25 '07 #5

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

reply views Thread by sachin | last post: by
4 posts views Thread by Stuart Norris | last post: by
13 posts views Thread by Lars Netzel | last post: by
3 posts views Thread by Ivonne Riedel | last post: by
2 posts views Thread by qhimq | last post: by
reply views Thread by leo001 | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.