如何从另一个事件/类调用Invalidate不是整个面板

时间:2015-04-08 11:19:17

标签: c# panel invalidation

我有一个看起来像这样的油漆事件:

private void panel1_Paint(object sender, PaintEventArgs e)
{
    Rectangle rec = new Rectangle(2, 2, 820, 620);
    Pen pi = new Pen(Color.Black, 2);
    e.Graphics.DrawRectangle(pi, rec);

    Rectangle rec2 = new Rectangle(Convert.ToInt32((410 + 2500 * GlobaleVariablen.IstWerte[0])), Convert.ToInt32(310 + 1875 * GlobaleVariablen.IstWerte[1]), 2, 2);
    e.Graphics.DrawRectangle(pi,rec2);
}

我有一个来自serialport的数据流,每当我收到数据时,我想使rec2无效,但不是整个表单。我能够在我的Datareceived事件中使用以下内容使整个表单无效:

panel1.Invalidate();

然而,我不知道如何才能使我的rec2无效,因为如果你一直使用数据流使整个表单无效,它会像疯了一样闪烁,看起来真的不太好。

1 个答案:

答案 0 :(得分:2)

Invalidate()有一个过载版本Rectangle,您希望无效:

panel1.Invalidate(GetRect2());

GetRect2()(请选择一个更好的名字)的地方如下:

static Rectangle GetRect2() {
    int x Convert.ToInt32((410 + 2500 * GlobaleVariablen.IstWerte[0]));
    int y = Convert.ToInt32(310 + 1875 * GlobaleVariablen.IstWerte[1]);

    return new Rectangle(x, y, 2, 2);
}

在您的绘图事件处理程序中,您首先要检查无效区域是否与要写入的每个对象相交(示例很简单,因为您正在处理矩形并且没有缓慢的扩展填充)。

在您的代码中会对性能产生更大影响的事实是您为每个绘制操作创建了一个新的Pen。这是您必须绝对避免的: 扩展本机资源必须重复使用。最终代码可能类似于:

private Pen _pen = new Pen(Color.Black, 2);
private void panel1_Paint(object sender, PaintEventArgs e)
{
    var rec = new Rectangle(2, 2, 820, 620);
    if (e.ClipRectangle.IntersectsWith(rec))
        e.Graphics.DrawRectangle(_pen, rec);

    var rec2 = GetRect2();
    if (e.ClipRectangle.IntersectsWith(rec2))
        e.Graphics.DrawRectangle(pi, rec2);
 }

现在您的代码稍微优化但它仍然可能会闪烁。为避免这种情况,您必须为面板启用双缓冲。从Panel派生自己的类并添加其构造函数:

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

也可能是重构代码并在一个单独的类中移动一些绘制逻辑(但不是面板本身)的好机会。有关您可能需要使用的其他标志(例如AllPaintingInWmPaint),请参阅MSDN。

最后的注意事项:你是硬编码的坐标,除非你有一个固定大小的面板(有或没有滚动),这不是一个好习惯,因为它不能很好地适应未来的变化,并且可能在许多情况下被破坏(如一旦你的代码变得比一个虚构的例子稍微复杂一点。)