MFC - 消息和事件

创建于 2024-12-03 / 25
字体: [默认] [大] [更大]

应用程序由各种对象组成。 大多数时候,计算机上运行着多个应用程序,操作系统不断被要求执行一些任务。 由于可能会出现如此多不可预测的请求,因此操作系统将其留给对象来指定它们想要什么、何时想要以及它们期望什么行为或结果。

概述

  • Microsoft Windows 操作系统无法预测一个对象需要处理哪种类型的请求以及另一个对象需要哪种类型的分配。

  • 为了管理所有这些分配和请求,对象会发送消息。

  • 每个对象都有责任决定发送什么消息以及何时发送。

  • 为了发送消息,控件必须创建事件。

  • 为了区分两者,消息的名称通常以 WM_ 开头,它代表"窗口消息"。

  • 事件的名称通常以 On 开头,表示一个操作。

  • 事件是发送消息的动作。

消息映射

由于 Windows 是面向消息的操作系统,因此 Windows 环境的编程很大一部分都涉及消息处理。 每次发生击键或鼠标单击等事件时,都会向应用程序发送一条消息,然后应用程序必须处理该事件。

  • 为了让编译器管理消息,它们应该包含在类定义中。

  • 应在类定义的末尾提供 DECLARE_MESSAGE_MAP 宏,如以下代码所示。

class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      DECLARE_MESSAGE_MAP()
};
  • 实际消息应列在 DECLARE_MESSAGE_MAP 行的正上方。

  • 要实现消息,您需要创建程序正在使用的消息表。

  • 该表使用两个定界宏;

  • 它以 BEGIN_MESSAGE_MAP 开始,以 END_MESSAGE_MAP 宏结束。

  • BEGIN_MESSAGE_MAP 宏采用两个参数,即类的名称和派生类的 MFC 类,如以下代码所示。

#include <afxwin.h>
class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      DECLARE_MESSAGE_MAP()
};
CMainFrame::CMainFrame() {

   // Create the window's frame
   Create(NULL, L"MFC Messages Demo", WS_OVERLAPPEDWINDOW,
                                      CRect(120, 100, 700, 480), NULL);
}
class CMessagesApp : public CWinApp {
   public:
      BOOL InitInstance();
};
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
END_MESSAGE_MAP()
BOOL CMessagesApp::InitInstance(){
   m_pMainWnd = new CMainFrame;
   m_pMainWnd->ShowWindow(SW_SHOW);
   m_pMainWnd->UpdateWindow();
   return TRUE;
}
CMessagesApp theApp;

让我们通过创建一个新的 Win32 项目来研究一个简单的示例。

Win32 项目

步骤 1 − 要创建 MFC 项目,请右键单击该项目并选择"属性"。

步骤 2 − 在左侧部分中,单击 Configuration Properties → General。

步骤 3 − 在"项目默认值"部分中选择"在共享 DLL 中使用 MFC"选项,然后单击"确定"。

步骤 4 − 我们需要添加一个新的源文件。

步骤 5 − 右键单击您的项目并选择 Add → New Item。

步骤 6 − 在"模板"部分中,单击"C++ 文件 (.cpp)"。

Win 项目

步骤 7 − 单击"添加"以继续。

步骤 8 − 现在,在 *.cpp 文件中添加以下代码。

#include <afxwin.h>
class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      DECLARE_MESSAGE_MAP()
};

CMainFrame::CMainFrame() {
   // Create the window's frame
   Create(NULL, L"MFC Messages Demo", WS_OVERLAPPEDWINDOW,
      CRect(120, 100, 700, 480), NULL);
}

class CMessagesApp : public CWinApp {
   public:
      BOOL InitInstance();
};

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
END_MESSAGE_MAP()
BOOL CMessagesApp::InitInstance() {
   m_pMainWnd = new CMainFrame;
   m_pMainWnd->ShowWindow(SW_SHOW);
   m_pMainWnd->UpdateWindow();
   return TRUE;
}
CMessagesApp theApp;

