我拥有GDI+的复杂绘图代码,它在用户控件上绘制类似图表的东西。如果用户在按下控件的情况下单击,则应显示一条短划线样式的垂直标记线。
现在,我正在寻找一种方法来扩展图形代码,而不必接触复杂的图形代码。
我创建了一个标记类,它附加到用户控件的鼠标向上事件。在事件处理程序中,对(ModifierKeys == Keys.Control)
进行检查。
如果用户按住控制键并用鼠标左键单击,则会以用户控件的Graphics
对象为参数调用标记类的绘制方法。
当前的行为是,每次单击都会绘制一条新线,但应该删除该线并绘制一条新线。
我怎样才能擦除划线?
我必须重新绘制用户控件的删除内容吗?
无法删除绘制的线,因为无法恢复底层图形。
你可以做的是:
- 重新绘制整个图形(不带直线)
或
- 在顶部堆叠第二个透明用户控件,并使用它来显示行。在需要时移除并绘制它
这里的答案显然是肯定的。使用GDI+,您只需直接在位图缓冲区上绘制,因此如果您想撤消以前的绘制操作,您可以执行以下操作之一(取决于问题的复杂性和性能):
- 恢复位图缓冲区上已更改的字节
- 重新加载图形位图的先前状态
一个简单的解决方案是有两个位图(类似的东西通常被称为双缓冲)。一个是当前显示的(包含最终状态),另一个仅用于预览。预览的始终是第一个的副本,只是经过了当前的修改。
所以这个简单实现的基本算法:
- 从两个位图(空白但大小相同)开始[命名为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;
}
}
此代码将通过简单地按下鼠标左键来显示从一点到另一点的直线绘制。