广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >MFC框架之OnIdle案例详解
  • 289
分享到

MFC框架之OnIdle案例详解

2024-04-02 19:04:59 289人浏览 薄情痞子
摘要

先看下MSDN对OnIdle()介绍: CWinApp::OnIdle OnIdle is called in the default message loop when

先看下MSDN对OnIdle()介绍:

CWinApp::OnIdle

OnIdle is called in the default message loop when the application's message queue is

empty. Use your override to call your own background idle-handler tasks.

     对于一般桌面应用程序中比较少重载这个函数。对于像是视频游戏这一块确有不少用处。在Win32 SDK的开发环境中,通过在消息循环中添加自已的render()等接口来使自已的程序核心运转起来,这也是常用的一种办法。来到MFC的环境中,保证程序运转的核心循环已经被整合到MFC中去了,这时侯要想将自已的接口函数可以合理的插进MFC的循环结构中,那么这个OnIdle()就是一个非常好的地方,在这儿你可以让你的代码获的足够的运行机会。先看看MSDN中对MFC的程序中Idle状态的处理:

    对CWinApp::OnIdle进行重载,返回非零值代表还有Idle Task任务要处理,这样下次OnIdle()仍然会继续执行。在你重载CWinApp::OnIdle()时,不要忘记要先调用CWinApp::OnIdle()进行MFC默认处理:


if (CWinApp::OnIdle(lCount))
      return TRUE;

如果忘掉了的话,你会发现一些MFC的UI会出现问题,比如菜单上的选择状态无法更新等问题。

 再下面加上你自已的处理函数即可:


YourMethod();
return TRUE; // 需要更多次的执行。。。

    对于MFC程序来讲,很多是采用MFC的文档视图类的框架。比如如果你要让视图不断刷新,在这个不断刷新的视图中可以完成场景渲洒更新等操作。你当然可以在 YourMethod()中获取视图的pView的指针,然后调用其内的接口函数, 就像这样:


CMainFrame *parent = (CMainFrame *)AfxGetMainWnd();
if ( parent && parent->GetSafeHwnd() )
{
    CFrameWnd* pFrame = parent->GetActiveFrame();
    CView *pView = pFrame->GetActiveView();
    if ( pView )
    {
        pView->Invalidate();
    }
}

但这会明显的让你的程序和MFC的框架不那么配套,MFC的文档视图结构的设计思想并没有体现出来。当然这样做也没什么错。类似这样的写法也是可以正常工作的。

     如果你查看过MFC文档类CDocument的话,你会发现它也有一个虚函数叫OnIdle(),很明显这个函数就是让你完成文档视图在Idle时期的处理工作的地方。你完全在其中可以这样写: 


POSITION pos = GetFirstViewPosition();
while ( pos != NULL )
{
  CView* pView = GetNextView( pos );
  pView->Invalidate();
    pView->UpdateWindow();
 }  

通过在文档的OnIdle中进行处理是更合适的地方。但是同样需要在CWinApp::OnIdle重载函数中进行一些处理:


 // In this example, as in most applications, you should let the
 // base class CWinApp::OnIdle complete its processing before you
 // attempt any additional idle loop processing.
 if ( CWinApp::OnIdle(lCount) )
   return TRUE;
CWinAppEx::OnIdle(0);
return TRUE;

你也许会问为什么要加上这句 CWinAppEx::OnIdle(0):加这句的目的其实我是希望调用MFC默认的对文档视图OnIdle的处理,也就是借用下面一段代码:


// call doc-template idle hook
 POSITION pos = NULL;
 if ( m_pDocManager != NULL )
  pos = m_pDocManager->GetFirstDocTemplatePosition();

 while ( pos != NULL )
 {
    CDocTemplate* pTemplate = m_pDocManager->GetNextDocTemplate(pos);
    ASSERT_KINDOF( CDocTemplate, pTemplate );
    pTemplate->OnIdle();
 }

你完全可以用上面的代码代替CWinAppEx::OnIdle(0)这句。

至此关于MFC中OnIdle的使用介绍已经完了。很多具体的东西还是需要深入MFC的具体实现当中去看。

