学习心得:控件之进度条(在程序的状态栏中实现进度条)

转载 2007年09月16日 13:47:00

  一、实现方法

  虽然Visual C++中的MFC类提供了标准的进度指示器控件(progress control),但是我们不能在状态栏里直接使用这个控件,要解决这个问题,可以创建一个可重用C++类CProgStatusBar,这个类从CStatusBar派生,用来来实现状态条中的进度指示。整个实现过程不是很难,思路是在状态栏创建一个进度指示器控制,把它作为子窗口来对待,然后根据不同的状态来显示或者隐藏进度指示器。

  在具体实现CProgStatusBar类的过程中,首先在CProgStatusBar派生类中加了一个CProgressCtrl类型的数据成员--m_wndProgBar,然后重载CstatusBar类的二个重要成员函数:OnCreate()、OnSize(),最后还要在该类中添加一个自定义成员函数OnProgress()。在上述三个函数中, OnCreate()负责在状态栏第一次被创建时接收控制,继而创建进度指示器并将它初始化为一个子窗口,它的实现代码如下:

int CProgStatusBar::OnCreate(LPCREATESTRUCT lpcs)
{
 lpcs->style |= WS_CLIPCHILDREN;
 VERIFY(CStatusBar::OnCreate(lpcs)==0);
 VERIFY(m_wndProgBar.Create(WS_CHILD, CRect(), this, 1));
 m_wndProgBar.SetRange(0,100);
 return 0;
}

  OnCreate()函数在状态栏的式样中加了一个WS_CLIPCHILDREN,它告诉Windows不要绘制子窗口以下的状态栏区域,这样可以减少屏幕闪烁。接着OnCreate()函数创建进度指示器控件并将它的范围设置成[0,100]。注意在这里创建进度指示器控件时没有用WS_VISIBLE,因为我们要实现的目标是仅仅当装载文件时进度条才显现,其余时间内应用程序都隐藏它。

  熟悉Windows编程的人都清楚,无论何时,只要在某个窗口里添加子窗口,那么一定要负责管理它的大小尺寸,也就是说,当父窗口大小改变后,子窗口的大小也要跟着作相应的改变。一般来说,这个工作由父窗口的WM_SIZE消息处理函数OnSize()来作,所以我们也要处理该类的OnSize()函数。

void CProgStatusBar::OnSize(...)
{
 CStatusBar::OnSize(...);
 CRect rc;
 GetItemRect(0, &rc);//获取状态条的第一个窗口的尺寸;
 m_wndProgBar.MoveWindow(&rc,FALSE);//移动进度条到状态条的第一个窗口;
}


  从上述代码可以看出,CProgStatusBar::OnSize()将进度指示器放在了状态栏的第一个窗格,这个窗格通常用来显示程序的"就绪"信息和命令提示信息。注意这里不论进度指示器是处于可见状态还是隐藏状态,MoveWindow都照样起作用--所以即便是进度指示器处于隐藏状态,其窗口大小同样是可调的。

  调整好进度指示器的窗口大小后,下面要作的就是进度指示器的显示,进度指示器当前进度状态的显示在CProgStatusBar::OnProgress中完成。它有一个类型为UINT的入口参数:参数值的范围从0到100,表示进度百分比,0表示进度没开始,100表示全部完成。如果这个参数的值大于0,则OnProgress显示进度控制并设置指示器的位置;如果参数值等于0,则 OnProgress隐藏进度控制。

  虽然子窗口控件通常都是放在父窗口能绘制的区域的最上面,但这样做在绘制方面是有一定风险的。在隐藏/显示进度控制时尤其如此,这时候会出现两个问题:第一,因为进度指示器显示在状态栏的第一个窗格位置,所以如果进度条指示器显示时已经显示有状态信息,那么进度指示器和状态信息文本就会有冲突,相互干扰。之所以会这样,是因为进度控制假设其绘制背景是干净的,并且只绘制进度控制的着色部分。解决这个问题最简单的方法是调用CStatusBar::SetWindowText(NULL)函数在显示进度指示器之前打扫一下环境卫生,清除以前的文本。

  对于状态栏来说,SetWindowText函数的作用是设置状态栏第一个窗格的文本。反之,当调用OnProgress(0)清除进度控制时也存在类似的问题,CProgStatusBar::OnProgress 隐藏进度控制后,状态栏第一个窗格该显示什么信息呢?一般显示"就绪"或其它的提示信息。当应用程序不做任何事情时,MFC程序总是在这个位置显示资源串AFX_IDS_IDLEMESSAGE表示的文本,其缺省值为"就绪",当然读者朋友们可以在当前项目的RC文件中任意修改这个值,不管怎样,在MFC程序的状态栏中显示"就绪"信息很容易,需要作的就是在CProgStatusBar::OnProgress()函数中调用语句GetParent()->PostMessage(WM_SETMESSAGESTRING,AFX_IDS_IDLEMESSAGE)向父窗口发送一个WM_SETMESSAGESTRING消息就可以了,需要注意的是,使用消息WM_SETMESSAGESTRING时必须包含它的定义文件"afxpriv.h",否则程序会报告编译错误。

  上述CprogStatusBar类实现了状态栏中包含进度条控件,该类的使用方法很简单,首先在应用程序的CmainFrame类中用CProgStatusBar代替CStatusBar声明实例,然后在任何想要显示进度控制指示的地方调用CProgStatusBar::OnProgress。本例中定义了一个消息MYWM_PROGRESS,它将进度条当前的进度作为WPARAM参数传递到CProgStatusBar::OnProgress()函数。

  经过上述处理,想要使用进度指示的任何对象都可以通过发送一个消息到主框架来调用状态栏进行进度条的显示。例如,在例子程序中,文档的Serialize()函数在加载文本文件时,利用Sleep()函数仿真耗时加载,每隔150毫秒报告一次进度状态。如果你不想从文档发送Windows消息,可以用MFC的视图更新机制来做。你可以发明一个"暗示"代码以及一个小结构来保存进度百分比数据,并通过向框架发送MYWM_PROGRESS消息调用暗示信息。这是从文档到视图/框架传递进度控制信息的最省事的方式。