Windows 消息

Windows 消息有不同类型,例如创建窗口、显示窗口等。以下是一些常用的 Windows 消息。

消息 映射条目 描述
WM_ACTIVATE ON_WM_ACTIVATE() 当CWnd对象被激活或停用时,框架调用此成员函数。
WM_ACTIVATEA PP ON_WM_ACTIVATEAPP() 框架向正在激活的任务的所有顶级窗口以及正在停用的任务的所有顶级窗口调用此成员函数。
WM_APPCOMM 和 ON_WM_APPCOMMAND() 当用户生成应用程序命令事件时,框架调用此成员函数。
WM_CANCELMODE WM_CANCELMODE() 框架调用该成员函数来通知CWnd取消任何内部模式。
WM_CHILDACTIVATE ON_WM_CHILDACTIVATE() 如果 CWnd 对象是多文档界面 (MDI) 子窗口,则当用户单击窗口的标题栏或激活、移动窗口或调整窗口大小时,框架将调用 OnChildActivate。
WM_CLIPBOAR DUPDATE ON_WM_CLIPBOARDUPDATE() 当剪贴板的内容发生更改时,框架调用此成员函数。
WM_CLOSE ON_WM_CLOSE() 框架调用此成员函数作为 CWnd 或应用程序要终止的信号。
WM_CONTEXTMENU ON_WM_CONTEXTMENU() 当用户在窗口中单击鼠标右键(右键单击)时由框架调用。
WM_COPYDATA ON_WM_COPYDATA() 框架调用此成员函数将数据从一个应用程序复制到另一个应用程序。
WM_CREATE ON_WM_CREATE() 当应用程序请求通过调用Create或CreateEx成员函数创建Windows窗口时,框架调用此成员函数。
WM_CTLCOLOR ON_WM_CTLCOLOR() 当子控件即将被绘制时,框架调用此成员函数。
WM_DELETEITEM ON_WM_DELETEITEM() 框架调用此成员函数来通知所有者绘制列表框或组合框的所有者该列表框或组合框已被销毁或项目已被删除。
WM_DESTROY ON_WM_DESTROY() 框架调用此成员函数来通知 CWnd 对象它正在被销毁。
WM_DRAWITEM ON_WM_DRAWITEM() 当控件或菜单的视觉方面发生更改时,框架为所有者绘制按钮控件、组合框控件、列表框控件或菜单的所有者调用此成员函数。
WM_DROPFILES ON_WM_DROPFILES() 当用户在已将自身注册为拖放文件接收者的窗口上释放鼠标左键时,框架将调用此成员函数。
WM_ENABLE ON_WM_ENABLE() 当应用程序更改 CWnd 对象的启用状态时,框架调用此成员函数。 语法。
WM_HELPINFO ON_WM_HELPINFO() 处理应用程序中的 F1 帮助(使用当前上下文)。
WM_HOTKEY ON_WM_HOTKEY() 当用户按下系统范围的热键时,框架调用此成员函数。
WM_HSCROLL ON_WM_HSCROLL() 当用户单击窗口的水平滚动条时,框架调用此成员函数。
WM_KEYDOWN ON_WM_KEYDOWN() 当按下非系统键时,框架调用此成员函数。
WM_KEYUP ON_WM_KEYUP() 当非系统密钥被释放时,框架调用此成员函数。
WM_KILLFOCUS ON_WM_KILLFOCUS() 框架在失去输入焦点之前立即调用此成员函数。
WM_LBUTTONDBLCLK ON_WM_LBUTTONDBLCLK() 当用户双击鼠标左键时,框架调用此成员函数。
WM_LBUTTONDOWN ON_WM_LBUTTONDOWN() 当用户按下鼠标左键时,框架调用此成员函数。
WM_LBUTTONUP ON_WM_LBUTTONUP() 当用户释放鼠标左键时,框架调用此成员函数。
WM_MBUTTONDBLCLK ON_WM_MBUTTONDBLCLK() 当用户双击鼠标中键时,框架调用此成员函数。
WM_MBUTTONDOWN ON_WM_MBUTTONDOWN() 当用户按下鼠标中键时,框架调用此成员函数。
WM_MBUTTONUP ON_WM_MBUTTONUP() 当用户释放鼠标中键时,框架调用此成员函数。
WM_MENUSELECT ON_WM_MENUSELECT() 如果 CWnd 对象与菜单关联,则当用户选择菜单项时,框架会调用 OnMenuSelect。
WM_MOUSEACTIVATE ON_WM_MOUSEACTIVATE() 当光标位于非活动窗口并且用户按下鼠标按钮时,框架调用此成员函数。
WM_MOUSEHOVER ON_WM_MOUSEHOVER() 当光标悬停在窗口的客户区域上并达到先前调用 TrackMouseEvent 中指定的时间段时,框架将调用此成员函数。
WM_MOUSEHWHEEL ON_WM_MOUSEHWHEEL() 当当前窗口由桌面窗口管理器(DWM)组成并且该窗口最大化时,框架调用此成员。
WM_MOUSELEAVE ON_WM_MOUSELEAVE() 当光标离开先前调用 TrackMouseEvent 时指定的窗口客户区时,框架调用此成员函数。
WM_MOUSEMOVE ON_WM_MOUSEMOVE() 当鼠标光标移动时,框架调用此成员函数。
WM_MOVE ON_WM_MOVE() 框架在 CWnd 对象移动后调用此成员函数。
WM_PAINT ON_WM_PAINT() 当 Windows 或应用程序请求重绘应用程序窗口的一部分时,框架调用此成员函数。
WM_SETFOCUS() ON_WM_SETFOCUS( ) 框架在获得输入焦点后调用此成员函数。
WM_SIZE( ) ON_WM_SIZE( ) 框架在窗口大小更改后调用此成员函数。
WM_TIMER ON_WM_TIMER() 框架在用于安装计时器的SetTimer成员函数中指定的每个时间间隔后调用此成员函数。
WM_VSCROLL ON_WM_VSCROLL() 当用户单击窗口的垂直滚动条时,框架调用此成员函数。
WM_WINDOWPOSCHANGED ON_WM_WINDOWPOSCHANGED() 当由于调用 SetWindowPos 成员函数或其他窗口管理函数而导致大小、位置或 Z 顺序发生更改时,框架将调用此成员函数。

