0

我拥有使用 GDI+ 的复杂绘图代码,它在用户控件上绘制类似于图表的东西。如果用户在按下控件的情况下单击,则应显示虚线样式的垂直标记线。

现在我寻找一种方法来扩展绘图代码,而无需触及复杂的绘图代码。

我创建了一个标记类,它附加到用户控件的鼠标向上事件。在事件处理(ModifierKeys == Keys.Control)程序中进行检查。

如果用户按住控制键并用鼠标左键单击,则以用户控件的Graphics对象作为参数调用标记类的绘制方法。

当前的行为是每次单击都会绘制一条新线,但应删除该线并绘制一条新线。

我怎样才能擦除绘制的线?

我是否必须重绘用户控件的完整内容?

4

2 回答 2

3

您无法删除绘制的线,因为无法恢复底层图形。

你可以做的是:

  • 重绘整个图形(没有线)

或者

  • 在顶部堆叠第二个透明用户控件并使用它来显示该行。需要时将其移除和绘制。
于 2012-08-05T13:26:05.457 回答
2

这里的答案显然是肯定的。使用 GDI+,您只需直接在位图缓冲区上绘图,因此如果您想撤消先前的绘图操作,您可以执行以下操作之一(取决于问题的复杂性和性能):

  • 恢复位图缓冲区上已更改的字节
  • 重新加载绘图位图的先前状态

一个简单的解决方案是拥有 2 个位图(类似的东西通常称为双缓冲)。一个当前显示(并包含最终状态),一个仅用于预览。预览版始终是第一个的副本 - 只是带有当前修改。

所以这个简单实现的基本算法:

  • 从两个位图开始(空白但大小相同)[命名为 A 和 B]
  • 如果用户画一条线,总是在 B 中复制位图 A 并在 B 上绘制 - 显示 B
  • 如果用户完成该行,则在 A 中复制 B 并再次 - 显示 B

所以总是显示预览位图,它只是原始位图的修改。

这是 C# 中的示例编程代码(假设所有事件都已连接,并且预览位图 B 是图片框本身(此处仅命名为 pictureBox1):

Bitmap bmp;
bool isDrawing;
Point previous;

void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
    isDrawing = true;
    previous = e.Location;
}

void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
    isDrawing = false;
}

void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    if (isDrawing)
    {
        using (Graphics g = Graphics.FromImage(bmp))
        {
            double wf = (double)bmp.Width / (double)pictureBox1.Width;
            double hf = (double)bmp.Height / (double)pictureBox1.Height;
            g.ScaleTransform((float)wf, (float)hf);
            g.DrawLine(Pens.Black, e.Location, previous);
        }

        pictureBox1.Refresh();
        previous = e.Location;
    }
}

这段代码将做所有事情来显示从一个点到另一个点的直线,只需按下鼠标左键。

于 2012-08-05T13:26:54.240 回答