问题
I have a Rectangle Drawn on top of my Windows Form and I want to resize it using one of the handles provided !

Rectangle areaRect = new Rectangle(100,100, 300, 300);
Bool dragging = false;
Point ptOld = new Point(0, 0);
protected override void OnPaint(PaintEventArgs e)
{
Graphics dcPaint = e.Graphics;
dcPaint.DrawRectangle(rectPen, areaRect);
}
protected override void OnMouseDown(MouseEventArgs e)
{
ptOld = new Point(e.X, e.Y);
dragging = true;
}
protected override void OnMouseMove(MouseEventArgs e)
{
if(dragging = true)
{
Point ptNew = new Point(e.X, e.Y);
Int32 handleSelected = GetSelectedHandle(ptNew);
// Lets say I want to resize this rectangle using Handle 2 now.
if(handleSelected == 2)
{
// I am resizing this rectangle Width
areaRect.X += ptNew.X - ptOld.X;
areaRect.Width -= ptNew .X - ptOld.X;
this.Invalidate();
}
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
dragging = false;
}
It will give me an effect like this. Which is correct,

How ever I want to have a small tweak in this, I would like to change the height of this rectangle as well, When I am moving point 2, my point 7 should remain exactly as it is, Something like this... Similarly when I moving point 4, my point 5 should intact and so on for point 7 and 2 also.

Any idea, how to proceed, because if I change the height, my point 7 location also gets changed ?
回答1:
Drawing on a MouseMove
like this is not going to be very smooth in WinForms.
You basically need a reference to the rectangle before you resize it.
I added the following code to keep track of the rectangle and the 8 draggable points:
private Point GetHandlePoint(int value) {
Point result = Point.Empty;
if (value == 1)
result = new Point(areaRect.Left, areaRect.Top);
else if (value == 2)
result = new Point(areaRect.Left, areaRect.Top + (areaRect.Height / 2));
else if (value == 3)
result = new Point(areaRect.Left, areaRect.Bottom);
else if (value == 4)
result = new Point(areaRect.Left + (areaRect.Width / 2), areaRect.Top);
else if (value == 5)
result = new Point(areaRect.Left + (areaRect.Width / 2), areaRect.Bottom);
else if (value == 6)
result = new Point(areaRect.Right, areaRect.Top);
else if (value == 7)
result = new Point(areaRect.Right, areaRect.Top + (areaRect.Height / 2));
else if (value == 8)
result = new Point(areaRect.Right, areaRect.Bottom);
return result;
}
private Rectangle GetHandleRect(int value) {
Point p = GetHandlePoint(value);
p.Offset(-2, -2);
return new Rectangle(p, new Size(5, 5));
}
Here is how I reworked your form code:
private Rectangle areaRect = new Rectangle(100, 100, 300, 300);
private Rectangle oldRect;
private int dragHandle = 0;
private Point dragPoint;
public Form1() {
InitializeComponent();
this.DoubleBuffered = true;
}
protected override void OnMouseDown(MouseEventArgs e) {
for (int i = 1; i < 9; i++) {
if (GetHandleRect(i).Contains(e.Location)) {
dragHandle = i;
oldRect = areaRect;
dragPoint = GetHandlePoint(i);
}
}
base.OnMouseDown(e);
}
protected override void OnMouseMove(MouseEventArgs e) {
if (dragHandle == 1) {
// to do
} else if (dragHandle == 2) {
int diff = dragPoint.X - e.Location.X;
areaRect = new Rectangle(oldRect.Left - diff, oldRect.Top, oldRect.Width + diff, oldRect.Height);
} else if (dragHandle == 7) {
int diff = dragPoint.X - e.Location.X;
areaRect = new Rectangle(oldRect.Left, oldRect.Top, oldRect.Width - diff, oldRect.Height);
}
if (dragHandle > 0)
this.Invalidate();
base.OnMouseMove(e);
}
protected override void OnMouseUp(MouseEventArgs e) {
dragHandle = 0;
base.OnMouseUp(e);
}
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.DrawRectangle(Pens.Red, areaRect);
for (int i = 1; i < 9; i++) {
e.Graphics.FillRectangle(Brushes.DarkRed, GetHandleRect(i));
}
base.OnPaint(e);
}
The posted code only does Points #2 and #7, but that should give you some logic to work with. I'm sure this code can be improved, it's just a working example.
回答2:
Although this is a little old, this is the first (and only useful, as far as I found) result for this sort of a task.
I've used the above sample to enhance and implement a tested solution. In my case, I also wanted to have the rectangle to be strictly within another rectangle. Specifically, I was drawing it in a PictureBox and I wanted it to never get outside of the picture. This is what the max_width and max_height correspond to.
Note that it is a little funny sometimes - it re-sizes in the other direction when hitting minimum size in certain directions. I decided I like that behavior and that it should be a feature. :)
protected void pictureBox1_OnMouseMove(object sender, MouseEventArgs e)
{
// Where I started - where I stopped
int x_diff = dragPoint.X - e.Location.X;
int y_diff = dragPoint.Y - e.Location.Y;
// Minimum values
int small_offset = 5;
int left = small_offset;
int top = small_offset;
int width = small_offset;
int height = small_offset;
// Max values
int max_width = this.pictureBox1.Image.Width;
int max_height = this.pictureBox1.Image.Height;
if (dragHandle == 1)
{
left = Math.Max(oldRect.Left - x_diff, left);
top = Math.Max(oldRect.Top - y_diff, top);
width = Math.Min(Math.Max(oldRect.Width + x_diff, width), max_width - left - small_offset);
height = Math.Min(Math.Max(oldRect.Height + y_diff, height), max_height - top - small_offset);
}
else if (dragHandle == 2)
{
left = Math.Max(oldRect.Left - x_diff, left);
top = oldRect.Top;
width = Math.Min(Math.Max(oldRect.Width + x_diff, width), max_width - left - small_offset);
height = oldRect.Height;
}
else if (dragHandle == 3)
{
left = Math.Max(oldRect.Left - x_diff, left);
top = oldRect.Top;
width = Math.Min(Math.Max(oldRect.Width + x_diff, width), max_width - left - small_offset);
height = Math.Min(Math.Max(oldRect.Height - y_diff, height), max_height - top - small_offset);
}
else if (dragHandle == 4)
{
left = oldRect.Left;
top = Math.Max(oldRect.Top - y_diff, top);
width = oldRect.Width;
height = Math.Min(Math.Max(oldRect.Height + y_diff, height), max_height - top - small_offset);
}
else if (dragHandle == 5)
{
left = oldRect.Left;
top = oldRect.Top;
width = oldRect.Width;
height = Math.Min(Math.Max(oldRect.Height - y_diff, height), max_height - top - small_offset);
}
else if (dragHandle == 6)
{
left = oldRect.Left;
top = Math.Max(oldRect.Top - y_diff, top);
width = Math.Min(Math.Max(oldRect.Width - x_diff, width), max_width - left - small_offset);
height = Math.Min(Math.Max(oldRect.Height + y_diff, height), max_height - top - small_offset);
}
else if (dragHandle == 7)
{
left = oldRect.Left;
top = oldRect.Top;
width = Math.Min(Math.Max(oldRect.Width - x_diff, width), max_width - left - small_offset);
height = oldRect.Height;
}
else if (dragHandle == 8)
{
left = oldRect.Left;
top = oldRect.Top ;
width = Math.Min(Math.Max(oldRect.Width - x_diff, width), max_width - left - small_offset);
height = Math.Min(Math.Max(oldRect.Height - y_diff, height), max_height - top - small_offset);
}
if (dragHandle > 0)
{
areaRect = new Rectangle(left, top, width, height);
this.Invalidate();
}
}
来源:https://stackoverflow.com/questions/10198381/resizing-a-rectangle-while-dragging-on-windows-form