如何从另一个 event/class 调用不对整个面板无效的方法

How to call Invalidate not for the whole panel from another event/class

我有一个看起来像这样的绘画事件:

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);
}

我有一个来自串行端口的数据流,每次收到数据时我都想让 rec2 无效,但不是整个表单。我能够在我的 Datareceived 事件中使整个表单无效:

panel1.Invalidate();

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

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 派生出你自己的 class 并添加到它的构造函数中:

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

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

最后说明:您对坐标进行了硬编码,这不是一个好的做法,除非您有一个固定大小的面板(有或没有滚动),因为它不会随着未来的变化而很好地缩放,并且在许多情况下可能会被破坏(一旦您的代码变得比虚构的示例稍微复杂一些)。