CWinThread::Run是程序生命的"活水源头"(侯捷:《深入浅出MFC》,函数存在于Vc++ 6.0安装目录下提供的THRDCORE.CPP文件中):


// main running routine until thread exits
int CWinThread::Run()
{
 ASSERT_VALID(this);

 // for tracking the idle time state
 BOOL bIdle = TRUE;
 LONG lIdleCount = 0;

 // acquire and dispatch messages until a WM_QUIT message is received.
 for (;;)
 {
  // phase1: check to see if we can do idle work
  while (bIdle && !::PeekMessage(&m_msGCur, NULL, NULL, NULL, PM_NOREMOVE))
  {
   // call OnIdle while in bIdle state
   if (!OnIdle(lIdleCount++))
    bIdle = FALSE; // assume "no idle" state
  }

  // phase2: pump messages while available
  do
  {
   // pump message, but quit on WM_QUIT
   if (!PumpMessage())
    return ExitInstance();

   // reset "no idle" state after pumping "nORMal" message
   if (IsIdleMessage(&m_msgCur))
   {
    bIdle = TRUE;
    lIdleCount = 0;
   }

  } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
 }
 ASSERT(FALSE); // not reachable
}

首先进行PeekMessage()未Peek到并且bIdle为True则进行OnIdle()并且lIdleCount++,完成之后返回一个值,如果要接收更多的空闲处理时间,则返回非零值,bIdle仍旧为true,继续peek,若仍未peek到,则接着OnIdle,此时的lIdleCout为1,可根据这个值进行不同优先级的任务设置,若peek到了则do,PumpMessage;如果不需要更多的空闲时间则返回0,bIdle为false,此时do第二个循环,主要是lIdleCount置0然后接着peek,下次空闲的时候将重新进行OnIdle的任务。

OnIdle具体如下:


CWinApp::OnIdle
virtual BOOL OnIdle( LONG lCount );

返回值:如果要接收更多的空闲处理时间,则返回非零值;如果不需要更多的空闲时间则返回0。
参数:

lCount

该参数是一个计数值,当应用程序的消息队列为空,OnIdle函数被调用时,该计数值就增加1。每当一条新消息被处理时,该计数值就被复位为0。你可以使用lCount参数来确定应用程序不处理消息时空闲时间的相对长度。

说明:
如果要执行空闲时处理,则重载这个成员函数。当应用程序的消息队列为空时,OnIdle就在缺省的消息循环中被调用。你可以用重载函数来调用自己的后台空闲处理任务。
OnIdle应返回0以表明不需要更多的空闲处理时间。当消息队列为空时,OnIdle每被调用一次lCount参数就增加,而每处理一条新消息lCount就被复位为0。你可以根据这个计数值调用不同的空闲处理例程。
下面总结了空闲循环处理:

1.

如果微软基础类库中的消息循环检查消息队列并发现没有未被处理的消息,它就为应用程序对象调用OnIdle函数,并将lCount参数设为0。

2.

OnIdle执行一些处理,然后返回一个非零值,表示它还需要被调用,以进行进一步处理。

3.

消息循环再次检查消息队列。如果没有未处理的消息,则再次调用OnIdle,增加lCount参数。

4.

最后,OnIdle结束所有的空闲任务并返回0。这就告诉消息循环停止调用OnIdle直到在消息队列中接收到下一条消息为止,在那时,空闲循环将重新启动,而参数被设为0。

因为只有在OnIdle返回之后应用程序才能处理用户输入,因此在OnIdle中不应进行较长的任务。

注意:

OnIdle的缺省实现更新命令用户接口对象,如菜单项和工具条等,还实现了内部数据结构的清理。因此,如果你重载了OnIdle,你必须用重载版本中使用的lCount值来调用CWinApp::OnIdle。首先调用所有基类的空闲处理(即直到基类的OnIdle返回0)。如果你需要在基类处理完成之前进行一些工作,则应回顾基类的实现以在自己的工作期间选择一个合适的lCount值。

示例:

下面的两个例子演示了OnIdle的用法。

