我有一些代码允许我(窗体)加载图像,在其上绘制一个矩形并保存它。然而,我想要实现一个" 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;但我真的没有看到错误。 谢谢你的帮助
答案 0 :(得分:1)
您的代码非常混乱。你为什么一直打电话给Invalidate
?您为什么使用List
哪个Stack
更合适?在bm
方法中进行撤消时,为什么要分配MouseUp
,而不是直接在撤消按钮单击?为什么要让Graphics
实例保持这么长时间,只需要它来绘制一个矩形?
最后,为什么不将undo
设置为假?
此外,您对一次位图的位置非常困惑。在撤消方法中,您需要检查bitMapList.Count != 0
,然后删除最后一项。但是,如果bitMapList.Count
为1
,则下一行将导致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
?