将列表中的位图保存为撤消c#第二次失败

时间:2014-03-06 12:36:45

标签: c# bitmap

我有一些代码允许我(窗体)加载图像,在其上绘制一个矩形并保存它。然而,我想要实现一个" Undo"功能。如果我写一个矩形,我会绘制到位图并保存修改后的位图。在我绘制另一个矩形后,我也保存了位图(在List中)。然而,我创建了一个按钮,删除我保存的最后一个位图,并将位图(新的最后一个)设置为pictureBox中的Image。这是有效的,但如果我做另一个矩形并单击撤消,则没有任何反应。我很困惑,也没有想法,问题出在哪里。我的代码在这里:

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;

        }
    }

}
}

我保存错误吗?我认为这是&#34;删除&#34;但我真的没有看到错误。 谢谢你的帮助

1 个答案:

答案 0 :(得分:1)

您的代码非常混乱。你为什么一直打电话给Invalidate?您为什么使用List哪个Stack更合适?在bm方法中进行撤消时,为什么要分配MouseUp,而不是直接在撤消按钮单击?为什么要让Graphics实例保持这么长时间,只需要它来绘制一个矩形?

最后,为什么不将undo设置为假?

此外,您对一次位图的位置非常困惑。在撤消方法中,您需要检查bitMapList.Count != 0,然后删除最后一项。但是,如果bitMapList.Count1,则下一行将导致IndexOutOfRangeException

你必须打破这种混乱。想想你正在尝试做什么,并考虑如何干净利落地做。这是一团糟。你在历史上想要什么位图?你真的需要一个单独的位图实例来实现&#34;实际&#34;位图,即使您只是在历史记录中放置了相同的位图?为什么不简单地将历史中的最新位图视为&#34; current&#34;一?然后你只需要Pop堆栈中的最后一项,一切都没有问题,干净利落。当然,您必须在位图的新实例上进行绘制,但这没有开销,因为new Bitmap(bm);无论如何都会完全相同。唯一可以改变的是订单 - 您创建新的位图,将矩形和Push绘制到堆栈中。就这么简单。

代码应该易于理解。这是代码维护的主要目标之一。这就是为什么你要将你的逻辑分成不同的方法等等,它必须易于阅读和理解,并且在一些方法中使用小范围的责任有所帮助。如果你已经陷入混乱的代码这么简短,想象一下维护一个比这个更复杂的应用程序会有多难。

所有这一切,快速修复您的问题就是更改pictureBox1_MouseUp中的撤消代码,如下所示:

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

但是,我强烈建议您改写代码,并使其更清晰。你甚至没有命名你的控件,根本没有帮助你的可读性。为什么不使用btnUndo代替button3