分享
 
 
 

程序进度指示的设计

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

程序进度指示的设计

动机:

我常常需要写一些很费时的算法函数。为了不让用户失去耐心,我需要一个进程条来指示程序运行的进度。然而算法函数是写在一个界面无关的模块里,我不可能把具体进程条的类暴露给它。算法函数也很少是一个简单的循环,它通常要调一些子函数,有些子函数也非常的费时。如果我让用户等了n分钟然后告诉用户程序运行了**%,那我给出进程条的意义就不大了,我需要实现均匀的进度指示。

接口:

通常进程条的实现是在界面模块里,为了不将具体进程条的类暴露给算法模块,我将进程条定义成下面的接口。

struct IProgress{

virtual void operator += (float r)=0;

virtual void operator =(const char* str)=0;

virtual bool operator!()const=0;

};

接口中各个函数意义如下:

一:+=操作符用来告诉用户程序前进了r。这里我们约定整个程序运行完算前进了100。

二:=操作符用来给出一些程序正在做什么事情的信息。

三:! 操作符用来告诉算法函数,用户是否取消了此项任务。

界面模块进程条的类必须实现这个接口,然后把它传给算法模块。由于算法模块只关心这个接口,所以界面模块可以随时改变进程条的风格而不必担心会对算法模块有任何影响。如果界面模块不想显示进程条,只需要简单的传一个空值。

使用:

算法模块接收到IProgress接口后,理论上是可以控制程序进度指示了。不过直接使用IProgress接口很不方便。例如:每次调用IProgress接口之前都需要都要判断一下传入的接口指针是否为空;要实现均匀的进度指示,子函数也必须处理进度条,然而光把IProgress接口传给子函数是不够的,必须传入其它的一些控制参数;最后,我们还要考虑一些必要的优化。所有这些如果直接使用IProgress接口来编码,那种代码会让人觉得很恐怖!

为了方便使用IProgress接口,我们需要一个包装类(假定类名是CProgress)。假定我们有一个名为myfun的暴露给外部模块的函数,它调用了child函数,child是一个简单的循环,占用myfun的70%的时间,myfun自己也有一个循环,占用30%的时间。我们希望能够象下面一样编码:

extern “c” void __declspec(dllexport) myfun(IProgress *Iprg);

void child(CProgress &prg){

for(int i=0; i<10000; ++i){

//do some thing

prg += 0.001;

}

}

void myfun(IProgress *Iprg){

CProgress prg(Iprg);

child( prg(70) );

for(int i=0; i<100; ++i){

//do some thing

prg += 0.03;

}

}

包装:

为了支持类似上面的编码,我们的包装类CProgress至少应该提供下面的公有方法:

class CProgress{

public:

CProgress(IProgress *i);

CProgress(CProgress &);

~CProgress();

void operator += (float r);

void operator =(const char* str);

bool operator!()const;

CProgress operator()(float r);

};

前面三个函数用来构造和析构CProgress对象,接下来三个对应IProgress接口的方法。最后一个函数用来生成子函数需要的进程条对象。CProgress对象应该做下面三个事情:

一:CProgress处理IProgress是否为空这种琐碎的事情。

二:当子函数接受到一个CProgress对象,它不因该考虑自己在主函数中所占的百分比。在它的眼光里,它完全跑完整个CProgress对象。

三:当某个CProgress +=或者()的调用会使得对这个CProgress的进度指示超过100%的时候,CProgress应该截断需要的前进幅度,保证进度指示永远运行在100%范围内。当函数结束的时候,如果进度指示不足100%, CProgress对象的析构函数因该补足需要的进度指示

四:为了不在程序仅仅运行了0.0001%的时候都去调用一下IProgress的+=函数(那样太浪费CPU了)。我们需要CProgress在对IProgress的进度指示前进积累到1%的时候才调用一下IProgress的+=函数。

所有的具体实现请参照原码。下面是给出的实现的原码。最后一个CWinProgress提供一个在主窗口显示程序运行进度的IProgress实现。

// IProgress.h: interface for the IProgress class.

//

//////////////////////////////////////////////////////////////////////

#if !defined(AFX_IPROGRESS_H__1E7FCB82_D541_48DE_8A83_D3E934A23082__INCLUDED_)

#define AFX_IPROGRESS_H__1E7FCB82_D541_48DE_8A83_D3E934A23082__INCLUDED_

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

const float progress_whole = 100;

file://显示程序运行进度的接口

class IProgress

{

public:

file://表示程序前进的进度,整个程序的进度是progress_whole

virtual void operator +=(float)=0;

file://设置当前程序正在干什么的信息

virtual void operator =(const char*)=0;

file://是否取消

virtual bool operator !()const=0;

};

file://这个类包装IProgress方便使用

class CProgress

{

file://这个对象类包装IProgress,实现累计优化

struct proxy{

IProgress* _i;

float _cur,_pre;

proxy(IProgress* i=0):_i(i),_cur(0),_pre(0){}

static int _int(float pre){

return (int)((pre*100)/progress_whole);

}

void operator += (float r){

if( !this || !_i || _int(_pre)==_int(_cur+=r) )

return; file://如果累计不足1%,不递交到IProgress的+=

*_i += _cur-_pre;

_pre = _cur;

}

};

proxy _proxy,*_i;

float _coe,_run;

void operator = (CProgress &p){

_coe = p._coe;

_run = p._run;

_i = p._i;

p._i = 0; file://为了不让p析构的时候重复补足

}

CProgress(proxy *i,float coe)

:_i(i),_coe(coe),_run(0){

}

public:

CProgress(IProgress *i)

:_proxy(i),_coe(1),_run(0){

_i = i? &_proxy:0;

}

CProgress(CProgress &p){

operator = (p);

}

~CProgress(){

*_i += _coe*(progress_whole-_run); file://补足未跑完的部分

}

file://构造子函数的运行指示器

CProgress operator () (float r){

if( _run+r>progress_whole )

r = progress_whole-_run;

_run += r;

return CProgress(_i,_coe*r/progress_whole);

}

file://设置程序运行进度

void operator += (float r){

if( !_i )

return;

if( _run+r>progress_whole )

r = progress_whole-_run;

_run += r;

*_i += r*_coe;

}

file://设置程序运行信息

void operator = (const char *info){

if(_i && _i->_i)

*(_i->_i) = info;

}

file://是否取消

bool operator !()const{

return (_i && _i->_i) ? !*(_i->_i):false;

}

};

#ifdef __AFXWIN_H__

class CWinProgress :public IProgress

{

CString _old;

CString _info;

float _run;

CWnd *_pWnd;

public:

CWinProgress(CWnd *pWnd=AfxGetMainWnd()):

_pWnd(pWnd),_run(0){

if(_pWnd)

_pWnd->GetWindowText(_old);

}

~CWinProgress(){

if(_pWnd)

_pWnd->SetWindowText(_old);

}

void operator = (const char *info){

_info = info;

}

bool operator !()const{

return false;

}

void operator +=(float r){

CString str;

str.Format("%d%% ",(int)(100*(_run+=r)/progress_whole) );

if(_pWnd)

_pWnd->SetWindowText(str+_info);

}

};

#endif

#endif // !defined(AFX_IPROGRESS_H__1E7FCB82_D541_48DE_8A83_D3E934A23082__INCLUDED_)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有