让我们看一个窗口创建的简单示例。

WM_CREATE − 当创建一个称为窗口的对象时,创建该对象的框架会发送一条标识为 ON_WM_CREATE 的消息。

步骤 1 − 要创建 ON_WM_CREATE,请添加 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); 在 DECLARE_MESSAGE_MAP() 之前,如下所示。

class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
      DECLARE_MESSAGE_MAP()
};

步骤 2 − 在 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) 之后、END_MESSAGE_MAP() 之前添加 ON_WM_CREATE()

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   ON_WM_CREATE()
END_MESSAGE_MAP()

步骤 3 − 下面是 OnCreate() 的实现

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {
   // Call the base class to create the window
   if (CFrameWnd::OnCreate(lpCreateStruct) == 0) {

      // If the window was successfully created, let the user know
      MessageBox(L"The window has been created!!!");
      // Since the window was successfully created, return 0
      return 0;
   }
   // Otherwise, return -1
   return -1;
}

步骤 4 − 现在您的 *.cpp 文件将如以下代码所示。

#include <afxwin.h>
class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
      DECLARE_MESSAGE_MAP()
};
CMainFrame::CMainFrame() {

   // Create the window's frame
   Create(NULL, L"MFC Messages Demo", WS_OVERLAPPEDWINDOW,
      CRect(120, 100, 700, 480), NULL);
}
class CMessagesApp : public CWinApp {
   public:
      BOOL InitInstance();
};
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   ON_WM_CREATE()
END_MESSAGE_MAP()
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {
   // Call the base class to create the window
   if (CFrameWnd::OnCreate(lpCreateStruct) == 0) {
      // If the window was successfully created, let the user know
      MessageBox(L"The window has been created!!!");
      // Since the window was successfully created, return 0
      return 0;
   }
   // Otherwise, return -1
   return -1;
}
BOOL CMessagesApp::InitInstance() { 
   m_pMainWnd = new CMainFrame;
   m_pMainWnd -> ShowWindow(SW_SHOW);
   m_pMainWnd -> UpdateWindow();
   return TRUE;
}
CMessagesApp theApp;

