科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件VC实现在状态栏中加入进度指示器

VC实现在状态栏中加入进度指示器

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

我最近作了一个C /MFC程序,这个程序有时要加载大容量文件,为了让文件加载过程不至于太单调。

作者:NorthTibet 来源:vckbase 2007年10月19日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
无论何时,只要你在某个窗口里添加子窗口,那么一定要负责管理它的大小尺寸,也就是说,当父窗口大小改变后,子窗口的大小也要跟着作相应的改变。一般来说,这个工作在父窗口的WM_SIZE/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函数中
// WM_SETMESSAGESTRING 的定义在<afxpriv.h>文件
GetParent()->PostMessage(WM_SETMESSAGESTRING,AFX_IDS_IDLEMESSAGE);

  如果你愿意,完全可以创建不同的ID和消息,如用ID_DONE_LOADING表示“加载完成”,以此取代“就绪”。

  CProgStatusBar实现了含有进度控制的状态栏。它的使用方法很简单:用CProgStatusBar代替CStatusBar声明实例,然后在任何想要显示进度控制指示的地方调用CProgStatusBar::OnProgress。详细代码请参考本文例子程序。创建CProgStatusBar很容易,它的原理与标准的状态栏CStatusBar一样——你只要明白什么时候以及在哪里调用OnProgress即可。

  实际应用中要根据你的应用而定。我建议你按照例子程序的方法来使用它。不要直接暴露CProgStatusBar::OnProgress函数,例子程序的主窗口实现了一个特殊的消息——MYWM_PROGRESS,它将WPARAM传递到CProgStatusBar::OnProgress:

// MYWM_PROGRESS 在resource.h文件中定义
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_MESSAGE(MYWM_PROGRESS,OnProgress)
END_MESSAGE_MAP()

// 处理MYWM_PROGRESS消息
LRESULT CMainFrame::OnProgress(WPARAM wp, LPARAM lp)
{
m_wndStatusBar.OnProgress(wp);
return 0;
}

  这样想要报告进度指示的任何对象都可以通过发送一个消息到主框架来代替直接对状态栏进行调用。例如,在例子程序中,文档的Serialize函数利用Sleep函数仿真耗时加载,每隔150毫秒报告一次进度状态。通常,你肯定想让文档这样的低级对象尽可能少地包含UI代码。虽然在实践中很少有程序员遵守这一原则,但最好不用UI操作你的文档类,因为你很可能有一天想在某个服务中或命令行程序中使用它。不管怎么说,发送消息到框架总比暴露框架的内部成员要好得多。

  为了安全起见,文档的Serialize函数在发送消息前最好检查一下框架是否存在。如果你不想从文档发送Windows消息,可以用MFC的视图更新机制来做。你可以发明一个“暗示”代码以及一个小结构来保存进度百分比数据,并通过向框架发送MYWM_PROGRESS消息调用暗示信息。这是从文档到视图/框架传递进度控制信息的最省事的方式。

  CProgStatusBar假设你报告的进度指示数据总是0到100的整数,并且假设你中途可以中断进度指示器。以便你在想要改变设置的时候,可以修改CProgStatusBar或者调用CProgStatusBar::GetProgressCtrl来直接存取进度控制状态。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章