第一个例子处理两个空闲任务,用lCount参数来排列这些任务的优先权。第一个任务优先权较高,一旦可能你就应当执行此任务。第二个任务不十分重要,只有当用户输入有一个较长时间的间歇的时候才应执行此任务。注意其中对基类的OnIdle的调用。第二个例子管理着一组具有不同优先权的空闲任务。


BOOL CMyApp::OnIdle(LONG lCount)
{
  BOOL bMore = CWinApp::OnIdle(lCount);
  if (lCount == 0)
  {
    TRACE("App idle for short period of time/n");
    bMore = TRUE;
  }
  else if (lCount == 10)
  {
    TRACE("App idle for longer amount of time/n");
    bMore = TRUE;
  }
  else if (lCount == 100)
  {
    TRACE("App idle for even longer amount of time/n");
    bMore = TRUE;
  }
  else if (lCount == 1000)
  {
    TRACE("App idle for quite a long period of time/n");
    // bMore 没有被设为TRUE, 不在需要空闲
    // 重要:bMore 没有被设为 FALSE,因为 CWinApp::OnIdle可能还有其它空闲任务要完成。
  }
  return bMore; // 返回TRUE,只要还有其它空闲任务
}

第二个示例:


// 在这个例子中,有四个空闲循环任务,它们被赋予
// 不同的优先权,运行的机会不同:
// Task1在空闲时总能运行,要求在框架处理它自己的空闲循环任务时没有消息在等候。(lCount为0或1)
// Task2 仅当Task1以及运行时才能运行,要求当Task1运行时没有消息在等候。
// Task3和Task4仅当Task1和Task2都运行之后才能运行,
// 并且在此期间没有消息在等候。如果Task3能够运行,
// 则Task4总是在Task3之后立即运行。
BOOL CMyApp::OnIdle(LONG lCount)
{
  // 在这个例子中,像多数应用程序一样,你应该让基类
  // 的CWinApp::OnIdle在你试图进行任何附加的空闲循环
  // 过程之前完成它的处理。
  if (CWinApp::OnIdle(lCount)) return TRUE;
  // 基类的CWinApp::OnIdle为lCount保留0和1给框架自己的
  // 空闲处理使用。如果你希望与框架平等地共享空闲处理
  // 时间,则应替换上面的if语句,直接调用CWinApp::OnIdle,
  // 然后为lCount的值0和/或1加入一个case语句。首先应当研
  // 究基类的实现以理解你的空闲循环任务将会如何与框架的
  // 空闲循环处理竞争。
  switch (lCount)
  {
    case 2:
      Task1();
      return TRUE; // 下一次给 Task2 一个机会
    case 3:
      Task2();
      return TRUE; // 下一次给Task3和Task4一个机会
    case 4:
      Task3();
      Task4();
      return FALSE; // 再次回到空闲循环任务
  }
  return FALSE;
}

到此这篇关于MFC框架之OnIdle案例详解的文章就介绍到这了,更多相关MFC框架之OnIdle内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: MFC框架之OnIdle案例详解

