前面一章我们已经知道最基本的C#使用GDI绘制矩形的实现过程,不清楚的看这篇文章C#使用GDI在图像中绘制感兴趣区域ROI,那么今天来进阶学习下如何移动画好的矩形框,如何改变画好的矩形框大小。
实现原理
首先绘制一个矩形框,这个很简单,一句话即可。然后根据绘制的矩形框坐标,绘制8个调整矩形框大小的小点。上图中是绘制了8个小矩形,你也可以创建8个标签来实现。
首先是移动,移动操作是鼠标控制的,因此,我们只需判断鼠标是否进入了矩形框范围,就可以确定是移动图形还是不操作。
改变图像大小比较复杂,主要是对调整大小后的矩形坐标进行计算,从而确定新矩形位置,并同步绘制。
为了方便大家使用,这个项目已经写成了一个类,代码如下:
复制
using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace UserRectDemo { public class UserRect { private PictureBox mPictureBox; public Rectangle rect; public bool allowDeformingDuringMovement=false ; private bool mIsClick=false; private bool mMove=false; private int oldX; private int oldY; private int sizeNodeRect= 5; private Bitmap mBmp=null; private PosSizableRect nodeSelected = PosSizableRect.None; private int angle = 30; private enum PosSizableRect { UpMiddle, LeftMiddle, LeftBottom, LeftUp, RightUp, RightMiddle, RightBottom, BottomMiddle, None }; public UserRect(Rectangle r) { rect = r; mIsClick = false; } public void Draw(Graphics g) { g.DrawRectangle(new Pen(Color.Red),rect); foreach (PosSizableRect pos in Enum.GetValues(typeof(PosSizableRect))) { g.DrawRectangle(new Pen(Color.Red),GetRect(pos)); } } public void SetBitmapFile(string filename) { this.mBmp = new Bitmap(filename); } public void SetBitmap(Bitmap bmp) { this.mBmp = bmp; } public void SetPictureBox(PictureBox p) { this.mPictureBox = p; mPictureBox.MouseDown +=new MouseEventHandler(mPictureBox_MouseDown); mPictureBox.MouseUp += new MouseEventHandler(mPictureBox_MouseUp); mPictureBox.MouseMove += new MouseEventHandler(mPictureBox_MouseMove); mPictureBox.Paint += new PaintEventHandler(mPictureBox_Paint); } private void mPictureBox_Paint(object sender, PaintEventArgs e) { try { Draw(e.Graphics); } catch (Exception exp) { System.Console.WriteLine(exp.Message); } } private void mPictureBox_MouseDown(object sender, MouseEventArgs e) { mIsClick = true; nodeSelected = PosSizableRect.None; nodeSelected = GetNodeSelectable(e.Location); if (rect.Contains(new Point(e.X,e.Y))) { mMove = true; } oldX = e.X; oldY = e.Y; } private void mPictureBox_MouseUp(object sender, MouseEventArgs e) { mIsClick = false; mMove = false; } private void mPictureBox_MouseMove(object sender, MouseEventArgs e) { ChangeCursor(e.Location); if (mIsClick == false) { return; } Rectangle backupRect = rect; switch (nodeSelected) { case PosSizableRect.LeftUp: rect.X += e.X - oldX; rect.Width -= e.X - oldX; rect.Y += e.Y - oldY; rect.Height -= e.Y - oldY; break; case PosSizableRect.LeftMiddle: rect.X += e.X - oldX; rect.Width -= e.X - oldX; break; case PosSizableRect.LeftBottom: rect.Width -= e.X - oldX; rect.X += e.X - oldX; rect.Height += e.Y - oldY; break; case PosSizableRect.BottomMiddle: rect.Height += e.Y - oldY; break; case PosSizableRect.RightUp: rect.Width += e.X - oldX; rect.Y += e.Y - oldY; rect.Height -= e.Y - oldY; break; case PosSizableRect.RightBottom: rect.Width += e.X - oldX; rect.Height += e.Y - oldY; break; case PosSizableRect.RightMiddle: rect.Width += e.X - oldX; break; case PosSizableRect.UpMiddle: rect.Y += e.Y - oldY; rect.Height -= e.Y - oldY; break; default: if (mMove) { rect.X = rect.X + e.X - oldX; rect.Y = rect.Y + e.Y - oldY; } break; } oldX = e.X; oldY = e.Y; if (rect.Width < 5 || rect.Height < 5) { rect = backupRect; } TestIfRectInsideArea(); mPictureBox.Invalidate(); } private void TestIfRectInsideArea() { // Test if rectangle still inside the area. if (rect.X < 0) rect.X = 0; if (rect.Y < 0) rect.Y = 0; if (rect.Width <= 0) rect.Width = 1; if (rect.Height <= 0) rect.Height = 1; if (rect.X + rect.Width > mPictureBox.Width) { rect.Width = mPictureBox.Width - rect.X - 1; // -1 to be still show if (allowDeformingDuringMovement == false) { mIsClick = false; } } if (rect.Y + rect.Height > mPictureBox.Height) { rect.Height = mPictureBox.Height - rect.Y - 1;// -1 to be still show if (allowDeformingDuringMovement == false) { mIsClick = false; } } } private Rectangle CreateRectSizableNode(int x, int y) { return new Rectangle(x - sizeNodeRect / 2, y - sizeNodeRect / 2, sizeNodeRect, sizeNodeRect); } private Rectangle GetRect(PosSizableRect p) { switch (p) { case PosSizableRect.LeftUp: return CreateRectSizableNode(rect.X, rect.Y); case PosSizableRect.LeftMiddle: return CreateRectSizableNode(rect.X, rect.Y + +rect.Height / 2); case PosSizableRect.LeftBottom: return CreateRectSizableNode(rect.X, rect.Y +rect.Height); case PosSizableRect.BottomMiddle: return CreateRectSizableNode(rect.X + rect.Width / 2,rect.Y + rect.Height); case PosSizableRect.RightUp: return CreateRectSizableNode(rect.X + rect.Width,rect.Y ); case PosSizableRect.RightBottom: return CreateRectSizableNode(rect.X + rect.Width,rect.Y + rect.Height); case PosSizableRect.RightMiddle: return CreateRectSizableNode(rect.X + rect.Width, rect.Y + rect.Height / 2); case PosSizableRect.UpMiddle: return CreateRectSizableNode(rect.X + rect.Width/2, rect.Y); default : return new Rectangle(); } } private PosSizableRect GetNodeSelectable(Point p) { foreach (PosSizableRect r in Enum.GetValues(typeof(PosSizableRect))) { if (GetRect(r).Contains(p)) { return r; } } return PosSizableRect.None; } private void ChangeCursor(Point p) { mPictureBox.Cursor = GetCursor(GetNodeSelectable(p)); } /// <summary> /// Get cursor for the handle /// </summary> /// <param name="p"></param> /// <returns></returns> private Cursor GetCursor(PosSizableRect p) { switch (p) { case PosSizableRect.LeftUp: return Cursors.SizeNWSE; case PosSizableRect.LeftMiddle: return Cursors.SizeWE; case PosSizableRect.LeftBottom: return Cursors.SizeNESW; case PosSizableRect.BottomMiddle: return Cursors.SizeNS; case PosSizableRect.RightUp: return Cursors.SizeNESW; case PosSizableRect.RightBottom: return Cursors.SizeNWSE; case PosSizableRect.RightMiddle: return Cursors.SizeWE; case PosSizableRect.UpMiddle: return Cursors.SizeNS; default: return Cursors.Default; } } } }
简单使用
在vs中新建一个类,复制上面的代码,然后在窗体代码中使用如下代码使用:
复制
rect = new UserRect(new Rectangle(10, 10, 100, 100)); rect.SetPictureBox(this.pictureBox1);
注意:由于封装类中写死了画板是pictureBox
控件提供的,所以我们必须使用pictureBox
控件来绘图,向你的项目中拖入一个pictureBox
控件即可使用。
通过修改allowDeformingDuringMovement
属性来实现变形,貌似原作者并没写变形,看不出效果。
最后再吐槽一下,百度资料真的难查,找了一天都没找到,谷歌5分钟不到就找到了…..坑爹!
评论 (3)