调整大小或刷新后保留绘画 [英] Preserve painting after resize or refresh
问题描述
如何保存在画框上绘制的画?
How can I preserve the painting I drew on a picturebox?
我画一个圆,然后通过ExtFloodFill API填充它。
很好。
I draw a circle, and fill it via the ExtFloodFill API. This works fine.
当我调整表格大小(或最小化)并将其调整回原始大小时,画中的一部分消失了。
When I resize the form (or minimize it) and resize it back to its original size part of the painting is gone.
刷新图片框后,绘画将完全消失
When I refresh the picturebox the painting will be gone completely
我试图在Paint事件中对其进行重新绘制,但这导致了它
I tried to repaint it in the Paint event, but this caused it to be repainted continuously as the painting itself triggered the Paint event as well.
请参见下面的测试项目。
See below for a test project.
- 单击图片框时,将绘制绘画。
- 双击图片框将刷新。
[1个带有1个名为pictureBox1的图片框的表单]
[1 form with 1 picturebox named 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();
}
}
}
如何我保留我调整表单或图片框大小或以其他任何方式刷新时所做的绘画吗?
How can I preserve the painting I make when my form or the picturebox is resized or in any other way to be refreshed?
我将Paint事件更改为以下内容:
I changed my Paint event to the following:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
DrawCircle();
FillGreen();
}
现在,圆圈在调整大小后正在重绘,但FloodFill不是t
And now the circle is being redrawn after a resized, but the FloodFill isn't
(我还为图片框提供了浅蓝色背景以供其他测试)
(I also gave the picturebox a lightblue background for another test)
我将Paint事件更改为使用Graphics g,如下所示:
I changed the Paint event to use the Graphics g as follows:
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的某些行,尤其是当我缓慢调整大小
But when I resize back to the original size some lines of the FloodFill are skipped, especially when I resize slowly
推荐答案
使用GDI +方法绘制代码很简单:
Using GDI+ methods for drawing the code is simply:
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
None of your DllImport
or constants is needed at all.
请注意,我选择使用宽度为2f的Pen来演示使用
子句正确创建和处理 GDI +
(非标准)对象 Pen
Note that I chose to use a Pen with a width of 2f to demonstrate the use of the using
clause to correctly create and dispose of the GDI+
(non-standard) object Pen
这将在需要时绘制时持续存在。要最初绘制它,必须调用 pictureBox1.Invalidate();
一次!
This will persist as it is drawn whenever needed. To draw it initially you must call pictureBox1.Invalidate();
once!
如果要更改坐标您应该将变量 rect
移到类级别,将其设置为新数据,然后在<$ c上调用 Invalidate
$ c> PictureBox !对于 Colors
或 Pen.Width
也是如此:使用类级变量,并在每次更改后触发Paint事件调用 Invalidate()
..
If you want to change the coordinates you should move the variable rect
to class level, set it to new data and the call Invalidate
on the PictureBox
! The same goes for Colors
or the Pen.Width
: use class level variables and after each change trigger the Paint event by calling Invalidate()
..
一旦您了解了,学习<$ c中绘图的最重要部分$ c> GDI + 完成。.
Once you understand that, the most important part of learning drawing in GDI+
is done..
要填充任何图形,您可以使用以下三种选择:
For filling any drawings you have three options:
- 使用
DrawXXX
方法绘制的简单形状都具有FillXXX
方法。 / li>
- 复杂形状可以通过
GraphicsPath
创建,该图形也同时具有DrawXXX
方法和FillXXX
方法。 - 不是由形状而是由绘制的像素创建的区域,必须使用Floodfill方法填充。
GDI +
中没有内置功能,但可以自己编写。可能像Fill4
在这个答案中 ..
- simple shapes draw with
DrawXXX
methods all have aFillXXX
method. - complex shapes can be created with a
GraphicsPath
, which also has both aDrawXXX
methods and aFillXXX
method. - areas not created by shapes but by drawn pixels must be filled with a floodfill method. There is non buit-in in
GDI+
, but can simply write your own. maybe like theFill4
in this answer..
更新:如果感觉更好您可以使用<$ c $ g> gdi32.dll 中的 FloodFill
,但是请更改代码以使用<$ c $ Paint
事件中的c> Graphics 对象:
Update: If you feel better using the FloodFill
from gdi32.dll
you can do so, but please change the code to use the Graphics
object from the Paint
event:
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);
}
为了获得更好的灵活性,您可以使所有参数动态化,但是我
for better flexibility you can probably make the params all dynamic, but I'm not used to that old library..
请注意,呼叫事项的顺序: FillXXX
将覆盖 DrawXXX
绘制的某些像素,因此它必须排在第一位。 FloodFill
但是取决于边界线,在您的情况下,首先绘制圆,因此它必须在后面。.
Note that the order of calls matters: FillXXX
wil cover some of the pixels drawn by DrawXXX
, so it must come first. FloodFill
however depends on the bounding lines, in your case the circle, being drawn first, so it must come after..
这篇关于调整大小或刷新后保留绘画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!