resize或刷新后保留绘画

我怎样才能保存我在绘图箱上画的画?

我绘制一个圆圈,并通过ExtFloodFill API填充它。 这很好用。

当我调整表单大小(或最小化它)并将其调整回原始大小时,绘画的一部分就消失了。

完成调整大小遗失的部分

当我刷新图片框时,绘画将完全消失

我试图在Paint事件中重新绘制它,但这导致它不断重新绘制,因为绘画本身也触发了Paint事件。

请参阅下面的测试项目。

  • 当您点击图片框时,将绘制绘画。
  • 双击时,图片框将刷新。

[1个带有1个名为pictureBox1的图片框]

using System; using System.Drawing; using System.Windows.Forms; using System.Runtime.InteropServices; namespace FloodFill { public partial class Form1 : Form { [DllImport("gdi32.dll")] public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj); [DllImport("gdi32.dll")] public static extern IntPtr CreateSolidBrush(int crColor); [DllImport("gdi32.dll")] public static extern bool ExtFloodFill(IntPtr hdc, int nXStart, int nYStart, int crColor, uint fuFillType); [DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); [DllImport("gdi32.dll")] public static extern int GetPixel(IntPtr hdc, int x, int y); public static uint FLOODFILLSURFACE = 1; public Form1() { InitializeComponent(); } private void pictureBox1_Click(object sender, EventArgs e) { DrawCircle(); FillGreen(); } private void DrawCircle() { Graphics graBox = Graphics.FromHwnd(pictureBox1.Handle); graBox.DrawEllipse(Pens.Red, 10, 10, 100, 100); } private void FillGreen() { Graphics graBox = Graphics.FromHwnd(pictureBox1.Handle); IntPtr ptrHdc = graBox.GetHdc(); IntPtr ptrBrush = CreateSolidBrush(ColorTranslator.ToWin32(Color.Green)); SelectObject(ptrHdc, ptrBrush); ExtFloodFill(ptrHdc, 50, 50, GetPixel(ptrHdc, 50, 50), FLOODFILLSURFACE); DeleteObject(ptrBrush); graBox.ReleaseHdc(ptrHdc); } private void pictureBox1_DoubleClick(object sender, EventArgs e) { pictureBox1.Refresh(); } } } 

当我的表格或图片框resize或以任何其他方式刷新时,我如何保留我所做的绘画?

[编辑]

我将Paint事件更改为以下内容:

  private void pictureBox1_Paint(object sender, PaintEventArgs e) { DrawCircle(); FillGreen(); } 

现在,在resize后重新绘制圆圈,但FloodFill不是

油漆事件

(我还给了图片框一个浅蓝色的背景,用于另一个测试)

[EDIT2]

我更改了Paint事件以使用Graphics g,如下所示:

  private void pictureBox1_Paint(object sender, PaintEventArgs e) { Graphics g = e.Graphics; DrawCircle(g); FillGreen(g); } private void DrawCircle(Graphics g) { g.DrawEllipse(Pens.Red, 10, 10, 100, 100); } private void FillGreen(Graphics g) { IntPtr ptrHdc = g.GetHdc(); IntPtr ptrBrush = CreateSolidBrush(ColorTranslator.ToWin32(Color.Green)); SelectObject(ptrHdc, ptrBrush); ExtFloodFill(ptrHdc, 50, 50, GetPixel(ptrHdc, 50, 50), FLOODFILLSURFACE); DeleteObject(ptrBrush); g.ReleaseHdc(ptrHdc); } 

但是当我重新调整到原始大小时,会跳过FloodFill的某些行,尤其是当我缓慢resize时

图形缺少线条

使用GDI +方法绘制代码很简单:

 private void pictureBox1_Paint(object sender, PaintEventArgs e) { Rectangle rect = new Rectangle(10, 10, 100, 100); e.Graphics.FillEllipse(Brushes.Green, rect); using (Pen pen = new Pen(Color.Red, 2f)) { e.Graphics.DrawEllipse(pen , rect); } } 

根本不需要你的DllImport或常量。

请注意,我选择使用宽度为2f的Pen来演示使用using子句来正确创建和处理GDI+ (非标准)对象Pen

这将在任何需要时随着时间的推移而持续存在。 要最初绘制它,你必须调用pictureBox1.Invalidate(); 一旦!

如果要更改坐标,则应将变量rect移动到类级别,将其设置为新数据并在PictureBox上调用Invalidate ! 对于ColorsPen.Width也是Pen.Width :使用类级变量,每次更改后通过调用Invalidate()触发Paint事件。

一旦你理解了,学习GDI+绘图的最重要的部分就完成了..

要填写任何图纸,您有三种选择:

  • 使用DrawXXX方法绘制的简单形状都具有FillXXX方法。
  • 可以使用GraphicsPath创建复杂形状, GraphicsPath同时具有DrawXXX方法和FillXXX方法。
  • 不是由形状创建的区域,而是由绘制的像素创建的区域必须使用floodfill方法填充。 在GDI+有非buit-in,但可以简单地编写自己的。 也许就像这个答案中的Fill4 ..

更新 :如果您使用gdi32.dllFloodFill感觉更好,可以这样做,但请更改代码以使用Paint事件中的Graphics对象:

  FillGreen(e.Graphics); private void FillGreen(Graphics graBox) { IntPtr ptrHdc = graBox.GetHdc(); IntPtr ptrBrush = CreateSolidBrush(ColorTranslator.ToWin32(Color.Green)); SelectObject(ptrHdc, ptrBrush); ExtFloodFill(ptrHdc, 50, 50, GetPixel(ptrHdc, 50, 50), FLOODFILLSURFACE); DeleteObject(ptrBrush); graBox.ReleaseHdc(ptrHdc); } 

为了更好的灵活性,你可以使params全部动态,但我不习惯那个旧库..

请注意,调用的顺序很 重要FillXXX覆盖DrawXXX绘制的一些像素,因此它必须首先出现。 然而, FloodFill取决于边界线,在你的情况下是圆圈,首先绘制,所以它必须在…之后。