2014-03-06 29 views
0

我有一點點的代碼,允許我(窗體)加載圖像,在上面畫一個矩形並保存它。但我想實現一個「撤消」功能。如果我寫一個矩形,我將繪製到位圖中並保存修改的位圖。繪製另一個矩形後,我也保存位圖(在列表中)。然而,我創建了一個按鈕,刪除我保存的最後一個位圖,並將位圖(最新的位圖)設置爲pictureBox中的Image。這有效,但如果我做另一個矩形,然後單擊撤消,沒有任何反應。我很困惑,沒有想法,問題在哪裏。這裏我的代碼:保存位圖列表中的撤消c#第二次失敗

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; 

namespace RecAngle 
{ 
public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     this.DoubleBuffered = true; 
    } 
    Rectangle mRect; 
    Bitmap bm; 
    Image file; 
    Boolean opened = false; 
    SaveFileDialog sfd = new SaveFileDialog(); 
    OpenFileDialog ofd = new OpenFileDialog(); 
    Boolean draw = false; 
    List<Bitmap> bitMapList = new List<Bitmap>(); 
    Boolean undo = false; 

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e) 
    { 
     mRect = new Rectangle(e.X, e.Y, 0, 0); 
     pictureBox1.Invalidate(); 

    } 

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (e.Button == MouseButtons.Left) 
     { 
      mRect = new Rectangle(mRect.Left, mRect.Top, e.X - mRect.Left, e.Y - mRect.Top); 
      pictureBox1.Invalidate(); 
      draw = true; 
     } 
    } 
    private void button1_Click(object sender, EventArgs e) 
    { 
     DialogResult dr = ofd.ShowDialog(); 
     if (dr == DialogResult.OK) 
     { 
      file = Image.FromFile(ofd.FileName); 
      bm = new Bitmap(ofd.FileName); 
      pictureBox1.Image = bm; 
      bitMapList.Add(bm); 
      opened = true; 
     } 
    } 
    private void button2_Click(object sender, EventArgs e) 
    { 
     DialogResult dr = sfd.ShowDialog(); 
     if (opened) 
     { 
       try 
       { 
        bm.Save(sfd.FileName, System.Drawing.Imaging.ImageFormat.Jpeg); 
       } 
       catch (Exception x) 
       { 
        Console.WriteLine(x); 
       } 
     } 
    } 

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e) 
    { 
     try 
     { 
      if (draw) 
      { 
       if (undo) 
       { 
        bm = bitMapList[bitMapList.Count - 1]; 

       } 

        using (Graphics a = Graphics.FromImage(bm)) 
        { 
         Pen pen = new Pen(Color.Red, 2); 
         a.DrawRectangle(pen, mRect); 
         pictureBox1.Invalidate(); 
         bitMapList.Add(new Bitmap(bm)); 
         pictureBox1.Image = bitMapList[bitMapList.Count - 1]; 

        } 
      } 
     } 
     catch (Exception x) 
     { 
      Console.WriteLine(x); 
     } 
    } 

    private void button3_Click(object sender, EventArgs e) 
    { 

     if (bitMapList.Count != 0) 
     { 
      bitMapList.RemoveAt(bitMapList.Count - 1); 
      pictureBox1.Image = bitMapList[bitMapList.Count - 1]; 
      undo = true; 

     } 
    } 

} 
} 

我是否保存錯誤的東西?我認爲這是與「刪除」的東西,但我真的沒有看到錯誤。 謝謝你的幫助

回答

1

你的代碼很混亂。你爲什麼總是打電話Invalidate?你爲什麼使用List其中Stack會更合適?爲什麼在MouseUp方法中執行撤消時分配bm,而不是直接在撤消按鈕中單擊?當你只需要繪製一個矩形時,你爲什麼要保持Graphics實例長時間運行?

最後,爲什麼不將undo設置爲false?

此外,您對位圖一次一個位置很困惑。在撤消方法中,您正在檢查bitMapList.Count != 0,然後刪除最後一個項目。但是,如果bitMapList.Count1,則下一行將導致IndexOutOfRangeException

你必須突破這種困惑。想想你想做什麼,並考慮如何幹淨地做。這是一團糟。你在歷史中想要什麼位圖?你真的需要一個單獨的位圖實例作爲「實際」位圖嗎,即使你剛剛在歷史中放置了相同的位圖?你爲什麼不簡單地把歷史上最新的位圖當作「當前」的呢?然後,你只需要從堆棧中最後一個項目Pop,一切都將毫無問題地乾淨地工作。當然,您必須在位圖的一個新實例上進行繪製,但這不是開銷,因爲new Bitmap(bm);無論如何都完全一樣。唯一會改變的是順序 - 你會創建新的位圖,繪製矩形和Push它到堆棧。就如此容易。代碼應該很容易理解。這是代碼維護的主要目標之一。這就是爲什麼你想要將你的邏輯分解成不同的方法等等,它必須易於閱讀和理解,並且有一小部分責任區域的一些方法的一切都會有所幫助。如果您已經對這段簡短的代碼感到困惑,想象一下如何維護一個比這更復雜的應用程序。

所有這一切說,快速修復你的眼前的問題是改變撤消代碼pictureBox1_MouseUp像這樣:

if (undo) 
{ 
    bm = new Bitmap(bitMapList[bitMapList.Count - 1]); 
    undo = false; 
} 

不過,我強烈建議你重寫代碼代替,並使其更清晰。你甚至不用命名你的控件,這根本無助於可讀性。爲什麼沒有btnUndo而不是button3

+0

謝謝你的詳細幫助!我來自webdynpros ABAP的開發,並以一種特殊的方式。然而,我必須做這個「繪畫」來編輯票據系統的屏幕截圖,並且必須快速開發解決方案,但我絕對是C#的新手,並且必須同時製作其他項目,以便這個簡短的代碼讓我困惑不已,因爲每一個小時我必須從Webdynpro更改爲Javascript,然後更改爲C#等......這個問題已經修復,但我重構了代碼並使用堆棧來完成。真的,非常感謝你的答案,它非常棒! – SirusWhite