如何保存我在绘图箱上绘制的画作?
我绘制一个圆圈,并通过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();
}
}
}
当我的表格或图片框调整大小或以其他任何方式刷新时,我如何保留我的画作?
[编辑]
我将Paint事件更改为以下内容:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
DrawCircle();
FillGreen();
}
现在,在调整大小后重新绘制圆圈,但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的某些行,尤其是当我调整缓慢时
答案 0 :(得分:1)
使用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+
(非标准)对象{{1} }
这将在任何需要时随着时间的推移而持续存在。要最初绘制它,您必须拨打Pen
一次!
如果您想更改坐标,则应将变量pictureBox1.Invalidate();
移至类级别,将其设置为新数据,并在rect
上调用Invalidate
! PictureBox
或Colors
也是如此:使用类级变量,每次更改后都会通过调用Pen.Width
来触发Paint事件。
一旦你理解了这一点,Invalidate()
中学习绘画最重要的部分就完成了。
如需填写任何图纸,您有三种选择:
GDI+
方法绘制的简单形状都具有DrawXXX
方法。FillXXX
创建复杂形状,GraphicsPath
同时包含DrawXXX
方法和FillXXX
方法。GDI+
中有非buit-in,但可以自己编写。也许像the Fill4
in this answer .. 更新:如果您使用FloodFill
中的gdi32.dll
感觉更好,可以这样做,但请更改代码以使用Graphics
对象Paint
事件:
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
然而取决于边界线,在你的情况下是圆圈,首先被绘制,所以它必须在...之后。