刷新表单后如何保留绘制的形状?
How to keep drawn shapes after the form is refreshed?
我正在尝试在 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;
}
}
}
我的这部分代码创建了一个矩形(2nd if),一个线段(3rd if)和一条线。它的工作原理与 MS Paint 几乎相同;直到用户释放鼠标左键(鼠标松开),矩形或线段才完成。但是当我再次尝试创建另一个矩形时最终制作了一个矩形时,表单会刷新( Refresh(); )并且我丢失了之前绘制的所有矩形或线条。我尝试用 Invalidate(rect); 和 Update(); 替换 Refresh();,但是我没有得到我想要的结果。
相反,我得到了这个:
您应该将所有绘图绘制到您随身携带的单独 Bitmap
"buffer" 中。将形状绘制到该位图,然后在实际需要更新屏幕时,将缓冲区绘制到屏幕。
此外,任何时候调用 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();
}
/// <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, 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
}
}
}
您正在直接在窗体的绘图表面上绘图。那个表面不是持久的。它持续到下一个油漆周期。
相反,您应该:
- 绘制到屏幕外位图。
- 将该位图绘制到例如图片框控件上。或者在
Paint
事件中将其直接绘制到窗体的绘图表面上。
我正在尝试在 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;
}
}
}
我的这部分代码创建了一个矩形(2nd if),一个线段(3rd if)和一条线。它的工作原理与 MS Paint 几乎相同;直到用户释放鼠标左键(鼠标松开),矩形或线段才完成。但是当我再次尝试创建另一个矩形时最终制作了一个矩形时,表单会刷新( Refresh(); )并且我丢失了之前绘制的所有矩形或线条。我尝试用 Invalidate(rect); 和 Update(); 替换 Refresh();,但是我没有得到我想要的结果。
相反,我得到了这个:
您应该将所有绘图绘制到您随身携带的单独 Bitmap
"buffer" 中。将形状绘制到该位图,然后在实际需要更新屏幕时,将缓冲区绘制到屏幕。
此外,任何时候调用 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();
}
/// <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, 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
}
}
}
您正在直接在窗体的绘图表面上绘图。那个表面不是持久的。它持续到下一个油漆周期。
相反,您应该:
- 绘制到屏幕外位图。
- 将该位图绘制到例如图片框控件上。或者在
Paint
事件中将其直接绘制到窗体的绘图表面上。