步骤 5 − 当上面的代码被编译并执行时,您将看到以下输出。

消息

步骤 6 − 当您单击"确定"时,它将显示主窗口。

消息

命令消息

图形应用程序的主要功能之一是提供允许用户与计算机交互的 Windows 控件和资源。 我们将学习的控件示例有按钮、列表框、组合框等。

我们在上一课中介绍的一种资源是菜单。 当用户单击此类控件和资源时,它们可以启动自己的消息。 从 Windows 控件或资源发出的消息称为命令消息。

让我们看一个命令消息的简单示例。

为了使您的应用程序能够创建新文档,CWinApp 类提供了 OnFileNew() 方法。

afx_msg void OnFileNew();

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   ON_COMMAND(ID_FILE_NEW, CMainFrame::OnFileNew)
END_MESSAGE_MAP()

Here is the method definition −

void CMainFrame::OnFileNew() {
   // Create New file
}

键盘消息

键盘是连接到计算机的硬件对象。 默认情况下,它用于在控件上输入可识别的符号、字母和其他字符。 键盘上的每个键都会显示一个符号、字母或这些符号的组合,以指示该键的用途。 用户通常按下一个键,该键会向程序发送信号。

每个键都有一个操作系统可以识别的代码。 此代码称为虚拟键代码

序号 常数/值和描述
1

VK_LBUTTON

鼠标左键

2

VK_RBUTTON

鼠标右键

3

VK_CANCEL

控制中断处理

4

VK_MBUTTON

鼠标中键(三键鼠标)

5

VK_BACK

退格键

6

VK_RETURN

ENTER键

7

VK_TAB

TAB键

8

VK_CLEAR

清除键

9

VK_SHIFT

SHIFT键

10

VK_CONTROL

CTRL键

11

VK_MENU

ALT键

12

VK_PAUSE

暂停键

13

VK_CAPITAL

大写锁定键

14

VK_ESCAPE

ESC键

15

VK_SPACE

空格键

16

VK_PRIOR

翻页键

17

VK_NEXT

向下翻页键

18

VK_END

END键

19

VK_HOME

HOME键

20

VK_LEFT

左箭头键

21

VK_UP

向上箭头键

22

VK_RIGHT

右箭头键

23

VK_DOWN

向下键

24

VK_SELECT

SELECT键

25

VK_PRINT

PRINT 键

26

VK_EXECUTE

执行键

27

VK_SNAPSHOT

打印屏幕键

28

VK_INSERT

INS键

29

VK_DELETE

DEL键

30

VK_NUMPAD0

数字键盘0键

31

VK_NUMPAD1

数字键盘1键

32

VK_NUMPAD2

数字键盘2键

33

VK_NUMPAD3

数字键盘3键

34

VK_NUMPAD4

数字键盘4键

35

VK_NUMPAD5

数字键盘 5 键

36

VK_NUMPAD6

数字键盘6键

37

VK_NUMPAD7

数字键盘7键

38

VK_NUMPAD8

数字键盘8键

39

VK_NUMPAD9

数字键盘9键

40

VK_MULTIPLY

乘号键