二、编程步骤

  1、 启动Visual C++6.0,生成一个单文档应用程序prgsbar,项目的视图类的基类选择CEdit类;

  2、 在程序的Resource.h文件中添加自定义消息的定义:

#define MYWM_PROGRESS (WM_USER+1)

  3、 在程序的主框架窗口CMainFrame类的头文件中声明MYWM_PROGRESS的消息响应函数afx_msg LRESULT OnProgress(WPARAM wp, LPARAM lp),在该类的实现中添加消息映射ON_MESSAGE(MYWM_PROGRESS,OnProgress);

  4、 将CMainFrame类中的工具条对象改为CProgStatusBar m_wndStatusBar;

  5、 重载CPrgsbarDoc::Serialize(CArchive& ar)函数,用来处理读取文件时的进度条仿真;

  6、 添加代码,编译运行程序。

  三、程序代码

////////////////////////////////////////////CprogStatusBar类的头文件;
// Status bar with progress control.
class CProgStatusBar : public CStatusBar {
public:
 CProgStatusBar();
 virtual ~CProgStatusBar();
 CProgressCtrl& GetProgressCtrl() {
  return m_wndProgBar;
 }
 void OnProgress(UINT pct);
protected:
 CProgressCtrl m_wndProgBar; // the progress bar
 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
 afx_msg void OnSize(UINT nType, int cx, int cy);
 DECLARE_MESSAGE_MAP()
 DECLARE_DYNAMIC(CProgStatusBar)
};
///////////////////////////////////////////////////////////////////////////// CprogStatusBar类的实现文件;
#include "StdAfx.h"
#include "ProgBar.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(CProgStatusBar, CStatusBar)
BEGIN_MESSAGE_MAP(CProgStatusBar, CStatusBar)
ON_WM_CREATE()
ON_WM_SIZE()
END_MESSAGE_MAP()
////////////////////////////////////////////////////////////////
CProgStatusBar::CProgStatusBar()
{}
CProgStatusBar::~CProgStatusBar()
{}
////////////////////////////////////////创建状态条时也创建进程条
int CProgStatusBar::OnCreate(LPCREATESTRUCT lpcs)
{
 lpcs->style |= WS_CLIPCHILDREN;
 VERIFY(CStatusBar::OnCreate(lpcs)==0);
 VERIFY(m_wndProgBar.Create(WS_CHILD, CRect(), this, 1));
 m_wndProgBar.SetRange(0,100); //设置进程条的范围;
 return 0;
}
////////////////////////////////////////////////////使进程度条的尺寸与状态条的尺寸同步变化;
void CProgStatusBar::OnSize(UINT nType, int cx, int cy)
{
 CStatusBar::OnSize(nType, cx, cy);
 CRect rc;
 GetItemRect(0, &rc);
 m_wndProgBar.MoveWindow(&rc,FALSE);
}
////////////////////////////////////////////////////////////根据pct的当前值对进程条进行设置
void CProgStatusBar::OnProgress(UINT pct)
{
 CProgressCtrl& pc = m_wndProgBar;
 DWORD dwOldStyle = pc.GetStyle();
 DWORD dwNewStyle = dwOldStyle;
 if (pct>0) //如果pct>0,将显示进度条
  dwNewStyle |= WS_VISIBLE;
 else //否则隐藏进度条;
  dwNewStyle &= ~WS_VISIBLE;
  if (dwNewStyle != dwOldStyle) {
   SetWindowText(NULL); //显示进度条前清空状态条;
   SetWindowLong(pc.m_hWnd, GWL_STYLE, dwNewStyle);
   //设置进度条处于显示状态;
  }
  // 设置进度条的当前位置;
  pc.SetPos(pct);
  if (pct==0)
   // 如果pct等于0,通知主框架窗口显示空闲信息;
   GetParent()->PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
 }
 /////////////////////////////////////////////////////////////////////////文档装载处理函数;
 void CPrgsbarDoc::Serialize(CArchive& ar)
 {
  CWnd* pFrame = AfxGetMainWnd();
  if (!ar.IsStoring()) {
   for (int pct=10; pct<=100; pct+=10) {//对文档装载进行仿真处理;
    Sleep(150);
    if (pFrame)
     pFrame->SendMessage(MYWM_PROGRESS, pct);
   }
  }
  if (pFrame)
   pFrame->SendMessage(MYWM_PROGRESS, 0);
   ((CEditView*)m_viewList.GetHead())->SerializeRaw(ar);//显示文本文件的内容;
}
 

