进度条卡死或卡顿现象的改进

来源:互联网 发布:网络大电影演员成本 编辑:程序博客网 时间:2024/04/26 14:37

        首先说明本帖是C++语言写的,其他语言可以参照。
        一般情况下,进度条容易出现卡顿或者卡死现象,是由于控制进度条的显示和代码的计算处于同一线程下,线程同时处理时就容易出错;我们的改进思路就是用多线程单独创建一个线程专门用来控制进度条的显示,让进度条控制与代码计算分开了管理从而解决问题。
        以下的“~”都是指你创建工程时你自己定义的工程名; 

1.在主入口文件的“~.h”文件中添加一个函数声明:

LPVOID AfxGetProgressWnd();    //该函数主要用于后期调用时获得指向进度条窗口的指针; 

2.在主入口文件的“~.cpp”文件中添加上述函数的实现部分,顺便再添加一个全局变量“LPVOID G_ProgressWnd”用来存放进度条窗口指针,以及后边需要用到的多线程函数的内容“VOID CreateProgressDlg(); 

LPVOID G_ProgressWnd;            //定义一个全局变量用于创建进度条窗口后存放其指针;  

LPVOID AfxGetProgressWnd()    //该函数主要用于后期调用时获得指向进度条窗口的指针;

        return G_ProgressWnd;
}

VOID CreateProgressDlg()         //创建多线程时调用的多线程函数;

       ~Dlg dlg;                                  // ~”是创建工程
       dlg.DoModal();                        //时你自己定义的工程名;
}  

3.依然在在主入口文件的“~.cpp”文件中对应函数下添加如下内容:
BOOL ~App::InitInstance()

        ... 
       CWinApp::InitInstance(); 
        ... 
       //~Dlg dlg;                                 //如果创建对话框工程时自动生成了该部分(即自动显示对话框),
       //m_pMainWnd = &dlg;          //可先将其注释掉,否则会出现两个窗口;
       //dlg.DoModal(); 
       ...

       //添加的内容:
      AfxBeginThread((AFX_THREADPROC)CreateProgressDlg, 0, THREAD_PRIORITY_NORMAL, 0, 0, NULL);
//创建控制进度条窗口的多线程;
      while(AfxGetProgressWnd() == NULL){ //由于多线程创建进度条窗口需要一定时间,如果创建没有完成而主线程还
              Sleep(100);                                //继续往下走,则在控制进度条的地方有可能会崩溃,所以我们设置一个
     }                                                                            //while”循环来进行等待,只有等待创建完成了,主线程才能继续往下走。
      ... 
 }  

4.当程序走到第3步的多线程时,会调到“CreateProgressDlg()”多线程函数,该函数内部会初始化进度条窗口,这时我们需要将初始化完的窗口指针
传给第2步定义的全局变量;所以我们需要在“~Dlg.cpp”文件中对应函数下添加如下内容: 
extern LPVOID G_ProgressWnd;    // 文件头处添加引用全局变量;  

BOOL ~Dlg::OnInitDialog()

      CDialog::OnInitDialog(); 
      SetIcon(m_hIcon, TRUE);
      SetIcon(m_hIcon, FALSE);
      ... 
      //添加的内容:
      G_ProgressWnd = (LPVOID)this;   // 将初始化完成的进度条窗口指针赋给全局变量;
      ...
}  

5.到这里准备工作就算是完成了,接下来只需要在用到进度条的地方调用第2步的“AfxGetProgressWnd()”函数来获得进度条窗口的指针使用就行了,例: 

//pProCtrl = (CProgressCtrl*) ( (~Dlg*)(AfxGetMainWnd()) )->GetDlgItem(IDC_PROGRESS1);
//pProText = (CStatic*) ( (~Dlg*)(AfxGetMainWnd()) )->GetDlgItem(IDC_STATIC_TEXT);

上边这两条是老的写法(卡顿),这里列出来是做参照的;
下边的是新写法,它将老写法中的系统函数“AfxGetMainWnd()”替换成我们自己写的函数“AfxGetProgressWnd()” ,从而获取到了我们的进度条窗口指针:

CProgressCtrl* pProCtrl = (CProgressCtrl*) ( (~Dlg*)(AfxGetProgressWnd()) )->GetDlgItem(IDC_PROGRESS1);//进度条位置;
CStatic* pProText = (CStatic*) ( (~Dlg*)(AfxGetProgressWnd()) )->GetDlgItem(IDC_STATIC_TEXT); //控制进度条文字;
     pProCtrl->SetRange32(0, 10); // 设置进度条大小是0-10;
     pProCtrl->SetPos(0); // 设置进度条当前位置是0;
     CString cstrText;  //进度条文字.
     cstrText.Format("当前处理 ( 7 / 100");
     pProText->SetWindowText(cstrText); 
     pProCtrl->SetPos(1); // 设置进度条当前位置是1;

以上的“IDC_PROGRESS1”是窗口中添加的进度条控件的ID,“IDC_STATIC_TEXT”是是窗口中添加的描述进度条的文本控件的ID

 

     另外,为了使用方便,也可将“CProgressCtrl* pProCtrl  和“CStatic* pProText  定义成全局变量方便其他文件使用进度条。