SetTimer,CMenu

来源:互联网 发布:在淘宝购物的步骤 编辑:程序博客网 时间:2024/04/29 16:17

SetTimer

  SetTimer函数的用法

  1)用WM_TIMER来设置定时器

  先请看SetTimer这个API函数的原型

  UINT_PTR SetTimer(

  HWND hWnd, //窗口句柄

  UINT_PTR nIDEvent, //定时器ID,多个定时器时,可以通过该ID判断是哪个定时器

  UINT uElapse, //时间间隔,单位为毫秒

  TIMERPROC lpTimerFunc //回调函数

  );

  例如

  SetTimer(m_hWnd,1,1000,NULL); //一个1秒触发一次的定时器

  在MFC程序中SetTimer被封装在CWnd类中,调用就不用指定窗口句柄了

  于是SetTimer函数的原型变为:

  UINT SetTimer(UINT nIDEvent,UINT nElapse,void(CALLBACK EXPORT *lpfnTimer)(HWND,UINT ,UINT ,DWORD))

  当使用SetTimer函数的时候,就会生成一个计时器。函数中nIDEvent指的是计时器的标识,也就是名字。nElapse指的是时间间隔,

  也就是每隔多长时间触发一次事件。第三个参数是一个回调函数,在这个函数里,放入你想要做的事情的代码,你可以将它设定为NULL

  也就是使用系统默认的回调函数,系统默认认的是onTime函数。这个函数怎么生成的呢?你需要在需要计时器的类的生成onTime函数:

  在ClassWizard里,选择需要计时器的类,添加WM_TIME消息映射,就自动生成onTime函数了。然后在函数里添加代码,让代码实现功能。

  每隔一段时间就会自动执行一次。

  例:

  SetTimer(1,1000,NULL);

  1:计时器的名称;

  1000:时间间隔,单位是毫秒;

  NULL:使用onTime函数。

  当不需要计时器的时候调用KillTimer(nIDEvent);

  例如:KillTimer(1);

  2调用回调函数

  此方法首先写一个如下格式的回调函数

  void CALLBACK TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime);

  然后再用SetTimer(1,100,TimerProc)函数来建一个定时器,第三个参数就是回调函数地址。

  二.或许你会问,如果我要加入两个或者两个以上的 timer怎么办?

  继续用SetTimer函数吧,上次的timerID1,这次可以是234。。。。

  SetTimer(2,1000,NULL);

  SetTimer(3,500,NULL);

  嗯,WINDOWS会协调他们的。当然onTimer函数体也要发生变化,要在函数体内添加每一个timer的处理代码:

  onTimer(nIDEvent)

  {

  switch(nIDEvent)

  {

  case 1:........;

  break;

  case 2:.......;

  break;

  case 3:......;

  break;

  }

  }

程序类对菜单命令的响应顺序:视类,文档类,框架类,应用程序类

