【问题标题】:How to paint additional things on a drawn panel?如何在绘制的面板上绘制额外的东西?
【发布时间】:2014-12-17 01:48:39
【问题描述】:

我正在阅读很多关于 C# 绘图和使用图形处理程序阅读 GDI+ 上的 MSDN 教程。

我希望能够绘制一个图表,我在列表中有哪些节点但我不能使用自动放置,我需要节点位于指定的位置并具有特定的外观等等,转换时间,这就是我停止寻找图形库的原因。

第一次绘制时效果很好,但是当我想要在代码中发生其他事情之后(而不是单击控件之后)绘制一些东西时,我不能这样做。例如:

if (somethingHappens) {
  // repaint the panel adding some things
}

我得到的只是没有新的事情发生,或者我之前的画消失了。

我发现了一些关于 OnPaint 覆盖和最小化时图纸消失的示例。当我需要在应用程序中发生某些事情时需要绘制额外的东西时,我是否必须覆盖它或者它是否完全不同?

【问题讨论】:

  • 如果你想在面板上绘制任何东西(持久性),你只能(读我的嘴唇:only)在 Paint 事件中或从那里调用的方法中进行(您将 e.Graphics 参数交给它)。其他的都是错误! - 无论您绘制什么,都必须首先将其放入(可能)存储在(可能)类级别的一系列绘制动作中,然后您可以在 Paint 事件中进行绘制。 - 每当您想绘制更多内容时,您必须将更多这些绘制动作添加到您拥有的集合中,然后致电yourPanel.Invalidate();! - 所以,你学会了如何让它看起来不错,现在用它来做正确的事!
  • 要获得更具体的建议,请考虑发布一些关于您目前绘制的内容和方式的代码..!
  • 顺便说一句:还有另一种选择:您也可以将放入 PictureBox 中显示的图像,然后依次添加更多内容。看可以回答here for a short example! - 主要区别在于这种累积绘制的方式不会让你改变你以前做过的事情。
  • 换句话说,每次调用 Paint() 事件时,都会绘制“绘图集合”中的所有内容。要添加新内容或更改某些内容,您可以以某种方式添加或修改集合,然后再次绘制所有内容,向您显示新的“状态”。
  • 如果有些东西是有条件地绘制的,我需要把所有的代码放在那里并有一些标志吗?不。如果有条件地绘制了一些东西,你将它添加到绘制动作集合中在这些条件下。绘制动作通常是一个类,其中包含点、画笔等数据以及线条、矩形椭圆等动作类型。 - 在 apint 事件中,您将有一些类似 foreach (drawaction da in drawactions) if (da.type==..) e.Graphics.DrawLines(..).. 如果您只在节点之间绘制线条,您可能没有一类平局动作就可以逃脱,就像彼得的回答一样..

标签: c# winforms drawing gdi+


【解决方案1】:

我寻找了另一个包含您需要的信息的问答。坦率地说,这是一个基本问题,如何正确处理绘制 Forms 控件。 Overriding the OnPaint MethodCustom Control Painting and Rendering 等 MSDN 主题提供了一些有关正确方法的详细信息。但令我惊讶的是,我找不到任何至少直接解决这个基本问题的 StackOverflow 问答(当然,有 许多 只是切题地解决这个问题)。

不管怎样……

这是在表单代码中绘制的基本顺序:

  1. 生成一些要绘制的数据
  2. 使绘制数据的控件无效
  3. 通过实际绘制数据来处理 Paint 事件

根据需要重复上述操作,即任何时候数据发生变化(例如“某事发生”,如您的问题中所示),您将返回到第 1 步,将您想要的任何新数据添加到您现有的数据集合中,然后使控件无效,并最终响应您的事件处理程序中的Paint 事件。

在绘制图表的情况下,这可能看起来像这样:

private List<Point> _points = new List<Point>();

void AddPoint(Point point)
{
    _points.Add(point);
    panel1.Invalidate();
}

void panel1_Paint(object sender, PaintEventArgs e)
{
    if (_points.Count < 2)
    {
        return;
    }

    Point previousPoint = _points[0];

    for (int i = 1; i < _points.Count; i++)
    {
        currentPoint = _points[i];

        e.Graphics.DrawLine(Pens.Black, previousPoint, currentPoint);
        previousPoint = currentPoint;
    }
}

请注意,panel1_Paint() 事件是一个事件处理程序。通常,您可以通过设计器创建它,方法是选择Panel 对象,切换到控件“属性”窗口中的“事件”列表,然后双击Paint 事件的编辑字段。

这当然是最简单的例子。您可以添加诸如以批处理方式更新数据之类的内容(即在添加一组点之前不要使控件无效),使用不同的颜色或线条样式进行绘制,绘制图形的其他元素,如轴、刻度,图例等。以上只是为了说明基本技术。

最后一点:根据您需要在图表中绘制的点数,上述方法可能不够快,也可能不够快。它应该可以达到数千点左右,但是如果您开始达到数万或数十万或更多,您可能会发现将绘图缓存到位图中并仅绘制位图很有用。但这是一个完全不同的问题。首先,您需要确保您了解 Forms 绘图模型并正确使用它。

【讨论】:

  • 谢谢!我在一个活动中画了我的表格,但显然我错过了一些东西。我不会绘制超过 50 个节点,所以它非常适合我。
  • 正确。虽然对于这种绘图,我想使用一个 DrawLines 会比许多 DrawLine 调用更好,无论是对于其他笔的性能和绘图质量,更不用说简单了..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多