【问题标题】:Why is my form blinking为什么我的表格在闪烁
【发布时间】:2012-06-01 11:05:55
【问题描述】:

我已经实现了一个简单的多线程服务器\客户端游戏作为我大学的作业。

在客户端除了主线程还有:

1-thread 负责绘制游戏场地和表格上的玩家。

2-thread 与服务器通信以发送方向并接收位置和其他信息。

首先我使用了调用技术,但它不起作用,因为我在处理它之后使用了 Graphics。见Draw on a form by a separate thread

所以为了避免这种情况并规范绘图线程,我只是在绘图线程上的每个特定时间提升标志“无效”并将其实际处理留给主线程:

    public Form1()
    {
        SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        InitializeComponent();
    }

    private void Draw()
    {
        while (true)
        {
            Thread.Sleep(200);
            Invalidate();
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        if (map.hasGraph)
        {
            map.Draw(e.Graphics);
            if (this.Index != null)
                e.Graphics.FillRectangle(Brush, Rectangle);
            if (OpponentIndex != null)
                e.Graphics.FillRectangle(OpponentBrush, OpponentRectangle);
        }
    }

这里的问题是,即使我使用双缓冲,表单也会以任意方式闪烁,并且当我增加绘图线程的睡眠时间时,闪烁会减少,但我认为 200 毫秒已经太多了。 有什么建议吗?

[编辑]

我意识到我正在从代码和属性编辑器中设置双缓冲标志,这导致了问题(这可能是个愚蠢的想法),但我花了半个小时用其中一个标志和他们两个,当我从两个地方设置双缓冲标志时出现的问题,我的问题已经解决了,但是现在我需要知道这是否可以解决它。

【问题讨论】:

  • 展示你如何使用双缓冲,sn-p 中没有证据。
  • 如果您将其空白然后在其上绘制缓冲图像,则可能会发生这种情况。而不是最后一张的缓冲图像。
  • 我们可以假设这是winforms吗?什么是绘画、图片框、面板……的控件?
  • @HansPassant:我添加了双缓冲设置代码
  • 将 DoubleBuffered 属性设置为 true。

标签: c# winforms multithreading drawing


【解决方案1】:

运行时间越长,它一定会越来越糟,对吧?

每次你的程序绘制它都会启动draw,它有一个无限循环,它调用paint,它在另一个无限循环中调用draw。看来您在这里有一个循环引用。如果我可以假设 Map.Draw 是私有的 void Draw()

对此有一个更简单的解决方案,将所有内容绘制到位图,然后在 onPaint 事件中绘制位图。

Bitmap buffer=new Bitmap(this.Width, this.Height); //make sure to resize the bitmap during the Form.Onresize event
Form1()
{
    InitializeComponent();
    Timer timer=new Timer();
    timer.Interval= 100;
    timer.Tick+=......
    timer.Start()
}

//the Timer tick event
private void timer_tick(....
{
    if (map.hasGraph)
    {
         using (Graphics g = Graphics.FromImage(buffer))
        {
            //You might need to clear the Bitmap first, and apply a backfround color or image
            //change color to whatever you want, or don't use this line at all, I don't know
            g.Clear(Color.AliceBlue);

            if (this.Index != null)
                g.FillRectangle(Brush, Rectangle);
            if (OpponentIndex != null)
                g.FillRectangle(OpponentBrush, OpponentRectangle);
        }
     panel1.BackgroundImage=buffer;
     }
}

注意我没有对此进行语法准确性测试。

【讨论】:

  • 如果您愿意,我可以更好地解释这一点。但它应该可以消除很多闪烁问题,我将频率设置为每秒 10 帧,将刻度值更改为您想要的任何值,您将其设置为每秒 5 帧,更改 timer.Interval=(以毫秒为单位)跨度>
  • 我可能没有把这个想法描述得很清楚,我确定我没有循环引用,因为draw方法是一个单独线程的启动方法,所以没有人调用它,而是负责线程.反正看看版本。
【解决方案2】:

对于执行的操作,系统的内存可能非常低。 阅读更多关于它的信息。 http://msdn.microsoft.com/en-us/library/system.drawing.graphics.aspx

【讨论】:

    【解决方案3】:
    1. 创建将用于存储最后渲染场景的图像。
    2. 创建将绘制到图像的新线程
    3. 创建一个定时器来刷新图像
    4. 在计时器滴答时将图像复制到表单

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-13
      • 1970-01-01
      • 1970-01-01
      • 2016-09-29
      • 2013-05-17
      • 2012-02-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多