2012-02-12 77 views
2

我正在做一个ms绘画应用程序,绘制conture并填充inside.I编写递归函数,填补conture。它工作正常,但如果conture太大,程序会抛出stackoverflow异常。我怎么解决这个问题??我甚至不能捕获这个异常((在递归中的stackoverflow

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 

[DllImport("user32.dll")] 
static extern IntPtr GetDC(IntPtr hWnd); 
[DllImport("user32.dll")] 
static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); 
[DllImport("gdi32.dll")] 
static extern int GetPixel(IntPtr hDC, int x, int y); 
[DllImport("gdi32.dll")] 
static extern int SetPixel(IntPtr hDC, int x, int y, int color); 

static public Color GetPixel(Control control, int x, int y) 
{ 
    Color color = Color.Empty; 
    if (control != null) 
    { 
     IntPtr hDC = GetDC(control.Handle); 
     int colorRef = GetPixel(hDC, x, y); 
     color = Color.FromArgb(
      (int)(colorRef & 0x000000FF), 
      (int)(colorRef & 0x0000FF00) >> 8, 
      (int)(colorRef & 0x00FF0000) >> 16); 
     ReleaseDC(control.Handle, hDC); 
    } 
    return color; 
} 
static public void SetPixel(Control control, int x, int y, Color color) 
{ 
    if (control != null) 
    { 
     IntPtr hDC = GetDC(control.Handle); 
     int argb = color.ToArgb(); 
     int colorRef = 
      (int)((argb & 0x00FF0000) >> 16) | 
      (int)(argb & 0x0000FF00) | 
      (int)((argb & 0x000000FF) << 16); 
     SetPixel(hDC, x, y, colorRef); 
     ReleaseDC(control.Handle, hDC); 
    } 
} 

     int oldX, oldY; 
     public Form1() 
     { 
      InitializeComponent(); 
     } 



     private void button1_Click(object sender, EventArgs e) 
     { 
      Graphics g = panel1.CreateGraphics(); 
      g.Clear(panel1.BackColor); 
     } 
     bool paint; 

     private void Form1_Load(object sender, EventArgs e) 
     { 

     } 

     private void panel1_MouseDown(object sender, MouseEventArgs e) 
     { 
      oldX = e.X; 
      oldY = e.Y; 
      paint = true; 
     } 

     private void panel1_MouseUp(object sender, MouseEventArgs e) 
     { 
      paint = false; 
     } 

     private void panel1_MouseMove(object sender, MouseEventArgs e) 
     { 
      if (paint) 
      { 
       Graphics g = panel1.CreateGraphics(); 
       Pen p = new Pen(Color.Black); 
       g.DrawLine(p, oldX, oldY, e.X, e.Y); 
       oldX = e.X; 
       oldY = e.Y; 
      } 
     } 

     private void panel1_MouseDoubleClick(object sender, MouseEventArgs e) 
     { 
      fill(e.X, e.Y, Color.Black, Color.Red); 
      Color c = GetPixel(panel1, e.X, e.Y); 
      ClearButton.BackColor = c; 
      label1.Text = e.X + " " + e.Y; 

     } 
     private void fill(int x, int y, Color border, Color c) { 

      Color PointedColor = GetPixel(panel1, x, y); 

      try { 
         if (PointedColor.R != border.R && PointedColor.G != border.G && PointedColor.B != border.B && 
       PointedColor.R != c.R && PointedColor.G != c.G && PointedColor.B != c.B && 
       x >= 0 && x < panel1.Size.Width && y >= 0 && y < panel1.Size.Height) 
      { 
       SetPixel(panel1, x, y, c); 

       fill(x - 1, y, border, c); 
       fill(x + 1, y, border, c); 
       fill(x, y - 1, border, c); 
       fill(x, y + 1, border, c); 

      } 

      } 
      catch(System.StackOverflowException e) 
      { 
       label1.Text = e.Message; 
      } 

     } 
    } 
} 
+0

尝试,只有职位SSCCE的(http://sscce.org) – 2012-06-15 06:03:52

+0

怎么来的,如果只有一个的通道等于边界你不着色?假设边界是#FFF,并且您在形状内找到的点之一是#F00不应该被着色? – 2012-06-15 06:07:58

回答

1

你不允许通过设计搭上StackOverflowException

从.NET Framework 2.0版开始,StackOverflowException对象不能被try-catch块捕获,并且相应的进程默认终止。因此,建议用户编写代码来检测和防止堆栈溢出。例如,如果您的应用程序依赖于递归,请使用计数器或状态条件来终止递归循环。

我相信有更高效的方法来实现这一点。但是,您起步,您可以递归转换成迭代通过reifying调用堆栈作为Stack<T>

private void fill(int xInitial, int yInitial, Color border, Color c) 
{ 
    var remaining = new Stack<Tuple<int, int>>(); 
    remaining.Push(Tuple.Create(xInitial, yInitial)); 

    while (remaining.Any()) 
    { 
     var next = remaining.Pop(); 
     int x = next.Item1; 
     int y = next.Item2; 

     Color PointedColor = GetPixel(panel1, x, y); 

     if (PointedColor.R != border.R && 
      PointedColor.G != border.G && 
      PointedColor.B != border.B && 
      PointedColor.R != c.R && 
      PointedColor.G != c.G && 
      PointedColor.B != c.B && 
      x >= 0 && 
      x < panel1.Size.Width && 
      y >= 0 && 
      y < panel1.Size.Height) 
     { 
      SetPixel(panel1, x, y, c); 
      remaining.Push(Tuple.Create(x - 1, y)); 
      remaining.Push(Tuple.Create(x + 1, y)); 
      remaining.Push(Tuple.Create(x, y - 1)); 
      remaining.Push(Tuple.Create(x, y + 1)); 
     } 
    } 
} 
+0

非常感谢你! – Nate 2012-02-12 16:30:00

2

您应该使用非递归洪水填充算法。

对于能解密看到维基百科article

鲍勃鲍威尔有一些源代码here

+0

我以为我可以创建新的线程,当前堆栈溢出?我不能吗? – Nate 2012-02-12 16:21:51

+2

@Nate,每次创建一个新线程都是非常昂贵的解决方案。采用简单的非递归解决方案肯定是更好的方法。如果您认为通过使用多线程可以获得更好的性能,那么创建额外的线程来解决堆栈问题并非线程的正确使用,即使这样您也应该使用非递归解决方案。 – 2012-02-12 16:27:05