用户操作
[即时聊天] [发私信] [加为好友]
曾洪宁ID:Knight94
277187次访问,排名224,好友0人,关注者46人。
Knight94的文章
原创 86 篇
翻译 0 篇
转载 1 篇
评论 620 篇
Knight94的公告
抉择?!
邮箱为 knight94cn@21cn.com
最近评论
lanyur:后面的怎么不写了呢?
bmoon:愚翁老师,非常感谢您的知识,您的blog一直在引导我的成长,谢谢
bmoon:愚翁老师,非常感谢您的知识,您的blog一直在引导我的成长,谢谢
hongxuyao:受益匪浅,严重支持!!!
levenwood:感激涕凌(最后一字错了)
文章分类
收藏
    相册
    网址推荐
    Code Project
    FAQ Asp.Net
    FAQ WinForm
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 如何弹出一个模式窗口来显示进度条收藏

    新一篇: 如何去写一个.Net程序 | 旧一篇: 程序以及窗体运行的唯一性汇总

    最近看了好多人问这方面的问题,以前我也写过一篇blog,里面说了如何在子线程中控制进度条。但目前大多数环境,需要弹出模式窗口,来显示进度条,那么只需要在原先的基础上稍作修改即可。

     

    首先是进度条窗体,需要在上面添加进度条,然后去掉ControlBox。除此外,还要增加一个方法,用来控制进度条的增加幅度,具体如下:

        /// <summary>

        /// Increase process bar

        /// </summary>

        /// <param name="nValue">the value increased</param>

        /// <returns></returns>

        public bool Increase( int nValue )

        {

            if( nValue > 0 )

            {

                if( prcBar.Value + nValue < prcBar.Maximum )

                {

                    prcBar.Value += nValue;

                    return true;

                }

                else

                {

                    prcBar.Value = prcBar.Maximum;

                    this.Close();

                    return false;

                }

            }

            return false;

        }

     

    接着就是主窗体了,如何进行操作了,首先需要定义两个私有成员,一个委托。其中一个私有成员是保存当前进度条窗体对象,另一个是保存委托方法(即增加进度条尺度),具体如下:

        private frmProcessBar myProcessBar = null;

        private delegate bool IncreaseHandle( int nValue );

        private IncreaseHandle myIncrease = null;

     

    接着要在主窗体中提供函数来打开进度条窗体,如下:

        /// <summary>

        /// Open process bar window

        /// </summary>

        private void ShowProcessBar()

        {

            myProcessBar = new frmProcessBar();

     

            // Init increase event

            myIncrease = new IncreaseHandle( myProcessBar.Increase );

            myProcessBar.ShowDialog();

            myProcessBar = null;

        }

     

    那么现在就可以开始创建线程来运行,具体如下:

        /// <summary>

        /// Sub thread function

        /// </summary>

        private void ThreadFun()

        {

            MethodInvoker mi = new MethodInvoker( ShowProcessBar );

            this.BeginInvoke( mi );

     

            Thread.Sleep( 1000 );//Sleep a while to show window

     

            bool blnIncreased = false;

            object objReturn = null;

            do

            {

                Thread.Sleep( 50 );

                objReturn = this.Invoke( this.myIncrease,

                    new object[]{ 2 } );

                blnIncreased = (bool)objReturn ;

            }

            while( blnIncreased );

        }

          

           注意以上,在打开进度条窗体和增加进度条进度的时候,一个用的是BeginInvoke,一个是Invoke,这里的区别是BeginInvoke不需要等待方法运行完毕,而Invoke是要等待方法运行完毕。还有一点,此处用返回值来判断进度条是否到头了,如果需要有其他的控制,可以类似前面的方法来进行扩展。

     

    启动线程,可以如下:

        Thread thdSub = new Thread( new ThreadStart( ThreadFun ) );

        thdSub.Start();

     

    这样,一个用模式打开进度条窗体就做完了。

    发表于 @ 2006年05月27日 10:43:00|评论(loading...)|编辑

    新一篇: 如何去写一个.Net程序 | 旧一篇: 程序以及窗体运行的唯一性汇总

    评论

    #Tuff 发表于2006-05-29 22:11:00  IP: 222.190.124.*
    未处理 System.InvalidOperationException
    Message="在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。"
    Source="System.Windows.Forms"
    #knight94 发表于2006-05-30 07:44:00  IP: 218.71.239.*
    to Tuff

    出现这类问题,主要是窗体还没形成,就调用Invoke或者BeginInvoke方法。
    哪个方法产生的异常,如果是第二个,你把Thread.Sleep时间加长一些,或者在其Form_load时间中尽快的显示出来,即用“this.Show()”。
    #violence 发表于2006-07-31 16:07:00  IP: 61.144.207.*
    怎么改变线程里的某个被用的变量的量.
    #knight94 发表于2006-08-01 17:49:00  IP: 218.71.239.*
    参看我的另外一篇文章,关于线程类的,
    地址:
    http://blog.csdn.net/knight94/archive/2006/03/21/631238.aspx
    #4G 发表于2006-08-04 11:31:00  IP: 202.122.32.*
    frmProcessBar是什么类
    #knight94 发表于2006-08-04 11:54:00  IP: 218.71.239.*
    to frmProcessBar是什么类

    显示进度条的窗体类
    #tianjj 发表于2006-08-14 14:18:00  IP: 203.86.72.*
    为什么要用线程,请指教。
    是菜鸟
    #tianjj 发表于2006-08-14 14:36:00  IP: 203.86.72.*
    用Timer是不是也可以。
    请教两者的区别。
    #knight94 发表于2006-08-14 14:49:00  IP: 218.71.239.*
    to tianjj

    用timer操作进度条没有什么问题,但是和数据导入之类操作的交互性就比较差了。
    #tianjj 发表于2006-08-14 15:46:00  IP: 203.86.72.*
    OK,谢谢knight94
    #tianjj 发表于2006-08-14 15:58:00  IP: 203.86.72.*
    还有一件事请教:
    this.BeginInvoke(mi);
    在vsnet为什么不能智能显示。
    #knight94 发表于2006-08-14 17:47:00  IP: 218.71.239.*
    to tianjj

    你所谓的智能显示具体是什么意思
    #tianjj 发表于2006-08-15 10:42:00  IP: 203.86.72.*
    this.BeginInvoke(mi);
    ==========
    OK,
    解决了,是.net1.1 和2.0下都调试成功。


    如果在frmProcessBar做一个随这着进度条的百分比,是否还要有一个Invoke 线程。
    #knight94 发表于2006-08-15 12:01:00  IP: 218.71.239.*
    to tianjj

    至于百分比之类的,属于细节问题,

    我只是给了一个方法,怎么在我的基础上进行扩展属于你的工作。

    我相信你会做得更漂亮。
    #damofengbo 发表于2006-08-27 16:37:00  IP: 218.97.242.*
    MethodInvoker mi = new MethodInvoker (ShowProcessBar );
    this.BeginInvoke( mi );
    出错:ShowProcessBar()
    与委托“void System.Windows.Forms.MethodInvoker()”不匹配
    #damofengbo 发表于2006-08-27 16:32:00  IP: 218.97.242.*
    MethodInvoker mi = new MethodInvoker (ShowProcessBar );
    this.BeginInvoke( mi );
    出错:ShowProcessBar()
    与委托“void System.Windows.Forms.MethodInvoker()”不匹配
    #damofengbo 发表于2006-08-27 17:41:00  IP: 218.97.242.*
    问题:
    主窗体类()
    {控件1;A a;B b}
    类A()
    {B b; 方法F1(){b.F2(参数)}}
    类B()
    {控件1 方法F2(参数){访问控件1}}

    线程函数里面调用a.F1()访问控件1,
    这里好像是线程里面访问主界面的控件问题
    请问我的方法F1里面该怎么写,
    F1()
    {
    object[] pList = {参数};
    MethodInvoker mi = new MethodInvoker(b.F2);
    b.控件1.BeginInvoke(mi,pList);
    }
    #knight94 发表于2006-08-27 18:39:00  IP: 218.71.239.*
    to damofengbo

    MethodInvoker只是一个比较简单的委托,原型如下
    public delegate void MethodInvoker();

    如果你要使用MethodInvoker来定义对象,首先要看看是否符合上面的样式。
    如果不符合的话,可以进行扩展,例如:
    public delegate returntype myMethodInvoker( yourParam );
    myMethodInvoker mi = new myMethodInvoker( .. );
    yourControl.BeginInvoke( mi, new object[]{..} );
    #damofengbo 发表于2006-08-28 19:41:00  IP: 218.97.242.*
    谢谢
    #dlzhangln 发表于2006-09-21 16:21:00  IP: 218.24.136.*
    帅,你就是我偶像
    #User 发表于2006-09-22 11:51:00  IP: 219.238.164.*
    学习:
    我如果有如下:
    // System.Data.SqlClient.SqlConnection m_conn = null;
    // m_conn = new System.Data.SqlClient.SqlConnection();
    // m_conn.ConnectionString = "Data Source=192.168.0.1; Initial Catalog=MaxData; User Id=sa; Password=123456;";
    // m_conn.Open();
    通过进度条来显示速度,该放到您的代码的什么位置呢?
    #knight94 发表于2006-09-22 12:13:00  IP: 218.71.239.*
    to user

    对于你所说的,并不是很好控制,因为对于connection的open操作,你无法判断要用多少时间,因此进度条的信息只能是模拟,无法去精确控制。

    线程中大致如下:
    //打开进度条窗体

    //用begininvoke去触发窗体来打开connection

    while( !blnFinished )
    {
    //按照一定步频修改进度条

    Thread.Sleep( 20 );
    }

    //关闭进度条窗体

    以上是在线程函数中进行的操作。

    那么对于连接可以如下:
    private bool blnFinished = false;
    private void ConnectDB()
    {
    //Open connection here

    blnFinished = true;//Set signal here
    }
    #User 发表于2006-10-11 18:39:00  IP: 219.238.164.*
    那么对于从数据库检索数据,能否用进度条来控制呢?
    #knight94 发表于2006-10-11 18:44:00  IP: 218.71.239.*
    to User

    如果是用DataAdapter.Fill的话,很难在进度条上体现;
    如果是用DataReader来逐条读取的话,是可以的。
    #yanam 发表于2006-10-13 16:56:00  IP: 202.105.139.*
    IncreaseHandle myIncrease = new IncreaseHandle(myProcessBar.Increase);

    为何我在这个地方会提示
    实例方法的委托不能具有空“this”。

    我用的是。net2.0
    #knight94 发表于2006-10-13 18:34:00  IP: 218.71.239.*
    to yanam

    我试了一下,并没有发生类似的问题。

    而且这点儿来说,1.1和2.0没有区别。
    #Jason_mf 发表于2006-10-14 16:57:00  IP: 222.191.180.*
    private void ThreadFun()中的
    object objReturn = null是什么?
    #knight94 发表于2006-10-14 19:11:00  IP: 218.71.239.*
    to Jason_mf

    我的例子中使用的Delegate是有返回值的,而返回值需要通过Object才能接收。

    所以objReturn是接收委托函数返回值用的。
    #zyc21st 发表于2006-10-22 08:15:00  IP: 202.136.63.*
    我将启动线程的语句
    Thread thdSub = new Thread( new ThreadStart( ThreadFun ) );
    thdSub.Start();
    放在主窗体的一个方法体中执行,thdSub.Start();后面还有其他的语句,为什么必须该方法执行完后,进度条窗体才能启动?
    不能执行完thdSub.Start();就启动进度条窗体?

    #knight94 发表于2006-10-22 09:49:00  IP: 218.71.239.*
    to zyc21st

    你如果想在thdSub.Start()后立刻开启线程,可以在之后先加上
    Thread.Sleep(20);//Run sub-thread
    即可。
    #zyc21st 发表于2006-10-22 10:53:00  IP: 202.136.63.*
    我现在想实现这样一个效果:
    在主窗口中点击按钮Download一个文件,并打开进度条等待
    private void button1_Click(object sender, System.EventArgs e)
    {
    Thread thdSub = new Thread( new ThreadStart( ThreadFun ) );
    thdSub.Start();
    Thread.Sleep(20);
    ftp.Download();
    }
    现在好像必须ftp.Download();执行完成之后,进度窗体才能显示,我现在想thdSub.Start();之后进度窗体显示,进度条开始滚动,同时主窗体在执行ftp.Download();下载文件,这个地方应该怎么写?谢谢你了
    #knight94 发表于2006-10-31 12:54:00  IP: 218.71.239.*
    to webber

    你如何写的,
    这里需要注意两点,
    1、如果窗体用ShowDialog打开,不要用Invoke,而要用BeginInvoke;
    2、如果窗体用Show打开,不要把窗体定义为局部变量,把它改成成员。
    #webber 发表于2006-10-31 11:48:00  IP: 222.66.77.*
    我在调用ShowProcessBar()的时候用的是Invoke方法(自己写了一个委托),但是当弹出进度条窗体的时候就没有反应了,因为什么啊?

    #webber 发表于2006-10-31 13:37:00  IP: 222.66.77.*
    谢谢您,还有一个问题。BeginInvoke中的的委托是必须是MethodInvoker的吗?
    #yanam 发表于2006-10-31 13:31:00  IP: 202.105.139.*
    我调用的时候有时很正常的运行,但是有时弹出这个窗口就整个程序都没反应了,这是怎么回事啊?

    #knight94 发表于2006-11-01 10:22:00  IP: 218.71.239.*
    to yanam

    仔细检查你的程序,以我的程序进行参考,对比细节处,是否处理正确。

    to webber

    不一定是MethodInvoker,Invoke或者BeginInvoke只是执行一个委托函数而已,并不要求委托函数类型具体是什么,这方面你可以参看
    http://blog.csdn.net/Knight94/archive/2006/08/24/1111267.aspx
    #yanam 发表于2006-11-02 15:04:00  IP: 202.105.139.*
    knight94 你好,这个进度条我是这样调用的

    private void ShareSelect_Load(object sender, EventArgs e)
    {
    Thread thdSub = new Thread(new ThreadStart(ThreadFun));
    thdSub.Start();
    initData();//填充datagrid
    }
    如果用线程调用initdata,会出错,如何才能initdata完成就进度条完成100关闭呢?

    谢谢,刚学c#,很多东西不熟悉
    #knight94 发表于2006-11-02 17:05:00  IP: 218.71.239.*
    to yanam

    如果比较正确地完成你的功能,需要把initData这个函数放到线程中去做,并写在初始化datagrid时候,动态改变进度条的值。

    那么其中涉及到的invoke或者begininvoke有三个方面
    1、进度条的窗体模态显示;
    2、进度条的变动;
    3、datagrid的操作。

    那么这些都可以参照我给的方法去完成即可。
    #vessel 发表于2006-11-13 11:11:00  IP: 220.184.66.*
    knight94

    你好,我想实现调用一个dll函数,这个函数调用会占比较长的时间,所以显示进度条。
    希望效果:
    开始调用该函数时显示进度条窗体,并不断让进度条滚动,函数调用好后关闭进度条窗体,由于不能确定函数调用时间,把进度条style设成Marquee就可以了。

    具体该怎么做?谢谢!
    #knight94 发表于2006-11-13 15:26:00  IP: 218.71.239.*
    to vessel

    文章控制进度条的显示是在“ThreadFun”这个函数中,那么你可以对它进行扩展,让调用函数和进度条的显示进行同步。
    #zhouxiaoming 发表于2008-03-14 15:33:03  IP: 222.240.167.*
    hi,你好
    我还是没搞好,请帮我看看啊。

    具体如下:

    一个费时的操作A,在执行的时候会自动弹出几个窗体;
    一个记录操作A进度的全局变量i,用来显示执行进度;

    method A()
    {
    ...
    Thread thdSub = new Thread(new ThreadStart(ThreadFun));
    thdSub.Start();

    ...(省略的用method B表示吧)
    }

    method B()
    {
    ...
    i++;
    ...
    }

    //显示进度
    private void ThreadFun()
    {
    MethodInvoker mi = new MethodInvoker(ShowProcessBar);
    this.BeginInvoke(mi);

    //Thread.Sleep( 500 );//Sleep a while to show window

    bool blnIncreased = false;
    object objReturn = null;
    do
    {
    Thread.Sleep( 50 );
    objReturn = this.Invoke( this.myIncrease,
    new object[] { methodC(i) });//methodC()为关于i的的函数,用来显示进度
    blnIncreased = (bool)objReturn ;
    }
    while( blnIncreased );
    }

    正如你所说,Invoke调用要等待方法A结束才开始,也就是方法B结束,这样ThreadFun没有执行也就不能实时的反映进度了,请问怎样解决。

    谢谢!
    #zhouxiaoming 发表于2008-03-14 15:36:32  IP: 222.240.167.*
    我刚刚发了一遍了啊,呵呵。也就如何同步的问题?我把Invoke改成BeginInvoke就有错误发生,真的不知道怎么弄了。

    拜谢解答如何同步!!!
    #csppqiuyx 发表于2008-05-23 11:59:16  IP: 218.4.61.*
    感谢了,
    #zhmvb 发表于2008-05-25 22:09:54  IP: 58.30.94.*
    偶像,能不能把完整的代码给我发一份?zhmvb@tom.com
    谢谢了!
    #gengxin_914 发表于2008-07-07 21:43:43  IP: 58.241.135.*
    如果想用代码来关闭该等待窗口该怎么实现啊,比如:
    Thread thdSub = new Thread( new ThreadStart( ThreadFun ) );
    thdSub.Start();
    //执行长时间等待的函数,执行时间不确定
    //函数执行完毕后自动关闭等待窗口
    #gengxin_914 发表于2008-07-14 15:22:26  IP: 218.91.32.*
    如果我想通过代码提前将等待窗口关闭,那用代码该怎么写啊?
    #zhenqiyi 发表于2008-07-23 23:00:26  IP: 221.237.19.*
    我是个菜鸟,第一次做DLL,我是做了一个带界面的DLL,ASP.NET里调用它的,就是说在网页里点下按钮打开DLL里的那个页面,在这个页面里有一个打开文件的按钮,按这个就会报错:在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常。
    具体线程什么的我不懂啊,代码是这样的,大师有空帮我看看哈:
    在ASP.NET里:
    protected void OKADD_Click(object sender, EventArgs e)
    {//testExcelToOracle是我的DLL的NAMESPACE
    testExcelToOracle.Form1 TESTadd = new testExcelToOracle.Form1 ();
    TESTadd.ShowDialog ();
    }
    DLL的FORM1里:
    private void openExcel_Click(object sender, EventArgs e)
    {
    OpenFileDialog openFileDialog = new OpenFileDialog();
    openFileDialog.InitialDirectory = "c:\\";//注意这里写路径时要用c:\\而不是c:\
    // openFileDialog.Filter="文本文件|*.*|Excel文件|*.xls|C#文件|*.cs|所有文件|*.*";
    openFileDialog.Filter = "Excel文件|*.xls";
    openFileDialog.RestoreDirectory = true;
    openFileDialog.Title = "打开文件";
    openFileDialog.FilterIndex = 1;
    //在这里报错的。。
    if (openFileDialog.ShowDialog() == DialogResult.OK )
    。。。。。。

    }
    万分感谢!!!
    #zhenqiyi 发表于2008-07-23 23:00:39  IP: 221.237.19.*
    我是个菜鸟,第一次做DLL,我是做了一个带界面的DLL,ASP.NET里调用它的,就是说在网页里点下按钮打开DLL里的那个页面,在这个页面里有一个打开文件的按钮,按这个就会报错:在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常。
    具体线程什么的我不懂啊,代码是这样的,大师有空帮我看看哈:
    在ASP.NET里:
    protected void OKADD_Click(object sender, EventArgs e)
    {//testExcelToOracle是我的DLL的NAMESPACE
    testExcelToOracle.Form1 TESTadd = new testExcelToOracle.Form1 ();
    TESTadd.ShowDialog ();
    }
    DLL的FORM1里:
    private void openExcel_Click(object sender, EventArgs e)
    {
    OpenFileDialog openFileDialog = new OpenFileDialog();
    openFileDialog.InitialDirectory = "c:\\";//注意这里写路径时要用c:\\而不是c:\
    // openFileDialog.Filter="文本文件|*.*|Excel文件|*.xls|C#文件|*.cs|所有文件|*.*";
    openFileDialog.Filter = "Excel文件|*.xls";
    openFileDialog.RestoreDirectory = true;
    openFileDialog.Title = "打开文件";
    openFileDialog.FilterIndex = 1;
    //在这里报错的。。
    if (openFileDialog.ShowDialog() == DialogResult.OK )
    。。。。。。

    }
    万分感谢!!!
    #No4000 发表于2008-08-19 11:07:49  IP: 218.65.218.*
    按你所做的, 我复制代码也不成功,为何显示数据后才出现窗体?
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © Knight94