41

VK_ADD

添加密钥

42

VK_SEPARATOR

分隔键

43

VK_SUBTRACT

减法键

44

VK_DECIMAL

十进制键

45

VK_DIVIDE

分割键

46

VK_F1

F1键

47

VK_F2

F2键

48

VK_F3

F3键

49

VK_F4

F4键

50

VK_F5

F5键

52

VK_F6

F6键

53

VK_F7

F7键

54

VK_F8

F8键

55

VK_F9

F9键

56

VK_F10

F10键

57

VK_F11

F11键

58

VK_F12

F12键

59

VK_NUMLOCK

NUM LOCK 键

60

VK_SCROLL

滚动锁定键

61

VK_LSHIFT

左SHIFT键

62

VK_RSHIFT

右SHIFT键

63

VK_LCONTROL

左CONTROL键

64

VK_RCONTROL

右 CONTROL 键

按下某个键会导致 WM_KEYDOWNWM_SYSKEYDOWN 消息被放置在线程消息中。 这可以定义如下 −

afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);

让我们看一个简单的例子。

步骤 1 − 这是消息。

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   ON_WM_CREATE()
   ON_WM_KEYDOWN()
END_MESSAGE_MAP()

步骤 2 − 这是OnKeyDown()的实现。

void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
   switch (nChar) {

      case VK_RETURN:
         MessageBox(L"You pressed Enter");
         break;
      case VK_F1:
         MessageBox(L"Help is not available at the moment");
         break;
      case VK_DELETE:
         MessageBox(L"Can't Delete This");
         break;
      default:
         MessageBox(L"Whatever");
   }
}

步骤 3 − 当上面的代码被编译并执行时,您将看到以下输出。

消息窗口

步骤 4 − 当您按 Enter 时,将显示以下消息。

消息输出

鼠标消息

鼠标是连接到计算机的另一个对象,允许用户与机器交互。

  • 如果按下鼠标左键,则会发送 ON_WM_LBUTTONDOWN 消息。 该消息的语法是 −

    • afx_msg void OnLButtonDown(UINT nFlags, CPoint point)

  • 如果按下鼠标右键,则会发送 ON_WM_RBUTTONDOWN 消息。 它的语法是 −

    • afx_msg void OnRButtonDown(UINT nFlags, CPoint point)

  • 同样,如果释放鼠标左键,则发送 ON_WM_LBUTTONUP 消息。 它的语法是 −

    • afx_msg void OnLButtonUp(UINT nFlags, CPoint point)

  • 如果释放鼠标右键,则发送 ON_WM_TBUTTONUP 消息。 它的语法是 −

    • afx_msg void OnRButtonUp(UINT nFlags, CPoint point)

让我们看一个简单的例子。

步骤 1 − 在 CMainFrame 类定义中添加以下两个函数,如以下代码所示。

class CMainFrame : public CFrameWnd {
   public:
      CMainFrame();
   protected:
      afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
      afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
      afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
      DECLARE_MESSAGE_MAP()
};

步骤 2 − 添加以下两个消息映射。

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   ON_WM_KEYDOWN()
   ON_WM_LBUTTONDOWN()
   ON_WM_RBUTTONUP()
END_MESSAGE_MAP()

步骤 3 − 这是函数定义。

void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point) { 
   CString MsgCoord;
   MsgCoord.Format(L"Left Button at P(%d, %d)", point.x, point.y);
   MessageBox(MsgCoord);
}
void CMainFrame::OnRButtonUp(UINT nFlags, CPoint point) { 
   MessageBox(L"Right Mouse Button Up");
}

步骤 4 − 当您运行此应用程序时,您将看到以下输出。

鼠标消息

步骤 5 − 单击"确定"后,您将看到以下消息。

鼠标消息

步骤 6 − 右键单击该窗口。 现在,当您释放鼠标右键时,将显示以下消息。

鼠标消息

0 人点赞过