代码之家  ›  专栏  ›  技术社区  ›  jheddings

更新面板的子项时出现“闪烁”问题

  •  0
  • jheddings  · 技术社区  · 15 年前

    我有一个 TableLayoutPanel 包含多行标签的。此控件位于具有渐变背景的窗体上。标签定期更新,通常作为一个整体更新。当它们被更新时,它们的更新速度非常慢,并且对用户非常可见。

    我试过用 DoubleBuffered 在表单上,但正如预期的那样,这没有帮助。然后我试着延长 表布局面板 设置它的 双缓冲的 财产,但这似乎使事情变得更糟。我也试过 SuspendLayout() 在桌子上,但这也没有任何效果。

    我从 DataGridView 不支持透明度…不过,我真的很想找到这个设置的替代方案。

    Other questions 似乎有关联,但我还没有找到解决问题的方法。

    关于如何解决更新问题,或者一个可能的替代方案,有什么想法吗?

    编辑 因为我要处理固定数量的数据来表示这个表,所以我将研究直接在油漆处理程序中绘制字符串,而不是使用标签。

    2 回复  |  直到 15 年前
        1
  •  2
  •   Vasyl Boroviak    15 年前

    标签是否停靠(意思是 label.Dock = DockStyle.Fill )是吗?

    每个代码之间有多少个代码 label.Text 改变?

    我的应用程序有完全相同的用户界面。tablelayoutpanel内的标签,tablelayoutpanel内的标签。但没有渐变背景。每个面板和标签都没有边距和填充。每个标签都是停靠填充的。首先,我们获取每个标签的所有值。只有在这之后,我们才能改变所有的标签,只是在单独的线程中。

    string[] texts = GetAllLabels();
    ownerControl.Invoke(new Action(() =>
    {
      for (int i = 0; i < UpdatingControls.Count && i < texts.Count; i++)
      {
        UpdatingControls[i].Text = texts[i];
      }
    }));
    

    这将(在我们的例子中)闪烁减少到最小。

        2
  •  1
  •   jheddings    15 年前

    消除闪烁的唯一方法是使用自定义控件(如面板)的绘制处理程序。我尝试的其他方法似乎可以减少闪烁,但没有什么能消除它。

    根据我所看到的,标签本身都在做类似的事情,当它们的数据被更改时,它们就会失效。没有办法阻止这个过程,所以净效果是滚动/滞后更新每个标签到下一个。这在复杂的背景(如图像)上被放大。

    通过使用画图处理程序并计算每个“行”的边界,我能够为应用程序获得相同的表查找,并且其背景保持透明。

    这不是一个新颖的代码,但在这里是为了防止它帮助其他人:

    private const int RowCount = 10;
    private DataTable _table;  // updated elsewhere
    
    private void OnPaint(Object sender, PaintEventArgs e) {
        if (! this.DesignMode) {
            DrawTable(e.Graphics);
        }
    }
    
    private void DrawTable(Graphics gfx) {
        SolidBrush brush = new SolidBrush(this.ForeColor);
        for (int rownum = 0; rownum < RowCount; rownum++) {
            RectangleF rect = GetRowBounds(rownum);
            DrawRowNumber(gfx, rect, rownum);
    
            if (_table.Rows.Count > rownum) {
                DataRow data = _table.Rows[rownum];
                DrawName(gfx, rect, Convert.ToString(data["name"]));
                DrawCount(gfx, rect, Convert.ToSingle(data["count"]));
            }
        }
    }
    
    private void DrawRowNumber(Graphics gfx, RectangleF bounds, int place) {
        String str = String.Format("{0}.", (place + 1));
        SolidBrush brush = new SolidBrush(this.ForeColor);
        gfx.DrawString(str, this.Font, brush, bounds.Location);
    }
    
    private void DrawName(Graphics gfx, RectangleF bounds, String name) {
        PointF loc = new PointF(80, bounds.Top);
        SolidBrush brush = new SolidBrush(this.ForeColor);
        gfx.DrawString(name, this.Font, brush, loc);
    }
    
    private void DrawCount(Graphics gfx, RectangleF bounds, float score) {
        SolidBrush brush = new SolidBrush(this.ForeColor);
        String str = score.ToString("N1");
        SizeF size = gfx.MeasureString(str, this.Font);
        float offset = bounds.Right - size.Width;
        PointF loc = new PointF(offset, bounds.Top);
        gfx.DrawString(str, this.Font, brush, loc);
    }
    
    private RectangleF GetRowBounds(int row) {
        if ((row < 0) || (row >= RowCount)) {
            return RectangleF.Empty;
        }
    
        Rectangle bounds = this.ClientRectangle;
        float height = (float) bounds.Height / (float) RowCount;
    
        PointF loc = new PointF(bounds.Left, height * row);
        SizeF size = new SizeF(bounds.Width, height);
    
        return new RectangleF(loc, size);
    }