我试图在Visual Studio 2015中创建一个小的绘图应用程序.我的项目属于
Windows窗体应用程序的类别.我有以下问题:
private void Form1_MouseMove(object sender,MouseEventArgs e) { if (a == 1) { if (r == 1 || el == 1) { int x = Math.Min(inX,e.X); int y = Math.Min(inY,e.Y); int width = Math.Max(inX,e.X) - Math.Min(inX,e.X); int height = Math.Max(inY,e.Y) - Math.Min(inY,e.Y); rect = new Rectangle(x,y,width,height); Refresh(); } else if (l == 1) { ep = e.Location; Refresh(); } else { ep = e.Location; g = this.CreateGraphics(); g.DrawLine(p,sp,ep); sp = ep; } } }
我的代码的这一部分创建了一个Rectangular(第2个if),一个线段(第3个if)和一条线.它的工作原理与MS Paint几乎相同;在用户释放鼠标左键(鼠标向上)之前,矩形或线段不会完成.但是当我再次尝试创建另一个矩形时最终制作了一个矩形,表单刷新(Refresh();)并且我丢失了之前绘制的所有矩形或线条.我试过替换Refresh(); with Invalidate(rect);和Update();,但我没有得到我想要的结果.
相反,我明白了:
解决方法
您应该将所有绘图都放到一个单独的位图“缓冲区”中.将形状绘制到该位图,然后在实际需要更新屏幕时,将缓冲区绘制到屏幕上.
此外,无论何时调用Graphics.FromImage,您都需要记住Dispose,否则它会像疯了一样泄漏资源.
令人难以置信的简单例子
using System; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; namespace DrawExample { public partial class Form1 : Form { private Bitmap _canvas; //This is the offscreen drawing buffer private Point _anchor; //The start point for click-drag operations private Rectangle? _ghost; private Brush _ghostBrush; public Form1() { InitializeComponent(); } private void Form1_Load(object sender,EventArgs e) { _ghostBrush = new SolidBrush(Color.FromArgb(200,200,255)); //This creates a slightly blue,transparent brush for the ghost preview ResizeCanvas(); } private void Form1_Resize(object sender,EventArgs e) { ResizeCanvas(); } /// <summary> /// Resizes the offscreen bitmap to match the current size of the window,it preserves what is currently in the bitmap. /// </summary> private void ResizeCanvas() { Bitmap tmp = new Bitmap(this.Width,this.Height,PixelFormat.Format32bppRgb); using (Graphics g = Graphics.FromImage(tmp)) { g.Clear(Color.White); if (_canvas != null) { g.DrawImage(_canvas,0); _canvas.Dispose(); } } _canvas = tmp; } private void Form1_MouseDown(object sender,MouseEventArgs e) { if (e.Button == MouseButtons.Left) { _anchor = new Point(e.X,e.Y); } } private void Form1_MouseMove(object sender,MouseEventArgs e) { if (e.Button == MouseButtons.Left) { _ghost = new Rectangle(_anchor.X,_anchor.Y,e.X - _anchor.X,e.Y - _anchor.Y); this.Invalidate(); } } private void Form1_MouseUp(object sender,MouseEventArgs e) { if (e.Button == MouseButtons.Left) { //Create a Graphics for the offscreen bitmap using (Graphics g = Graphics.FromImage(_canvas)) { Rectangle rect = new Rectangle(_anchor.X,e.Y - _anchor.Y); g.FillRectangle(Brushes.White,rect); g.DrawRectangle(Pens.Black,rect); } _ghost = null; //This queues up a redraw call for the form this.Invalidate(); } } private void Form1_Paint(object sender,PaintEventArgs e) { if (_ghost.HasValue) { using (Bitmap tmp = new Bitmap(_canvas)) { using (Graphics g = Graphics.FromImage(tmp)) { g.FillRectangle(_ghostBrush,_ghost.Value); g.DrawRectangle(Pens.Black,_ghost.Value); e.Graphics.DrawImage(tmp,0); } } } else { e.Graphics.DrawImage(_canvas,0); } } //This stops the flickering protected override void OnPaintBackground(PaintEventArgs e) { //Do nothing } } }