调整大小或刷新后保留绘画 [英] Preserve painting after resize or refresh

查看:88
本文介绍了调整大小或刷新后保留绘画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何保存在画框上绘制的画?

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 a FillXXX method.
  • complex shapes can be created with a GraphicsPath, which also has both a DrawXXX methods and a FillXXX 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 the Fill4 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