CMenu

  对于系统菜单,创建起来比较简单,直接使用资源编辑器就能生成菜单,再通过ClassWizard创建菜单命令函数。在我的资源中上传了一个工程,实现了一个右键弹出贴图菜单。结合这个工程,介绍动态创建菜单、创建弹出式菜单和重绘菜单。

  首先介绍基础知识:

  一、CMenu类的成员函数:

  1. CreateMenu()CreatePopupMenu(),这两个函数用来创建一个菜单实例,CreateMenu()创建的是普通的菜单实例,如果想创建弹出式菜单,就要用CreatePopupMenu()函数。

  2. AppendMenu()向菜单中添加一个子项,这个函数有两个主要的参数。第一个UINT nFlags,这个参数表明了该子项的属性特征,可以这样说,这个参数规定了菜单的样式和功能。后面会详细讲这个参数所能使用的值。第二个参数UINT_PTR nIDNewItem,根据nFlags使用不同的设置,该参数将标明菜单的资源ID或在这个菜单中的索引号。第三个参数可以省略,如果不省略,可以传入一个字符串,这个字符串将显示在菜单中(因为我准备用突破表示菜单项,所以我的工程中省略了这个参数)。

  3. DrawItem(),这是一个虚函数,如果菜单设置成可以自绘类型,则这个函数将在生成菜单、弹出菜单、选中菜单、点击菜单等时由系统框架调用。因此,这个函数是一个很有用的函数,它可以帮你绘制出各种样式的菜单。

  4. MeasureItem()也是一个虚函数,当菜单被创建的时候由系统框架调用。这个函数用来设置菜单的大小。

  二、nFlags说明:

  只有当nFlags设置成MF_OWNERDRAW的时候,系统框架才会重绘菜单。

  MF_CHECKED:命令旁显示默认复选标志

  MF_UNCHECKED:清除命令旁的复选标志

  MF_DISABLED:禁止此菜单命令,但是不变灰显示

  MF_ENABLED:允许此菜单命令,恢复到正常状态

  MF_GRAYED:禁止此菜单命令,变灰显示

  MF_MENUBARBREAK:对于静态菜单,放到新行;对于弹出菜单,放到新栏中,栏间有分隔线

  MF_MENUBREAK:对于静态菜单,放到新行;对于弹出菜单,放到新栏,栏间雾分隔线

  MF_OWNERDRAW:指定该命令是自画式菜单命令

  MF_POPUP:指定该菜单命令有一个关联的弹出式菜单

  MF_SEPARATOR:画一条水平分隔线,只用于弹出式菜单

  MF_STRING:指定此菜单命令是一个字符串

  CMenu类从CObject类派生而来。为什么要使用CMenu类呢?AppWzard不是把菜单做好了吗?在资源编辑器上修改菜单不是很方便吗?

  感觉学vc++稍微深入一点好,至少要能搞清楚AppWizard在背后都干了些什么东西。

  事实上mfc就是用CMenu类来生成菜单的。让我们就从CMenu开始吧。

  CMenu生成的菜单有两种:Popup类型和非Popup类型。这两种方法里又可以分

  成使用资源编辑器生成的菜单资源和不使用这个资源。对于非Popup类型的菜单,

  必须在创建出来后把它张贴到某个窗口上,它才会显示出来,从而才有用处。Po

  pup的菜单却不能张贴到窗口上。

  说明之前,先定义几个常量:

  #define IDM_MENU0 0

  #define IDM_MENU1 1

  #define IDM_MENU2 2

  #define IDM_MENU3 3

  #define IDM_ITEM0 10

  #define IDM_ITEM1 11

  #define IDM_ITEM2 12

  #define IDM_ITEM3 13

  #define IDM_ITEM4 14

  #define IDM_ITEM5 15

  #define IDM_ITEM6 16

  一。创建非Popup类型菜单,不使用资源。

  ()创建非下拉菜单。

  1。在窗口类的OnCreate函数里创建CMenu对象。如果是创建运用程序主框架窗口

  的话,也可以在InitInstance()函数里。

  2。声明一个CMenu对象:CMenu MyMenu;

  3。调用MyMenu.CreateMenu()MyMenu.LoadMenu()

  4。调用若干次MyMenu.AppendMenu()MyMenu.InsertMenu(),每调用一次创建一

  个菜单项。

  5。调用MyMneu.SetMenu()将菜单Attach到窗口上。

  6。调用MyMenu.Detach()

  例子:

  int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )

  {

  {

  CMenu MyMenu;

  MyMenu.CreateMenu();

  MyMenu.AppendMenu(MF_STRING,IDM_MENU0,"文件");

  MyMenu.AppendMenu(MF_STRING,IDM_MENU1,"编辑");

  MyMenu.AppendMenu(MF_STRING,IDM_MENU2,"查看");

  MyMenu.AppendMenu(MF_STRING,IDM_MENU3,"帮助");

  MyMenu.InsertMenu(IDM_MENU2,MF_BYCOMMAND,IDM_ITEM0,"有关");

  this->SetMenu(&MyMenu);

  MyMenu.Detach();

  return 0;

  }//各个函数的细节就不讲解了,看联机帮助是最好的。

  这个方法是先把菜单创建好后再贴到窗口上去,然后用Detach()使菜单和My

  Menu对象脱离关系,因为MyMenu对象马上就要超出作用域了,这一步是必须的。

  ()创建下拉菜单,不使用资源。

  这种菜单当鼠标移动到菜单条目上面点击时不是去执行某段程序,而是弹出

  一个下拉菜单。这需要用前面的方法创建两个菜单。第一个是鼠标未点击时看到

  的那个菜单,另一个就是扮演下拉菜单的菜单。例子:

  int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )

  {

  CMenu MyMenu0,MyMenu1;

  //下面这几条创建下拉菜单

  MyMenu1.CreateMenu();

  MyMenu1.AppendMenu(MF_STRING,IDM_ITEM0,"拷贝");

  MyMenu1.AppendMenu(MF_STRING,IDM_ITEM1,"剪切");

  MyMenu1.AppendMenu(MF_STRING,IDM_ITEM2,"粘贴");

  MyMenu1.AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");

  MyMenu1.AppendMenu(MF_STRING,IDM_ITEM4,"全选");

  MyMenu1.AppendMenu(MF_SEPARATOR,IDM_ITEM5,"");

  MyMenu1.AppendMenu(MF_STRING,IDM_ITEM6,"删除");

  //下面这两条创建鼠标未点击时看到的那个菜单

  //其中第二句将下拉菜单张贴到第一个菜单上。

  MyMenu0.CreateMenu();

  MyMenu0.AppendMenu(MF_POPUP,(UINT)MyMenu1.m_hMenu,"编辑");

  this->SetMenu(&MyMenu0);//将菜单张贴到窗口上

  MyMenu0.Detach();//必须有

  MyMenu1.Detach();//必须有

  return 0;

  }

  二。创建Popup类型的菜单,也不用资源。

  很多程序里,只要用鼠标右键点一下窗口客户区,就会在鼠标的位置弹出一

  个菜单,这叫右键菜单。我们可以用CMenu类来制作。

  制作这种菜单比制作第一类菜单稍微复杂点。首先要在窗口类里加个成员变

  量:CMenu *MyMenu2;

  然后在窗口类的构造函数里(OnCreate()函数里)加上创建菜单的语句,再

  在析构函数里加上销毁菜单的语句,最后在OnRButtonDown()函数里加上显示菜单

  的语句。

  创建菜单时,CMenu类对象应该用new来分配。

  例子:

  CMyWnd::CMyWnd()

  {

  //CMyWnd是从CWnd派生来的。

  //先把菜单创建起来。

  MyMenu2=new CMenu;

  MyMenu2->CreatePopupMenu();

  MyMenu2->AppendMenu(MF_STRING,IDM_ITEM0,"拷贝");

  MyMenu2->AppendMenu(MF_STRING,IDM_ITEM1,"剪切");

  MyMenu2->AppendMenu(MF_STRING,IDM_ITEM2,"粘贴");

  MyMenu2->AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");

  MyMenu2->AppendMenu(MF_STRING,IDM_ITEM4,"全选");

  MyMenu2->AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");

  MyMenu2->AppendMenu(MF_STRING,IDM_ITEM5,"删除");

  }

  CMyWnd::~CMyWnd()

  {

  MyMenu2->DestroyMenu();//销毁菜单所占用的系统资源

  delete MyMenu2;//销毁菜单类对象

  }

  void CMyWnd::OnRButtonDown(UINT nFlags, CPoint point)

  {

  RECT rect;

  GetWindowRect(&rect);

  //显示菜单

  MyMenu2->TrackPopupMenu(TPM_RIGHTALIGN,point.x+rect.left,point.y+

  rect.top,this,NULL);

  }

  三。使用资源编辑器做好的菜单,只能做非POPUP类型菜单。

  如果使用资源的话,创建菜单确实非常简单了,只须在窗口类的OnCreate()

  函数里加几句话就行了:

  int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )

  {

  CMenu MyMenu3;

  MyMenu3.LoadMenu(IDR_MENU1);//IDR_MENU1是你的菜单的资源ID

  this->SetMenu(&MyMenu3);

  MyMenu3.Detach();

  return 0;

  }

  CMenu类还有很多成员函数,使你可以在运行中对菜单进行裁剪,比如加上几

  项或减去几项等等,使用非常方便。大家可以去看msdn

  如果要实验以上的菜单创建方法的话,可以用一个非常简单的mfc程序来搞:

  //这是一个非常简单的mfc程序,必要的函数自己去加吧。

  #include

  class CMyApp : public CWinApp

  {

  public:

  virtual BOOL InitInstance();

  };

  };

  class CMyWnd : public CWnd

  {

  public:

  DECLARE_MESSAGE_MAP()

  };

  CMyApp MyApp;

  BEGIN_MESSAGE_MAP(CMyWnd,CWnd)

  END_MESSAGE_MAP()

  BOOL CMyApp::InitInstance()

  {

  RECT rect={30,30,400,300};

  CMyWnd* pCWindow=new CMyWnd;

  pCWindow->CreateEx

  (

  NULL,

  AfxRegisterWndClass(NULL,0,(HBRUSH)::GetStockObject(WHITE_BRU

  SH),0),

  "实验程序",

  WS_OVERLAPPEDWINDOW,

  rect,NULL,NULL,NULL

  );

  m_pMainWnd = pCWindow;

  pCWindow->ShowWindow(m_nCmdShow);

  pCWindow->UpdateWindow();

  return TRUE;