为什么我的异步进度忽悠文本? [英] Why does the text on my asynchronous ProgressBar flicker?

查看:106
本文介绍了为什么我的异步进度忽悠文本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要显示的文字进度没有的一个的自定义进度栏)。这并不难做到,而且不涉及的OnPaint 法 - 为具有以下code的button1的证明。但是,这种方法阻止UI线程,这是邪恶
不幸的是,以异步方式我最好的刺使文本闪烁,这是很烦人的。

有人能告诉我如何异步更新文本而不闪烁?


  

<子>(要运行下面的code,只需将其粘贴到一个新的项目
  含3个按钮和3 ProgressBars)表单。


 使用系统;
使用System.Drawing中;
使用System.Windows.Forms的;
使用System.Threading.Tasks;
使用的System.Threading;命名空间ProgBarTest //改变命名空间相应的Program.cs
{
    公共部分Form1类:表格
    {
        公共Form1中()
        {
            的InitializeComponent();
        }        私人无效的button1_Click(对象发件人,EventArgs的发送)
        {
            //此方法将阻塞主UI线程
            //(从而冻结其他按钮)
            StartUpdate(this.progressBar1);
        }
        私人无效button2_Click(对象发件人,EventArgs的发送)
        {
            //该方法(和下一个)不阻塞的用户界面中,并且可以同时使用,
            //但文字闪烁
            任务T =新建任务(()=&GT; StartUpdate(this.progressBar2));
            t.Start();
        }
        私人无效button3_Click(对象发件人,EventArgs的发送)
        {
            任务T =新建任务(()=&GT; StartUpdate(this.progressBar3));
            t.Start();
        }        私人无效StartUpdate(进度progBar)
        {
            的for(int i = 1; I&LT; = 100;我++)
            {
                UpdateProgressBar(ⅰ,progBar);
                Thread.sleep代码(100);
            }
        }        私人无效UpdateProgressBar(INT I,进度progBar)
        {
            如果(progBar.InvokeRequired)//用于后台任务使用
            {
                progBar.Invoke(新动作&LT; INT,进度&GT;(UpdateProgressBar)
                                  新的对象[] {我,progBar});
            }
            其他
            {
                //设置进度条:
                progBar.Value = I;
                progBar.Refresh();                //设置状态标签:
                字符串percentStr = i.ToString()+%;
                的PointF位置=新的PointF(progBar.Width / 2 - 10,progBar.Height / 2 - 7);
                使用(图形克= progBar.CreateGraphics())
                {
                    gr.DrawString(percentStr,新的字体(宋体,10),Brushes.Red,位置);
                }
            }
        }    }
}


解决方案

在所有诚实,一个自定义的进度将是你最好的选择。如果您正确设置它。我知道我不会回答你的问题,所以请不要downvote,只是提供不同的解决方案。我没有测试过这个工具,但它在理论上得出的百分比每一个进度条来得及重新绘制,该值被改变了会发生,每次

您目前的问题是,酒吧的重新绘制本身每次您更改值,从而文字的闪烁。如果它不重画,你会看到个你画开始在覆盖的海誓山盟哪也不好顶。

这将是更好地从设计的角度封装一个控制内的所有内容以及

 类CustomProgressBar:进度{
    公共CustomProgressBar():碱(){}    保护覆盖无效的OnPaint(PaintEventArgs的E){
        //调用基类的OnPaint方法。
        base.OnPaint(E);
        字符串percentStr = this.Value.ToString()+%;
        的PointF位置=新的PointF(this.Width / 2 - 10,this.Height / 2 - 7);
        //将System.Drawing.Graphics召唤方法对象。
        e.Graphics.DrawString(percentStr,新的字体(宋体,10),Brushes.Red,位置);
    }
}

I want to display text on a ProgressBar, (without all the nonsense of a custom progress bar). This is not hard to do, and does not involve the OnPaint method -- as demonstrated with button1 of the following code. However, this method blocks the UI thread, which is evil. Unfortunately, my best stab at an asynchronous approach causes the text to flicker, which is very annoying.

Can somebody show me how to update the text asynchronously without the flicker?

(To run the following code, just paste it into a new project containing a Form with 3 Buttons and 3 ProgressBars).

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Threading;

namespace  ProgBarTest //change namespace in Program.cs accordingly
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //This method will block the main UI thread
            // (thus freezing the other buttons)
            StartUpdate(this.progressBar1); 
        }
        private void button2_Click(object sender, EventArgs e)
        {
            //this method (and the next) don't block the UI, and can be used concurrently,
            // but the text flickers
            Task t = new Task(() => StartUpdate(this.progressBar2));
            t.Start();
        }
        private void button3_Click(object sender, EventArgs e)
        {
            Task t = new Task(() => StartUpdate(this.progressBar3));
            t.Start();
        }

        private void StartUpdate( ProgressBar progBar)
        {
            for (int i = 1; i <= 100; i++)
            {
                UpdateProgressBar(i, progBar);
                Thread.Sleep(100);
            }
        }

        private void UpdateProgressBar(int i, ProgressBar progBar)
        {
            if (progBar.InvokeRequired) //for use with background Task
            {
                progBar.Invoke(new Action<int, ProgressBar>(UpdateProgressBar), 
                                  new Object[] { i, progBar });
            }
            else
            {
                //set progress bar:
                progBar.Value = i;
                progBar.Refresh();

                //set status label:
                string percentStr = i.ToString() + "%";
                PointF location = new PointF(progBar.Width / 2 - 10, progBar.Height / 2 - 7);
                using (Graphics gr = progBar.CreateGraphics())
                {
                    gr.DrawString(percentStr, new Font("Arial",10), Brushes.Red, location );
                }
            }
        }

    }
}

解决方案

In all honesty, a custom ProgressBar would be your best bet.. if you set it up correctly. I know I'm not answering your question so please don't downvote, just offering a different solution. I haven't tested this yet, but it would in theory draw the percentage every time the progress bar had to repaint, which would happen everytime the value was changed.

Your current problem is that the bar is repainting itself everytime you change the value, thus the flickering of the text. If it didn't repaint, you would see percentage you draw starting to overlay on top of eachother which is not good either.

This would be better to encapsulate everything within one control from a design standpoint as well.

class CustomProgressBar : ProgressBar {
    public CustomProgressBar() : base() {}

    protected override void OnPaint(PaintEventArgs e) {
        // Call the OnPaint method of the base class.
        base.OnPaint(e);
        string percentStr = this.Value.ToString() + "%";
        PointF location = new PointF(this.Width / 2 - 10, this.Height / 2 - 7);
        // Call methods of the System.Drawing.Graphics object.
        e.Graphics.DrawString(percentStr, new Font("Arial",10), Brushes.Red, location );
    } 
}

这篇关于为什么我的异步进度忽悠文本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