2012-02-12 86 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