首页 > 代码库 > [wxWidgets]_[初级]_[常见更新进度条的方案]

[wxWidgets]_[初级]_[常见更新进度条的方案]


场景:

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


[wxWidgets]_[初级]_[常见更新进度条的方案]