我试图在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(); ,但我没有得到我想要的结果.
相反,我明白了:
你应该把你所有的绘图都放到一个单独的Bitmap
"缓冲区"中.将形状绘制到该位图,然后在实际需要更新屏幕时,将缓冲区绘制到屏幕上.
此外,无论何时打电话,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, 200, 255)); //This creates a slightly blue, transparent brush for the ghost preview ResizeCanvas(); } private void Form1_Resize(object sender, EventArgs e) { ResizeCanvas(); } ////// Resizes the offscreen bitmap to match the current size of the window, it preserves what is currently in the bitmap. /// 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, 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, _anchor.Y, e.X - _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, 0); } } } else { e.Graphics.DrawImage(_canvas, 0, 0); } } //This stops the flickering protected override void OnPaintBackground(PaintEventArgs e) { //Do nothing } } }