从数组中检索正确的 PictureBox 图像
Retrieving Correct PictureBox Images From Array
在我的表单中,我试图让我的撤消按钮起作用。我使用 pictureBox1
绘制我的正方形,并使用 pictureBox2
显示绘制的历史记录。
功能
在 Picturebox mouseup 事件中,我将所有绘制的对象添加到我的列表数组中,因此稍后当我单击撤消按钮时,它应该会显示我绘制的矩形的历史记录。所以如果我在 picturebox1 上有 4 个矩形并且我单击撤消 picturebox2 应该显示 3 个矩形。如果我再次单击撤消按钮,picturebox2 应该会显示 2 个矩形。
问题是当我点击撤消按钮时它没有像我希望的那样工作。它一直向我显示我绘制的所有矩形,但不显示我绘制对象的历史记录。
代码
Point startArea; // mouse-down position
Point currentArea; // current mouse position
bool drawingBox; // busy drawing
List<Rectangle> rectangleList = new List<Rectangle>(); //previous rectangles
List<Image> ImageCollection = new List<Image>();
int ImageHistory;
private void Test_Load(object sender, EventArgs e)
{
pictureBox1.Image = Properties.Resources.background;
}
private Rectangle getRectangle()
{
return new Rectangle(
Math.Min(startArea.X, currentArea.X),
Math.Min(startArea.Y, currentArea.Y),
Math.Abs(startArea.X - currentArea.X),
Math.Abs(startArea.Y - currentArea.Y));
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
currentArea = startArea = e.Location;
drawingBox = true;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
currentArea = e.Location;
if (drawingBox)
{
pictureBox1.Invalidate();
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if(drawingBox)
{
drawingBox = false;
var rc = getRectangle();
if(rc.Width > 0 && rc.Height > 0)
{
rectangleList.Add(rc);
pictureBox1.Invalidate();
}
}
ImageHistory++;
ImageCollection.Add(pictureBox1.Image);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (rectangleList.Count > 0)
{
using (var g = Graphics.FromImage(pictureBox1.Image))
{
g.DrawRectangles(Pens.Black, rectangleList.ToArray());
pictureBox1.Invalidate();
}
}
if(drawingBox)
{
e.Graphics.DrawRectangle(Pens.Red, getRectangle());
pictureBox1.Invalidate();
}
}
private void button1_Click(object sender, EventArgs e)
{
ImageHistory--;
pictureBox2.Image = ImageCollection[ImageHistory];
}
}
更改以下行
ImageCollection.Add(pictureBox1.Image);
到
ImageCollection.Add((Image)pictureBox1.Image.Clone())
虽然接受的答案可以解决问题,但在尝试解决问题时应考虑一些重要注意事项:
你不需要使用List<Image>
作为撤销缓冲区,它会占用大量内存。目前,由于您不处理未使用的图像,您的应用程序很快就会发生内存泄漏。
用List<Rectangle>
作为undo buffer就够了。它明显使用更少的内存。你不需要跟踪任何要处理的东西,它不需要处理。
为了实现这个想法,最好将 List<Rectangle>
保留为撤消缓冲区,每次绘制矩形时,将其添加到缓冲区中,每次撤消时,只需删除最后一个矩形并使绘图表面无效。这样你就不需要改变图片框的图像,你应该只在绘图表面上绘制矩形而不是在图像上绘制它们。最后,如果您需要导出包含所有矩形的图像,只需将它们绘制在位图上并导出图像即可。
可以将Undo
方法和Redo
方法和CanUndo
属性封装在DrawingSurface
控件中使用那些方法在您的应用程序中,而不是直接将这些逻辑放在按钮后面。
例子
您可以查看有关 的示例。
在我的表单中,我试图让我的撤消按钮起作用。我使用 pictureBox1
绘制我的正方形,并使用 pictureBox2
显示绘制的历史记录。
功能
在 Picturebox mouseup 事件中,我将所有绘制的对象添加到我的列表数组中,因此稍后当我单击撤消按钮时,它应该会显示我绘制的矩形的历史记录。所以如果我在 picturebox1 上有 4 个矩形并且我单击撤消 picturebox2 应该显示 3 个矩形。如果我再次单击撤消按钮,picturebox2 应该会显示 2 个矩形。
问题是当我点击撤消按钮时它没有像我希望的那样工作。它一直向我显示我绘制的所有矩形,但不显示我绘制对象的历史记录。
代码
Point startArea; // mouse-down position
Point currentArea; // current mouse position
bool drawingBox; // busy drawing
List<Rectangle> rectangleList = new List<Rectangle>(); //previous rectangles
List<Image> ImageCollection = new List<Image>();
int ImageHistory;
private void Test_Load(object sender, EventArgs e)
{
pictureBox1.Image = Properties.Resources.background;
}
private Rectangle getRectangle()
{
return new Rectangle(
Math.Min(startArea.X, currentArea.X),
Math.Min(startArea.Y, currentArea.Y),
Math.Abs(startArea.X - currentArea.X),
Math.Abs(startArea.Y - currentArea.Y));
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
currentArea = startArea = e.Location;
drawingBox = true;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
currentArea = e.Location;
if (drawingBox)
{
pictureBox1.Invalidate();
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if(drawingBox)
{
drawingBox = false;
var rc = getRectangle();
if(rc.Width > 0 && rc.Height > 0)
{
rectangleList.Add(rc);
pictureBox1.Invalidate();
}
}
ImageHistory++;
ImageCollection.Add(pictureBox1.Image);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (rectangleList.Count > 0)
{
using (var g = Graphics.FromImage(pictureBox1.Image))
{
g.DrawRectangles(Pens.Black, rectangleList.ToArray());
pictureBox1.Invalidate();
}
}
if(drawingBox)
{
e.Graphics.DrawRectangle(Pens.Red, getRectangle());
pictureBox1.Invalidate();
}
}
private void button1_Click(object sender, EventArgs e)
{
ImageHistory--;
pictureBox2.Image = ImageCollection[ImageHistory];
}
}
更改以下行
ImageCollection.Add(pictureBox1.Image);
到
ImageCollection.Add((Image)pictureBox1.Image.Clone())
虽然接受的答案可以解决问题,但在尝试解决问题时应考虑一些重要注意事项:
你不需要使用
List<Image>
作为撤销缓冲区,它会占用大量内存。目前,由于您不处理未使用的图像,您的应用程序很快就会发生内存泄漏。用
List<Rectangle>
作为undo buffer就够了。它明显使用更少的内存。你不需要跟踪任何要处理的东西,它不需要处理。为了实现这个想法,最好将
List<Rectangle>
保留为撤消缓冲区,每次绘制矩形时,将其添加到缓冲区中,每次撤消时,只需删除最后一个矩形并使绘图表面无效。这样你就不需要改变图片框的图像,你应该只在绘图表面上绘制矩形而不是在图像上绘制它们。最后,如果您需要导出包含所有矩形的图像,只需将它们绘制在位图上并导出图像即可。可以将
Undo
方法和Redo
方法和CanUndo
属性封装在DrawingSurface
控件中使用那些方法在您的应用程序中,而不是直接将这些逻辑放在按钮后面。
例子
您可以查看有关