C# 调整大小或刷新后保留绘图

C# 调整大小或刷新后保留绘图,c#,refresh,repaint,flood-fill,C#,Refresh,Repaint,Flood Fill,我怎样才能保存我在画盒上画的画 我画了一个圆圈,并通过ExtFloodFill API填充它。 这个很好用 当我调整窗体大小(或最小化)并将其调整回原始大小时,绘画的一部分就消失了 当我刷新图片盒时,这幅画将完全消失 我试图在Paint事件中重新绘制它,但这导致它不断地重新绘制,因为绘画本身也触发了Paint事件 请参见下面的测试项目 单击picturebox时,将绘制绘画 双击后,将刷新picturebox [1个表格,其中1个picturebox名为pictureBox1] using

我怎样才能保存我在画盒上画的画

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

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

当我刷新图片盒时,这幅画将完全消失

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

请参见下面的测试项目

  • 单击picturebox时,将绘制绘画
  • 双击后,将刷新picturebox
[1个表格,其中1个picturebox名为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();
        }

    }
}
当我的表单或picturebox被调整大小或以任何其他方式刷新时,我如何保存我制作的绘画

[编辑]

我将绘画活动更改为以下内容:

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        DrawCircle();
        FillGreen();
    }
现在,在调整大小后,圆正在重新绘制,但洪水填充没有

(我还为picturebox提供了浅蓝色背景,以便进行另一项测试)

[EDIT2]

我将绘制事件更改为使用图形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);
    }
但当我重新调整到原始大小时,一些泛洪填充线会被跳过,特别是当我缓慢调整大小时


使用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的笔来演示如何使用
using
子句来正确创建和处理
GDI+
(非标准)对象
Pen

这将在需要时绘制时保持不变。要最初绘制它,必须调用
pictureBox1.Invalidate()一次

如果要更改坐标,应将变量
rect
移动到类级别,将其设置为新数据,并在
图片框上调用
Invalidate
!对于
颜色
画笔宽度
:使用类级变量,每次更改后通过调用
Invalidate()
触发绘制事件

一旦你明白了这一点,在
GDI+
中学习绘图最重要的部分就完成了

要填充任何图形,有三个选项:

  • 使用
    DrawXXX
    方法绘制的简单形状都有
    FillXXX
    方法
  • 可以使用
    GraphicsPath
    创建复杂形状,它还具有
    DrawXXX
    方法和
    FillXXX
    方法
  • 必须使用泛光填充方法填充不是由形状创建而是由绘制像素创建的区域。在
    GDI+
    中有非内置的,但可以自己编写。也许像
更新:如果使用
gdi32.dll
中的
泛光填充
感觉更好,可以这样做,但请更改代码以使用
绘制事件中的
图形
对象:

   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);
}
为了获得更好的灵活性,您可能可以使参数都是动态的,但我不习惯使用那个旧库


请注意,调用的顺序很重要:
FillXXX
将覆盖
DrawXXX
绘制的一些像素,因此它必须放在第一位<代码>泛光填充
但是取决于边界线,在您的情况下,首先绘制的是圆,因此它必须位于..

之后。您需要使用绘制参数中的图形或picturebox的图像位图绘制绘制或从绘制事件中绘制。使用从位图创建的图形!其他任何事情都不会像你看到的那样持续下去。我也不明白为什么不使用gdi+绘图,假设您使用的是winforms..我来自VB6,正在尝试将我的应用程序转换为C#。。。我编辑了我的问题,添加了一个我尝试过的新绘制事件,结果是:圆现在正在重新绘制,但是泛光填充没有。您能解释一下如何使用绘制参数中的e.图形吗?与我所做的相比,gdi+绘图如何?通过调用
pictureBox1.Invalidate(),可以轻松避免调整大小
Paint
错误在表单的
调整大小
事件中!谢谢这就成功了:)谢谢你的例子。。。最后,我想在picturebox(或其图形)上绘制一个位图(png文件),并动态填充该位图的某些奇数形状区域。。。fillcolor将取决于我通过tcp连接从接收到的数据。对于我的java小程序,我创建了自己的floodfill方法,该方法运行良好,但在我的VB6程序中,我使用ExtFloodFill API。。。VB6程序比java小程序发展得更远,所以我想把它转换成。。。在VB6中使用ExtFloodFill API非常简单:-)DrawImage方法用于在位图上绘制。对于填充,您可能确实需要一种泛光填充方法,如链接中的方法。顺便说一句:您还应该决定一个基本问题:您可以在PictureBox的曲面或位图图像上绘制。并查看我正确使用gdi32.dll调用的更新答案!