MFC - 訊息與事件



一個應用程式是由各種物件組成的。大多數時候,計算機上執行著不止一個應用程式,並且作業系統不斷地被要求執行一些任務。由於可能會有如此多的請求以不可預測的方式出現,因此作業系統將決定權留給物件來指定它們想要什麼、何時想要以及期望什麼行為或結果。

概述

  • 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 Project

步驟 1 - 要建立 MFC 專案,請右鍵單擊該專案並選擇“屬性”。

步驟 2 - 在左側部分,單擊“配置屬性”→“常規”。

步驟 3 - 在“專案預設值”部分中選擇“在共享 DLL 中使用 MFC”選項,然後單擊“確定”。

步驟 4 - 我們需要新增一個新的原始檔。

步驟 5 - 右鍵單擊您的專案並選擇“新增”→“新建項”。

步驟 6 - 在“模板”部分,單擊“C++ 檔案 (.cpp)”。

Win Project

步驟 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_CREATE - 當建立一個稱為視窗的物件時,建立物件的框架會發送一個標識為 ON_WM_CREATE 的訊息。

步驟 1 - 要建立 ON_WM_CREATE,請在 DECLARE_MESSAGE_MAP() 之前新增 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);,如下所示。

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 - 編譯並執行上述程式碼後,您將看到以下輸出。

Message

步驟 6 - 單擊“確定”後,將顯示主視窗。

Message

命令訊息

圖形應用程式的主要功能之一是呈現 Windows 控制元件和資源,允許使用者與機器互動。我們將學習的控制元件示例包括按鈕、列表框、組合框等。

我們在上一課中介紹了一種資源型別,即選單。當用戶單擊此類控制元件和資源時,它們可以啟動自己的訊息。源自 Windows 控制元件或資源的訊息稱為命令訊息。

讓我們來看一個簡單的命令訊息示例。

為了使您的應用程式能夠建立新文件,CWinApp 類提供了 OnFileNew() 方法。

afx_msg void OnFileNew();

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

以下是方法定義 -

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

鍵盤訊息

鍵盤是連線到計算機的硬體物件。預設情況下,它用於在控制元件上輸入可識別的符號、字母和其他字元。鍵盤上的每個鍵都顯示一個符號、一個字母或它們的組合,以指示該鍵可用於什麼。使用者通常按下某個鍵,該鍵會向程式傳送訊號。

每個鍵都有一個作業系統可以識別的程式碼。此程式碼稱為虛擬鍵碼

按下某個鍵會導致將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 - 編譯並執行上述程式碼後,您將看到以下輸出。

Message Window

步驟 4 - 按下 Enter 鍵後,將顯示以下訊息。

Message Output

滑鼠訊息

滑鼠是連線到計算機的另一個物件,允許使用者與機器互動。

  • 如果按下左滑鼠按鈕,則會發送 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 - 執行此應用程式時,您將看到以下輸出。

Mouse Messages

步驟 5 - 單擊“確定”後,您將看到以下訊息。

Mouse Messages

步驟 6 - 右鍵單擊此視窗。現在,當您釋放滑鼠右鍵時,將顯示以下訊息。

Mouse Messages
廣告

© . All rights reserved.