C#语言操作Win7系统任务栏(TaskBar)中程序图标的背景进度条

C#语言操作Win7系统任务栏(TaskBar)中程序图标的背景进度条  收藏 北风其凉   发表于 11个月前 阅读 266 收藏 1 点赞 0 评论 0 ...
  • mosangbike
  • mosangbike
  • 2017年06月21日 16:17
  • 159

在状态栏中加载进度条

C技巧:在程序的状态栏中实现进度条 读者朋友们可能天天使用Visual 这个强大的工具来应用程序,不知道注意到没有,Visual 每次装载一个项目的时候,为了使项目加载过程不至于太单调,会在状态...
  • liqing19850102
  • liqing19850102
  • 2012年06月01日 06:57
  • 4888

状态栏中实现进度条

一、MainFrame中的OnPaint()函数中 void CMainFrame::OnPaint()  { CPaintDC dc(this); CRect rect; m_wn...
  • aristolto
  • aristolto
  • 2011年07月20日 10:39
  • 458

自己编写vb进度条控件

主程序代码:Option ExplicitDim i As DoublePrivate Sub Command1_Click() i = 0 Timer1.Enabled = TrueEn...
  • sysdzw
  • sysdzw
  • 2009年10月09日 15:55
  • 5472

【Android开发学习27】界面控件之进度条(ProgressBar)

一、基础知识:   1.ProgressBar在界面文件XML中的布局:
  • ypist
  • ypist
  • 2013年03月16日 10:04
  • 19789

Android自定义控件:进度条的四种实现方式

Progress Wheel为GitHub热门项目,作者是:Todd-Davies,项目地址: https://github.com/Todd-Davies/ProgressWheel 前三...
  • dianyueneo
  • dianyueneo
  • 2015年03月20日 17:31
  • 3535

【Qt开发】Qt控件之进度条

QT 进度条操作实例是本文要介绍的内容,在QT中可以用QProgressBar或着QProgressDialog来实现进度条。 QProgressBar的使用    首先在designer中...
  • LG1259156776
  • LG1259156776
  • 2016年09月09日 09:30
  • 2152

MFC在状态栏中使用进度条控件

在MFC中把进度条放到状态栏中使用,就这么简单!
  • baidu_24190413
  • baidu_24190413
  • 2017年03月15日 20:04
  • 416

Java 进度条控件的使用

利用JProcessBar类可以实现一个进度条,它本身不过是一个矩形控件,通过填充它的部分或全部来指示一个任务的执行情况,可以放置到一个新的线程中运行。 示例如下:...
  • kehyuanyu
  • kehyuanyu
  • 2014年05月19日 17:44
  • 9040

利用JS实现动态进度条效果

效果:实现一个每隔一秒进度增加1%,到100%停止的进度条,不同的进度改变进度条的颜色。 一、利用HTML+CSS进行页面布局 注意:1.将进度条变化区域宽度(width)设置为0,再设置一个背景颜色...
  • Qianqianliuliu
  • Qianqianliuliu
  • 2017年10月27日 19:51
  • 848
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:学习心得:控件之进度条(在程序的状态栏中实现进度条)
举报原因:
原因补充:

(最多只允许输入30个字)