【问题标题】:How do I clear a previously-drawn rectangle from an image using mouse/paint events?如何使用鼠标/绘画事件从图像中清除先前绘制的矩形?
【发布时间】:2012-07-24 03:17:18
【问题描述】:

我正在设计一个将图像加载到 PictureBox 并允许用户在其上绘制选择矩形的应用程序。目前,我使用 Paint 事件和一个布尔值来清除先前绘制的矩形(因为它是一个可拖动的选择框)。

问题:

代码失败,因为之前的矩形没有从图像中清除。尽管绘制的每个矩形都是透明的,但效果是一个不透明的矩形,因为之前的矩形没有被清除。如何清除这些矩形?

逻辑:

saveState 默认为真。当 Paint 事件第一次被触发时,包含正常图像的状态被保存。当触发 MouseDown 事件时,我们注册矩形的起始位置和一个指示正在绘制矩形的布尔值。

当触发 MouseMove 事件时,我们在当前坐标处绘制一个矩形。由于绘制时触发了Paint事件(我认为)并且saveState为false,因此我们在绘制矩形之前恢复正常图像。

最后,当触发 MouseUp 事件时,saveState 被设置为 true,因此图形状态(最后绘制的矩形)被保存,我们又回到了起点。

我读到了 ControlPaint.DrawReversibleFrame,但由于 this articlethis question 给我的印象是它不是为在图像上绘制而是为直接在屏幕或表单上绘制而设计的,我不确定那是我需要什么。

代码:

public partial class MainWindow : Form
{
    private bool drawingRectangle;
    private int x1, y1, x2, y2;
    private Image currentImage;
    private GraphicsState previousState;
    private bool saveState;

    public MainWindow()
    {
        InitializeComponent();
        this.drawingRectangle = false;
        this.saveState = true;
    }

    private void EditorPictureBox_MouseDown(object sender, MouseEventArgs e)
    {
        this.x1 = e.X;
        this.y1 = e.Y;
        this.drawingRectangle = true;
    }

    private void EditorPictureBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (this.drawingRectangle)
        {
            this.x2 = e.X;
            this.y2 = e.Y;
            Graphics g = Graphics.FromImage(this.currentImage);
            int[] dim = ImageLibrary.CalculateRectangleDimensions(this.x1, this.y1, this.x2, this.y2);
            g.FillRectangle(new SolidBrush(Color.FromArgb(100, 128, 255, 255)), dim[0], dim[1], dim[2], dim[3]);
            this.Refresh();
        }
    }

    private void EditorPictureBox_Paint(object sender, PaintEventArgs e)
    {
        if (this.saveState)
        {
            this.previousState = e.Graphics.Save();
            this.saveState = false;
        }
        else
            e.Graphics.Restore(this.previousState);
    }

    private void EditorPictureBox_MouseUp(object sender, MouseEventArgs e)
    {
        if (this.drawingRectangle)
        {
            this.drawingRectangle = false;
            // When the mouse click is released, save the graphics state
            this.saveState = true; 
        }
    }

    private void LoadImage2Button_Click(object sender, EventArgs e)
    {
        this.currentImage = Image.FromFile("goat2.jpg");
        this.EditorPictureBox.Image = this.currentImage;
    }   
}

这是CalculateRectangleDimensions 的代码(存储在静态库中):

public static int[] CalculateRectangleDimensions(int x1, int y1, int x2, int y2)
{
    int[] dimensions = new int[4]; // x1, y1, width, height
    if (x1 <= x2) // Mouse was dragged to the right
    {
        dimensions[0] = x1;
        dimensions[2] = x2 - x1;
    }
    else // Mouse was dragged to the right
    {
        dimensions[0] = x2;
        dimensions[2] = x1 - x2;
    }

    if (y1 <= y2) // Mouse was dragged up
    {
        dimensions[1] = y1;
        dimensions[3] = y2 - y1;
    }
    else // Mouse was dragged down
    {
        dimensions[1] = y2;
        dimensions[3] = y1 - y2;
    }
    return dimensions;
}

【问题讨论】:

    标签: c# winforms graphics


    【解决方案1】:

    Graphics.Save 在调用时不会保存图形的全部内容,它只是保存状态信息,如平移、缩放、变换等。

    如果您想撤消已经完成的绘制,则必须执行可逆绘制之类的操作,否则您必须在要撤消绘制时重新绘制原始图像。

    【讨论】:

    • 我应该使用ControlPaint.DrawReversibleFrame吗?它允许我在图像本身上画画吗?
    • 对于你正在做的事情(鼠标拖动时的临时绘图),我认为DrawReversibleFrame 正是你想要的。您不需要在图像上绘制,您需要在用户拖动鼠标的屏幕上临时绘制,对吧?
    • 基本上,是的。一旦用户放开鼠标,我需要将透明矩形与图像一起保存,但对于选择过程,不需要保存。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    • 1970-01-01
    • 2019-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    相关资源
    最近更新 更多