场景:
1. 很多程序需要根据处理业务的进度来更新进度条,进度条的目的是让用户能知道业务处理的进度,有进度条的程序更友好,让用户知道程序在运行,而不是没有响应。
2. 现在更新进度条的见过两种方法,一种是通过事件(信号,队列)的发送让主线程按照发送的顺序来更新进度条,一种是设置一个全局整形变量,
通过运行定时器的方式来更新进度条。第一种不适合在更新频率比较高的地方,比如一秒钟发送了20个事件,这样会造成主线程忙于处理事件界面出现假死状态。
所以最好的办法就是使用第2种通过定时器更新进度条,设置一个合理的值,比如500毫秒这样既能看到更新的进度,也不会让主线程过于忙。
3. 这里用wxWidgets做例子,其实mfc,wtl,cocoa都是一样的。
部分代码:
my_thread.cpp
#include "domain/my_thread.h"
#include "window/my_frame.h"
wxThread::ExitCode MyThread::Entry()
{
Sleep(500);
int i = 1;
while (!TestDestroy() && i <= 100)
{
if(type_)
{
//第一种方法,发事件更新进度条,注意,不能直接更新进度条控件,因为非主线程不能更新控件
wxCommandEvent* evt = new wxCommandEvent(wxEVT_COMMAND_MYTHREAD_UPDATE);
evt->SetInt(i);
wxQueueEvent(m_pHandler->GetEventHandler(), evt);
}else
{
//第二种方法,直接更新MyFrame里的Int成员变量,然会wxTimer会根据这个值自动更新进度条控件.
m_pHandler->progress_value_ = i;
Sleep(200);
}
++i;
}
//1.最后这个其实还是必要的,告诉wxTimer可以结束了。总之就是通知界面工作任务已经完成,你自己做该做的事。
wxQueueEvent(m_pHandler->GetEventHandler(), new wxCommandEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));
return (wxThread::ExitCode)0;
}
my_frame.cpp
#include "window/my_frame.h"
#include "wx/xrc/xmlres.h"
#include <iostream>
#include "domain/my_thread.h"
using namespace std;
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_COMPLETED, MyFrame::OnThreadCompletion)
EVT_TIMER(wxID_ANY,MyFrame::OnTimer)
END_EVENT_TABLE()
wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent);
wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);
void MyFrame::Init()
{
gauge_ = XRCCTRL(*this, "m_gauge1", wxGauge);
event_update_button_ = XRCCTRL(*this, "m_button1", wxButton);
event_update_button_->Bind(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(MyFrame::OnEventUpdate), this, XRCID("m_button1"));
timer_update_button_ = XRCCTRL(*this, "m_button3", wxButton);
timer_update_button_->Bind(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(MyFrame::OnTimerUpdate), this, XRCID("m_button3"));
timer.SetOwner(this->GetEventHandler());
}
MyFrame::MyFrame(wxWindow* parent)
{
progress_value_ = 0;
}
MyFrame::~MyFrame()
{
}
void MyFrame::OnThreadUpdate(wxCommandEvent& evt)
{
cout << "OnThreadUpdate" << endl;
gauge_->SetValue(evt.GetInt());
}
void MyFrame::OnThreadCompletion(wxCommandEvent&)
{
cout << "OnThreadCompletion" << endl;
if(!type_)
{
timer.Stop();
gauge_->SetValue(progress_value_);
}
timer_update_button_->Enable();
event_update_button_->Enable();
}
void MyFrame::OnTimer(wxTimerEvent&)
{
cout << "OnTimer" << endl;
gauge_->SetValue(progress_value_);
}
void MyFrame::DoTask(bool type)
{
timer_update_button_->Enable(false);
event_update_button_->Enable(false);
MyThread *m_pThread = new MyThread(type,this);
if ( m_pThread->Run() != wxTHREAD_NO_ERROR )
{
cout << "Can't create the thread!: " << type << endl;
delete m_pThread;
m_pThread = NULL;
}
}
void MyFrame::OnTimerUpdate(wxCommandEvent& evt)
{
cout << "OnTimerUpdate" << endl;
gauge_->SetValue(0);
progress_value_ = 0;
type_ = false;
timer.Start(500);
DoTask(type_);
}
void MyFrame::OnEventUpdate(wxCommandEvent& evt)
{
cout << "OnEventUpdate" << endl;
gauge_->SetValue(0);
progress_value_ = 0;
type_ = true;
DoTask(type_);
}
gui.cpp
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/xrc/xmlres.h"
#include <assert.h>
#include <iostream>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include "wx/listctrl.h"
#include "wx/grid.h"
#include "wx/event.h"
#include "window/my_frame.h"
using namespace std;
static void OpenConsole()
{
AllocConsole();
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
int hCrt = _open_osfhandle((long)handle,_O_TEXT);
FILE * hf = _fdopen( hCrt, "w" );
*stdout = *hf;
}
static wxString GetAppRunDirectory()
{
wxString directory(wxTheApp->argv[0]);
directory.Replace(wxT("\\"), wxT("/"));
wxString str = directory.BeforeLast('/');
if(str.IsEmpty())
{
return wxT(".");
}
return directory.BeforeLast('/');
}
static wxString GetInstallDirectory()
{
wxString directory = GetAppRunDirectory();
#ifdef __QXWIN32__
return directory.BeforeLast('/');
#else
return directory;
#endif
}
class MyApp : public wxApp
{
public:
virtual bool OnInit();
virtual int OnExit();
};
IMPLEMENT_APP(MyApp)
// 'Main program' equivalent: the program execution "starts" here
bool MyApp::OnInit()
{
if (!wxApp::OnInit())
{
return false;
}
OpenConsole();
wxInitAllImageHandlers();
wxXmlResource::Get()->InitAllHandlers();
wxString ui_dir = GetInstallDirectory()+wxT("/Themes");
wxXmlResource::Get()->LoadAllFiles(ui_dir);
MyFrame *frame = new MyFrame(NULL);
bool loaded = wxXmlResource::Get()->LoadFrame(frame, NULL, "MyFrame1");
assert(loaded);
frame->Init();
frame->Show(true);
return true;
}
int MyApp::OnExit()
{
return 0;
}
截图:
完整代码下载地址:
http://download.csdn.net/detail/infoworld/8105011