none
如何给graphics对象填充颜色? RRS feed

  • 问题

  • 我想写一个函数void FillColor(Graphics g,int x,int y,Color c);功能是在graphics对象g上,以点(x,y)为中心,用颜色c填充一个封闭区域(该区域取决于已经在g上画的内容),相当于实现windows附件中的画图软件中的工具栏上燃料桶图标所表示的功能.
    但不知道该如何实现.
    主要问题:
    既无法获取与g关联的Bitmap对象(以便取得Bitmap对象上某点的颜色),也无法直接取得g上某点已被画上的颜色,总之就是无法获取graphics对象上已经画上的内容,这样任何填充算法都无法使用.
    请问改如何解决这一问题?
    2009年11月17日 14:52

答案

  • 你好!
         可以参考如下代码:
    using System.Runtime.InteropServices;
    
    //insert by Zswang(wjhu111#21cn.com) at 2007-05-22
    
    [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 FLOODFILLBORDER = 0;
    
    public static uint FLOODFILLSURFACE = 1;
    
    
    
    private void button1_Click(object sender, EventArgs e)
    
    {
    
      Graphics vGraphics = Graphics.FromHwnd(Handle);
    
      vGraphics.DrawRectangle(Pens.Blue, new Rectangle(0, 0, 300, 300));
    
      vGraphics.DrawRectangle(Pens.Blue, new Rectangle(50, 70, 300, 300));
    
      IntPtr vDC = vGraphics.GetHdc();
    
      IntPtr vBrush = CreateSolidBrush(ColorTranslator.ToWin32(Color.Red));
    
      IntPtr vPreviouseBrush = SelectObject(vDC, vBrush);
    
      ExtFloodFill(vDC, 10, 10, GetPixel(vDC, 10, 10), FLOODFILLSURFACE);
    
      SelectObject(vDC, vPreviouseBrush);
    
      DeleteObject(vBrush);
    
      vGraphics.ReleaseHdc(vDC);
    
    }
    
    

    周雪峰

    这段代码我试过了,只能解决一半的问题:即只能在picturebox等控件上实现填充,而无法在Bitmap对象上填充,原因可能是只有控件才有设备上下文句柄吧。那么如果我想在Bitmap上填充,该怎么办呢?
    • 已建议为答案 062369 2010年10月29日 2:56
    • 已标记为答案 ygc 2010年10月29日 5:14
    2010年10月27日 2:51

全部回复

  • Graphics 有个私有字段是 backingImage  通过这个字段你可以获取到Image

    你可以通过反射获取这个私有字段的引用
    参考我下面的这段代码


     class Program
       {
          static void Main(string[] args)
          {
     PrivateFieldReflection();

             Console.ReadLine();
          }

          private static void PrivateFieldReflection()
          {
             AClassHasAPrivateField c = new AClassHasAPrivateField();
             Type aClassType = typeof(AClassHasAPrivateField);
             string privateString = "";
             FieldInfo privateFiled = aClassType.GetField("privateString", BindingFlags.NonPublic | BindingFlags.Instance);
             if (privateFiled != null)
             {
                privateString = privateFiled.GetValue(c).ToString();
             }
             Console.WriteLine(privateString);
          }

          public class AClassHasAPrivateField
          {
             private string privateString;

             public AClassHasAPrivateField()
             {
                this.privateString = "I am a private string.";
             }
          }


    Wenn ich dich hab’,gibt es nichts, was unerträglich ist.坚持不懈!My blog~~~
    2009年11月18日 8:08
    版主
  • 你好!
         可以这样获取某一点的颜色:
      [DllImport("user32.dll")]
      static extern IntPtr GetDC(IntPtr hwnd);

      [DllImport("user32.dll")]
      static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);

      [DllImport("gdi32.dll")]
      static extern uint GetPixel(IntPtr hdc,int nXPos,int nYPos);

      // Print out the RGB value of the pixel which is under the mouse cursor.
      // NB: BLUE and RED components will be swapped because GetPixel returns ABGR
      static private void myControl_MouseMove(object sender,System.Windows.Forms.MouseEventArgs e)
      {
        IntPtr hdc = GetDC(IntPtr.Zero);
        uint pixel = GetPixel(hdc, Cursor.Position.X, Cursor.Position.Y);
        ReleaseDC(IntPtr.Zero,hdc);
        Color color = Color.FromArgb((int)pixel);
        Console.WriteLine("Color is {0}",color);
      }
    周雪峰
    2009年11月18日 14:23
    版主
  • 谢谢您的解答.
    我还想问一下,有没有什么.NET Framework内置的方法或者api函数能够直接实现按种子点给某一区域涂色?
    我自己找到了一个api: ExtFloodFill, 但不知如何使用.
    2009年11月26日 8:57
  • 你好!
         可以参考如下代码:
    using System.Runtime.InteropServices;
    //insert by Zswang(wjhu111#21cn.com) at 2007-05-22
    [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 FLOODFILLBORDER = 0;
    public static uint FLOODFILLSURFACE = 1;
    
    private void button1_Click(object sender, EventArgs e)
    {
        Graphics vGraphics = Graphics.FromHwnd(Handle);
        vGraphics.DrawRectangle(Pens.Blue, new Rectangle(0, 0, 300, 300));
        vGraphics.DrawRectangle(Pens.Blue, new Rectangle(50, 70, 300, 300));
        IntPtr vDC = vGraphics.GetHdc();
        IntPtr vBrush = CreateSolidBrush(ColorTranslator.ToWin32(Color.Red));
        IntPtr vPreviouseBrush = SelectObject(vDC, vBrush);
        ExtFloodFill(vDC, 10, 10, GetPixel(vDC, 10, 10), FLOODFILLSURFACE);
        SelectObject(vDC, vPreviouseBrush);
        DeleteObject(vBrush);
        vGraphics.ReleaseHdc(vDC);
    }

    周雪峰
    • 已标记为答案 ygc 2009年11月26日 13:48
    • 取消答案标记 ygc 2010年10月27日 2:42
    2009年11月26日 9:26
    版主
  • 你好!
         可以参考如下代码:
    using System.Runtime.InteropServices;
    
    //insert by Zswang(wjhu111#21cn.com) at 2007-05-22
    
    [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 FLOODFILLBORDER = 0;
    
    public static uint FLOODFILLSURFACE = 1;
    
    
    
    private void button1_Click(object sender, EventArgs e)
    
    {
    
      Graphics vGraphics = Graphics.FromHwnd(Handle);
    
      vGraphics.DrawRectangle(Pens.Blue, new Rectangle(0, 0, 300, 300));
    
      vGraphics.DrawRectangle(Pens.Blue, new Rectangle(50, 70, 300, 300));
    
      IntPtr vDC = vGraphics.GetHdc();
    
      IntPtr vBrush = CreateSolidBrush(ColorTranslator.ToWin32(Color.Red));
    
      IntPtr vPreviouseBrush = SelectObject(vDC, vBrush);
    
      ExtFloodFill(vDC, 10, 10, GetPixel(vDC, 10, 10), FLOODFILLSURFACE);
    
      SelectObject(vDC, vPreviouseBrush);
    
      DeleteObject(vBrush);
    
      vGraphics.ReleaseHdc(vDC);
    
    }
    
    

    周雪峰

    这段代码我试过了,只能解决一半的问题:即只能在picturebox等控件上实现填充,而无法在Bitmap对象上填充,原因可能是只有控件才有设备上下文句柄吧。那么如果我想在Bitmap上填充,该怎么办呢?
    • 已建议为答案 062369 2010年10月29日 2:56
    • 已标记为答案 ygc 2010年10月29日 5:14
    2010年10月27日 2:51