本文链接: https://www.lsjlt.com/news/133282.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • MFC框架之OnIdle案例详解
    先看下MSDN对OnIdle()介绍: CWinApp::OnIdle OnIdle is called in the default message loop when ...
    99+
    2022-11-12
  • Java之JSF框架案例详解
    这是一个分为两部分的系列,其中我介绍了JSF 2及其如何适合Java EE生态系统。 在第1部分中,我将介绍JavaServer Pages(JSF)背后的基本思想 ,在第2部分中,...
    99+
    2022-11-12
  • IOS之WebSocket框架Starscream案例详解
    传统的网络技术 (也就是 Berkeley sockets) 被认为是可靠和稳定的。但是 Berkeley socket 在某些 web 技术,比如代理和防火墙下不太好使。WebSo...
    99+
    2022-05-20
    IOS websocket
  • MFC LoadImage用法案例详解
    目录函数原型cxDesired, cyDesired:fuLoad:示例1.加载Icon资源2.加载本地磁盘的Icon文件3.加载本地磁盘的Bitmap文件函数原型 HANDLE...
    99+
    2022-11-12
  • Java Structs框架原理案例详解
    1 Struts2框架内部执行过程 Structs请求过程源码分析参考链接https://www.jb51.net/article/220585.htm 从上图来看,整个框架的运...
    99+
    2022-11-12
  • react.js框架Redux基础案例详解
    react.js框架Redux https://github.com/reactjs/redux 安装: npm install redux react-redux #基于rea...
    99+
    2022-11-12
  • MyBatis框架简介及入门案例详解
    目录前言MyBatis简介快速入门映射文件sql片段与resultMapMyBatis的增删改查1.添加操作2.修改操作3.删除操作前言 传统的JDBC操作数据库都是通过写一个jav...
    99+
    2022-11-13
    MyBatis 简介 MyBatis 案例
  • GameFramework框架详解之 Network网络框架
    前言 目前流行的一些开源的网络框架有很多,我自己也手写过网络相关的模块。但是当我看了GameFramework的网络框架,还是眼前一亮的感觉。他的封装继承体系真的非常值得我们细细去品味,去学习。今天就...
    99+
    2023-10-25
    网络 tcp/ip udp gameframework protobuf
  • Bootstrap框架之按钮组件的案例
    这篇文章将为大家详细讲解有关Bootstrap框架之按钮组件的案例,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。按钮下拉菜单按钮下拉菜单仅从外观上看和下拉菜单效果基本上是一样的。它们唯一的不同是外部容器p...
    99+
    2023-06-07
  • MyBatis框架零基础快速入门案例详解
    目录一、创建数据库和表二、创建maven工程三、代码编写1、编写Student实体类2、编写DAO接口StudentDao3、编写DAO接口Mapper映射文件StudentDao....
    99+
    2022-11-13
  • Android之AttributeSet案例详解
    public interface AttributeSet { public int getAttributeCount(); public...
    99+
    2022-11-12
  • Java之HashMap案例详解
    概述 这篇文章,我们打算探索一下Java集合(Collections)框架中Map接口中HashMap的实现。Map虽然是Collctions框架的一部分,但是Map并没有实现Col...
    99+
    2022-11-12
  • Java之Algorithm_analysis案例详解
    public class BubbleSort { public void sort(int[] array){ for(int i=1;i<...
    99+
    2022-11-12
  • Vue之TodoList案例详解
    <template> <div id="root"> <div class="todo-container"> ...
    99+
    2022-11-12
  • Pytest框架之fixture详解(三)
    相关文章 Pytest框架之fixture详解(一) Pytest框架之fixture详解(二) Pytest框架之fixture详解(三) 本文关于fixture的内容如下: 1、...
    99+
    2022-11-11
  • Pytest框架之fixture详解(二)
    相关文章 Pytest框架之fixture详解(一) Pytest框架之fixture详解(二) Pytest框架之fixture详解(三) 本文关于 fixture 的内容如下: ...
    99+
    2022-11-11
  • Pytest框架之fixture详解(一)
    相关文章 Pytest框架之fixture详解(一) Pytest框架之fixture详解(二) Pytest框架之fixture详解(三) 我们在编写测试用例,都会涉及到用例执行之...
    99+
    2022-11-11
  • Express框架之connect-flash详解
    第一步:我们首先来看看这个插件的使用 var flash = require('connect-flash'); app.use(flash());//Express使用这个插件 第二步:我们看看...
    99+
    2022-06-04
    详解 框架 Express
  • Java集合框架之Map详解
    目录1、Map的实现2、HashMap 和 Hashtable 的区别3、介绍下对象的 hashCode()和equals(),使用场景4、HashMap和TreeMap应该怎么选择...
    99+
    2022-11-13
  • pythonFlask框架之HTTP请求详解
    我们的浏览器访问网站时,默认为发送了一个HTTP的GET请求。 在浏览网站时,会经常填写表单,比如填写用户名密码。点击登录后,会跳转到我们的主页。 接下来,我们实现这个案例。 首先我...
    99+
    2022-11-11
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作