你好,作为练习,我决定编写自己的 Paint 模拟(我在面板上绘制,通过BitMap 映射“处理”画布,我还在 PaintBackground 上放置了一个“存根”,以便不调用画布)和遇到了很多问题:
1) 由于某种原因,如果您使用Graphics.Clear(fill color)创建一个 BitMap ,那么背景就这样丢失了,尽管如果您使用现成的图像,那么一切都很好。
2) 我只是无法理解如何渲染元素以致于“它不绘制地图,在地图中”,如果我理解正确的话,这正是发生在我身上的事情。
寻求有关更改绘图技术或如何解决上述问题的建议...
代码(去掉所有不必要的,以免干扰):
class Canvas : Panel
{
//###################################################################
//Имя объекта типа Canvas на форме - canvas
//###################################################################
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
}
protected override void OnPaintBackground(PaintEventArgs e) //"заглушка", если это так называется
{
}
}
//описание формы, на которой находится canvas
public partial class MainForm : Form
{
private bool enableBrush;
private PointF coordinate;
private PaintMode mode;
private Bitmap map;
private Color colorBrush;
public enum PaintMode
{
None,
Line,
Brush,
Rect,
Rectangle
}
public MainForm()
{
InitializeComponent();
mode = PaintMode.None;
Graphics g = canvas.CreateGraphics();
g.Clear(Color.White); //не отображает
map = new Bitmap(canvas.Width, canvas.Height, g);
colorBrush = Color.Green;
enableBrush = false;
}
private void canvas_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
coordinate = e.Location; //запоминает позицию курсора при нажатии для рисования
enableBrush = true;
}
}
private void canvas_MouseUp(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Left)
{
enableBrush = false;
map = new Bitmap(canvas.Width,canvas.Height);
canvas.DrawToBitmap(map, new Rectangle(new Point(), canvas.Size)); // "сейвлю" текущую карту в map(BitMap)
}
}
public void canvas_Paint(object sender, PaintEventArgs e)
{
if (enableBrush)
{
switch (mode)
{
case PaintMode.None:
break;
case PaintMode.Line:
e.Graphics.DrawLine(new Pen(colorBrush), coordinate, canvas.PointToClient(MousePosition));
break;
case PaintMode.Brush:
break;
case PaintMode.Rect:
break;
case PaintMode.Rectangle:
break;
default:
break;
}
}
}
private void canvas_MouseMove(object sender, MouseEventArgs e)
{
canvas.Invalidate(); //вызываю перерисовку в каждый момент времени, когда курсор мыши находится над canvas
}
private void LineButton_CheckedChanged(object sender, EventArgs e)
{
if (mode == PaintMode.Line)
mode = PaintMode.None;
else
mode = PaintMode.Line;
}
}
图中的图像可以分为两组
永久的,这实际上是图片本身,最终应该会出现
暂时的,这些是“技术”图像,可以在完成某些操作后将其固定为主要图像。例如画直线时,可以绕起点旋转。
这两组应该绘制在不同的图层上。永久的可以在 上绘制一次
Bitmap
,而临时的可以Bitmap
在控件本身的顶部绘制。这是最简单的选择,当然还有其他选择。为此,您需要将这样的实体定义为“工具”(铅笔,用于绘制点、线等)。那么绘图算法将如下所示:
Bitmap
有一个固定的图像。此顺序将确保图像定位正确 - 工具位于图像上方。
不需要单独的工具
Bitmap
,但我们不需要存储它的所有中间状态。该工具仅在固定时转移到主位图(例如,单击线的终点)。理想情况下,您需要 3 层:
在这种情况下,控件上只绘制了 1 和 2。第 2 个填充了 3 中所需比例的所需片段。应用工具的结果固定在 3 上。
如果你想像在 PhotoShop 中那样支持图层,那么每个图层分别有 2 个额外的位图,但这是完全不同的故事。
现在谈谈背景和其他乐趣。
工作
Graphics.Clear(цвет заливки)
取决于对象的获取方式和来源Graphics
。如果从控件的上下文中获取,那么控件的背景将被重新绘制,如果它Bitmap
是从上下文中重新绘制的Bitmap
。您不需要放置图像作为控件的背景,它不会让您有机会对大图像进行正常的缩放和滚动。
Graphics.DrawImage
另外,无论是控件的背景图片输出还是调用,在性能上都没有太大区别。为了渲染不“慢下来”,控件不“闪烁”,需要做两个强制动作:
启用双缓冲,这不需要您更改渲染代码,但它已经明显影响渲染的流畅性。
从事件处理中删除繁重的操作
Paint
。这些操作无需即时显示即可完成。