MFC - 快速指南



MFC - 概述

Microsoft Foundation Class (MFC) 庫提供了一組函式、常量、資料型別和類,用於簡化建立 Microsoft Windows 作業系統應用程式。在本教程中,您將學習有關如何使用 MFC 啟動和建立基於 Windows 的應用程式的所有知識。

先決條件

我們假設您瞭解以下內容:

  • 關於 Windows 程式設計的一些知識。
  • C++ 程式設計基礎。
  • 瞭解面向物件程式設計的基礎知識。

什麼是 MFC?

Microsoft Foundation Class 庫 (MFC) 是用於 Microsoft Windows 程式設計的“應用程式框架”。MFC 提供了許多程式碼,這些程式碼是以下內容所必需的:

  • 管理 Windows。
  • 選單和對話方塊。
  • 執行基本的輸入/輸出。
  • 儲存資料物件集合等。

透過在 MFC 框架中新增特定於應用程式的程式碼,您可以輕鬆擴充套件或覆蓋您 C++ 應用程式中的 MFC 框架的基本功能。

MFC 框架

  • MFC 框架提供了一組旨在簡化 Windows 程式設計的可重用類。

  • MFC 為許多基本物件提供了類,例如在日常程式設計中使用的字串、檔案和集合。

  • 它還為常見的 Windows API 和資料結構提供了類,例如視窗、控制元件和裝置上下文。

  • 該框架還為更高階的功能(例如 ActiveX 和文件檢視處理)提供了堅實的基礎。

  • 此外,MFC 還提供了一個應用程式框架,包括構成應用程式體系結構層次結構的類。

為什麼選擇 MFC?

MFC 框架是一種強大的方法,可以讓您建立在 Windows 專家程式設計師的工作基礎上。MFC 框架具有以下優點。

  • 它縮短了開發時間。

  • 它使程式碼更具可移植性。

  • 它還提供了巨大的支援,而不會降低程式設計自由度和靈活性。

  • 它可以輕鬆訪問“難以程式設計”的使用者介面元素和技術。

  • MFC 透過資料訪問物件 (DAO) 和開放資料庫連線 (ODBC) 簡化了資料庫程式設計,並透過 Windows 套接字簡化了網路程式設計。

MFC - 環境設定

Microsoft Visual C++ 是一種用於建立 Microsoft Windows 作業系統應用程式的程式設計環境。要在您的 C++ 應用程式中使用 MFC 框架,您必須已安裝 Microsoft Visual C++ 或 Microsoft Visual Studio。Microsoft Visual Studio 還包含 Microsoft Visual C++ 環境。

Microsoft 提供了 Visual Studio 的免費版本,其中也包含 SQL Server,您可以從 https://www.visualstudio.com/en-us/downloads/downloadvisual- studio-vs.aspx 下載。

以下是安裝步驟。

步驟 1 - 下載 Visual Studio 後,執行安裝程式。將顯示以下對話方塊。

Visual Studio

步驟 2 - 單擊“安裝”以啟動安裝過程。

Visual Studio Installation

步驟 3 - Visual Studio 成功安裝後,您將看到以下對話方塊。

Visual Studio Installed

步驟 4 - 關閉此對話方塊,並在需要時重新啟動計算機。

步驟 5 - 從“開始”選單開啟 Visual Studio,這將開啟以下對話方塊。首次啟動時,準備工作需要一些時間。

Visual Studio Preparing

步驟 6 - 接下來,您將看到 Visual Studio 的主視窗。

Visual Studio Main Window

步驟 7 - 您現在可以開始您的應用程式了。

MFC - VC++ 專案

在本章中,我們將介紹不同型別的 VC++ 專案。Visual Studio 包括幾種 Visual C++ 專案模板。這些模板有助於建立基本程式結構、選單、工具欄、圖示、引用和包含語句,這些語句適合您要建立的專案型別。以下是模板的一些主要功能。

  • 它為許多這些專案模板提供了嚮導,並幫助您在建立專案時自定義專案。

  • 建立專案後,您可以構建和執行應用程式。

  • 您不必使用模板來建立專案,但在大多數情況下,使用專案模板效率更高。

  • 修改提供的專案檔案和結構比從頭建立它們更容易。

在 MFC 中,您可以使用以下專案模板。

序號 專案模板和描述
1

MFC 應用程式

MFC 應用程式是基於 Microsoft Foundation Class (MFC) 庫的 Windows 可執行應用程式。建立 MFC 應用程式最簡單的方法是使用 MFC 應用程式嚮導。

2

MFC ActiveX 控制元件

ActiveX 控制元件程式是模組化程式,旨在為父應用程式提供特定型別的功能。例如,您可以建立用於對話方塊、工具欄或網頁上的按鈕等控制元件。

3

MFC DLL

MFC DLL 是一個二進位制檔案,充當共享函式庫,多個應用程式可以同時使用。建立 MFC DLL 專案最簡單的方法是使用 MFC DLL 嚮導。

以下是一些也可以用於建立 MFC 應用程式的通用模板:

序號 專案模板和描述
1

空專案

專案是構建應用程式所需的所有內容的邏輯容器。然後,您可以根據需要向解決方案中新增更多新的或現有的專案。

2

自定義嚮導

當您需要建立新的自定義嚮導時,Visual C++ 自定義嚮導是您要使用的工具。建立自定義嚮導最簡單的方法是使用自定義嚮導。

MFC - 入門

在本章中,我們將檢視一個正在工作的 MFC 示例。要建立 MFC 應用程式,您可以使用嚮導自定義您的專案。您也可以從頭開始建立應用程式。

使用專案模板建立專案

以下是使用 Visual Studio 中提供的專案模板建立專案的步驟。

步驟 1 - 開啟 Visual Studio 並單擊“檔案”→“新建”→“專案”選單選項。

步驟 2 - 您現在可以看到“新建專案”對話方塊已開啟。

Project

步驟 3 - 從左側窗格中選擇“模板”→“Visual C++”→“MFC”。

步驟 4 - 在中間窗格中,選擇“MFC 應用程式”。

步驟 5 - 在“名稱”欄位中輸入專案名稱“MFCDemo”,然後單擊“確定”繼續。您將看到以下對話方塊。

Application MFCDemo

步驟 6 - 單擊“下一步”。

MFC Application Type

步驟 7 - 選擇上面對話方塊中顯示的選項,然後單擊“下一步”。

MFC Application Options

步驟 8 - 取消選中所有選項,然後單擊“完成”按鈕。

您現在可以看到 MFC 嚮導預設情況下建立了此對話方塊框和專案檔案。

MFC Wizard

步驟 9 - 執行此應用程式,您將看到以下輸出。

MFC Application Result

從頭開始建立專案

您也可以從頭開始建立 MFC 應用程式。要建立 MFC 應用程式,您需要執行以下步驟。

步驟 1 - 開啟 Visual Studio 並單擊“檔案”→“新建”→“專案”選單選項。

步驟 2 - 您現在可以看到“新建專案”對話方塊。

Create Scratch

步驟 3 - 從左側窗格中選擇“模板”→“Visual C++”→“常規”。

步驟 4 - 在中間窗格中,選擇“空專案”。

步驟 5 - 在“名稱”欄位中輸入專案名稱“MFCDemoFromScratch”,然後單擊“確定”繼續。您將看到已建立了一個空專案。

MFCDemoFromScratch

步驟 6 - 要將其設為 MFC 專案,請右鍵單擊該專案並選擇“屬性”。

Select MFC Project & Properties

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

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

步驟 9 - 因為它現在是一個空專案;我們需要新增一個 C++ 檔案。因此,右鍵單擊該專案並選擇“新增”→“新建項...”

Add New Item

步驟 10 - 在中間窗格中選擇“C++ 檔案 (.cpp)”,在“名稱”欄位中輸入檔名,然後單擊“新增”按鈕。

Enter File Name

步驟 11 - 您現在可以看到“main.cpp”檔案已新增到“原始檔”資料夾下。

步驟 12 - 讓我們在此檔案中新增以下程式碼。

#include <iostream> 
using namespace std;  

void main() { 
   cout << "***************************************\n"; 
   cout << "MFC Application Tutorial"; 
   cout << "\n***************************************"; 
   getchar(); 
}

步驟 13 - 執行此應用程式時,您將在控制檯上看到以下輸出。

*************************************** 
MFC Application Tutorial 
***************************************

MFC - Windows 基礎

在本章中,我們將介紹 Windows 的基礎知識。要建立程式(也稱為應用程式),您需要從 MFC 的 CWinApp 派生一個類。CWinApp 代表Windows 應用程式類。

讓我們透過建立一個新的 Win32 專案來了解一個簡單的示例。

步驟 1 - 開啟 Visual Studio 並單擊“檔案”→“新建”→“專案”選單選項。

步驟 2 - 您現在可以看到“新建專案”對話方塊。

Windows Application

步驟 3 - 從左側窗格中選擇“模板”→“Visual C++”→“Win32”。

步驟 4 - 在中間窗格中,選擇“Win32 專案”。

步驟 5 - 在“名稱”欄位中輸入專案名稱“MFCWindowDemo”,然後單擊“確定”繼續。您將看到以下對話方塊。

Select Win32 Project

步驟 6 - 單擊“下一步”。

Win32 Application Setting

步驟 7 - 選擇上面對話方塊中顯示的選項,然後單擊“完成”。

MFCWindowsDemo

步驟 8 - 建立了一個空專案。

步驟 9 - 要將其設為 MFC 專案,請右鍵單擊該專案並選擇“屬性”。

MFCWindowDemo Property Page

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

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

步驟 12 - 新增一個新的原始檔。

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

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

MFCWindowDemo Add New Item

步驟 15 − 將名稱設定為 Example 並單擊新增。

視窗建立

任何應用程式都有兩個主要部分:

  • 框架或視窗

讓我們按照以下步驟建立一個視窗:

步驟 1 − 要建立應用程式,我們需要從 MFC 的 CWinApp 派生一個類。

#include
class CExample : public CWinApp {
   BOOL InitInstance() {
      return TRUE;
   }
};

步驟 2 − 我們還需要一個框架/視窗來顯示應用程式的內容。

步驟 3 − 為此,我們需要新增另一個類並從 MFC 的CFrameWnd類派生,並實現其建構函式並呼叫 Create() 方法,該方法將建立一個框架/視窗,如下面的程式碼所示。

class CMyFrame : public CFrameWnd {
   public:
      CMyFrame() {
         Create(NULL, _T("MFC Application Tutorial"));
      }
};

步驟 4 − 如您所見,Create() 方法需要兩個引數,類的名稱,應將其作為 NULL 傳遞,以及視窗的名稱,該名稱是將在標題欄中顯示的字串。

主視窗

建立視窗後,要讓應用程式使用它,可以使用指標來顯示用於建立視窗的類。在這種情況下,指標將是 CFrameWnd。要使用框架視窗,請將其指標分配給 CWinThread::m_pMainWnd 成員變數。這在應用程式的 InitInstance() 實現中完成。

步驟 1 − 以下是 CExample 類中 InitInstance() 的實現。

class CExample : public CWinApp {
   BOOL InitInstance() {
      CMyFrame *Frame = new CMyFrame();  m_pMainWnd = Frame;
      
      Frame->ShowWindow(SW_NORMAL);
      Frame->UpdateWindow();
      
      return TRUE;
   }
};

步驟 2 − 以下是 Example.cpp 檔案的完整實現。

#include <afxwin.h>

class CMyFrame : public CFrameWnd {
   public:
      CMyFrame() {
         Create(NULL, _T("MFC Application Tutorial"));
      }
};

class CExample : public CWinApp {
   BOOL InitInstance() {
      CMyFrame *Frame = new CMyFrame();
      m_pMainWnd = Frame;
      
      Frame->ShowWindow(SW_NORMAL);
      Frame->UpdateWindow();
      
      return TRUE;
   }
};

CExample theApp;

步驟 3 − 當我們執行上述應用程式時,將建立以下視窗。

Created Window

視窗樣式

視窗樣式是控制視窗外觀、邊框、最小化或最大化狀態或其他調整大小狀態等功能的特性。

序號 樣式和說明
1

WS_BORDER

建立具有邊框的視窗。

2

WS_CAPTION

建立一個具有標題欄的視窗(暗示 WS_BORDER 樣式)。不能與 WS_DLGFRAME 樣式一起使用。

3

WS_CHILD

建立一個子視窗。不能與 WS_POPUP 樣式一起使用。

4

WS_CHILDWINDOW

與 WS_CHILD 樣式相同。

5

WS_CLIPCHILDREN

在父視窗內繪製時,排除子窗口占據的區域。在建立父視窗時使用。

6

WS_CLIPSIBLINGS

剪輯彼此相關的子視窗;也就是說,當特定子視窗收到繪製訊息時,WS_CLIPSIBLINGS 樣式會將所有其他重疊的子視窗從要更新的子視窗區域剪裁掉。(如果沒有給出 WS_CLIPSIBLINGS 並且子視窗重疊,當您在子視窗的客戶區內繪製時,可能會在相鄰子視窗的客戶區內繪製。)僅與 WS_CHILD 樣式一起使用。

7

WS_DISABLED

建立一個最初停用的視窗。

8

WS_DLGFRAME

建立一個具有雙邊框但沒有標題的視窗。

9

WS_GROUP

指定一組控制元件中的第一個控制元件,使用者可以使用箭頭鍵在這些控制元件之間移動。在第一個控制元件之後,使用 WS_GROUP 樣式為 FALSE 定義的所有控制元件都屬於同一組。下一個具有 WS_GROUP 樣式的控制元件將開始下一組(即,一組在下一組開始的地方結束)。

10

WS_HSCROLL

建立一個具有水平捲軸的視窗。

11

WS_ICONIC

建立一個最初最小化的視窗。與 WS_MINIMIZE 樣式相同。

12

WS_MAXIMIZE

建立一個最大尺寸的視窗。

13

WS_MAXIMIZEBOX

建立一個具有最大化按鈕的視窗。

14

WS_MINIMIZE

建立一個最初最小化的視窗。僅與 WS_OVERLAPPED 樣式一起使用。

15

WS_MINIMIZEBOX

建立一個具有最小化按鈕的視窗。

16

WS_OVERLAPPED

建立一個重疊視窗。重疊視窗通常具有標題欄和邊框。

17

WS_OVERLAPPED WINDOW

使用 WS_OVERLAPPED、WS_CAPTION、WS_SYSMENU、WS_THICKFRAME、WS_MINIMIZEBOX 和 WS_MAXIMIZEBOX 樣式建立一個重疊視窗。

18

WS_POPUP

建立一個彈出視窗。不能與 WS_CHILD 樣式一起使用。

19

WS_POPUPWINDOW

使用 WS_BORDER、WS_POPUP 和 WS_SYSMENU 樣式建立一個彈出視窗。必須將 WS_CAPTION 樣式與 WS_POPUPWINDOW 樣式組合才能使控制選單可見。

20

WS_SIZEBOX

建立一個具有調整大小邊框的視窗。與 WS_THICKFRAME 樣式相同。

21

WS_SYSMENU

建立一個在標題欄中具有控制選單框的視窗。僅用於具有標題欄的視窗。

22

WS_TABSTOP

指定任何數量的控制元件之一,使用者可以使用 TAB 鍵在這些控制元件之間移動。TAB 鍵將使用者移動到由 WS_TABSTOP 樣式指定的下一個控制元件。

23

WS_THICKFRAME

建立一個具有粗邊框的視窗,可用於調整視窗大小。

24

WS_TILED

建立一個重疊視窗。重疊視窗具有標題欄和邊框。與 WS_OVERLAPPED 樣式相同。

25

WS_TILEDWINDOW

使用 WS_OVERLAPPED、WS_CAPTION、WS_SYSMENU、WS_THICKFRAME、WS_MINIMIZEBOX 和 WS_MAXIMIZEBOX 樣式建立一個重疊視窗。與 WS_OVERLAPPEDWINDOW 樣式相同。

26

WS_VISIBLE

建立一個最初可見的視窗。

27

WS_VSCROLL

建立一個具有垂直捲軸的視窗。

步驟 1 − 讓我們看看一個簡單的示例,我們將在其中新增一些樣式。建立視窗後,要將其顯示給使用者,我們可以對其應用 WS_VISIBLE 樣式,此外,我們還將新增 WS_OVERLAPPED 樣式。以下是實現:

class CMyFrame : public CFrameWnd {
   public:
      CMyFrame() {
         Create(NULL, _T("MFC Application Tutorial"), WS_VISIBLE | WS_OVERLAPPED);
      }
};

步驟 2 − 執行此應用程式後,將建立以下視窗。

Created Window

您現在可以看到最小化、最大化和關閉選項不再出現。

視窗位置

為了定位顯示在顯示器上的內容,計算機使用類似於笛卡爾座標系的座標系,但原點位於螢幕的左上角。使用此座標系,任何點都可以透過其到螢幕左上角的水平和垂直軸的距離來定位。

Win32 庫提供了一個名為 POINT 的結構,定義如下:

typedef struct tagPOINT {
   LONG x;
   LONG y;
} POINT;
  • “x”成員變數是從螢幕的左邊界到該點的距離。

  • “y”變量表示從螢幕的上邊界到該點的距離。

  • 除了 Win32 的 POINT 結構外,Microsoft Foundation Class (MFC) 庫還提供了 CPoint 類。

  • 這提供了與 POINT 結構相同的功能。作為 C++ 類,它添加了定位點所需的更多功能。它提供了兩個建構函式。

CPoint();
CPoint(int X, int Y);

視窗大小

雖然點用於在螢幕上定位物件,但每個視窗都有一個大小。大小提供了與物件相關的兩個度量。

  • 物件的寬度。
  • 物件的高度。

Win32 庫使用如下定義的 SIZE 結構:

typedef struct tagSIZE {
   int cx;
   int cy;
} SIZE;

除了 Win32 的 SIZE 結構外,MFC 還提供了 CSize 類。此類具有與 SIZE 相同的功能,但添加了 C++ 類的功能。它提供了五個建構函式,允許您以任何您選擇的方式建立大小變數。

CSize();
CSize(int initCX, int initCY);
CSize(SIZE initSize);
CSize(POINT initPt);
CSize(DWORD dwSize);

視窗尺寸

當視窗顯示時,可以透過其相對於顯示器邊界的​​位置在螢幕上識別它。還可以透過其寬度和高度來識別視窗。這些特性由Create()方法的rect引數指定或控制。此引數是一個可以透過 Win32 RECT 結構建立的矩形。

typedef struct _RECT {
   LONG left;
   LONG top;
   LONG right;
   LONG bottom;
} RECT, *PRECT;

除了 Win32 的RECT結構外,MFC 還提供了 CRect 類,它具有以下建構函式:

CRect();
CRect(int l, int t, int r, int b);
CRect(const RECT& srcRect);
CRect(LPCRECT lpSrcRect);
CRect(POINT point, SIZE size);
CRect(POINT topLeft, POINT bottomRight);

讓我們看看一個簡單的示例,我們將在其中指定視窗的位置和大小

class CMyFrame : public CFrameWnd {
   public:
      CMyFrame() {
         Create(NULL, _T("MFC Application Tutorial"), WS_SYSMENU, CRect(90, 120, 
            550, 480));
      }
};

執行此應用程式後,將在螢幕的左上角建立以下視窗,如 CRect 建構函式的前兩個引數中指定的那樣。最後兩個引數是視窗的大小。

Created Application Window

視窗父級

在現實世界中,許多應用程式由不同的視窗組成。當應用程式使用各種視窗時,大多數物件都依賴於特定視窗。它可能是建立的第一個視窗,也可能是您指定的另一個視窗。這樣的視窗稱為父視窗。所有其他視窗都直接或間接地依賴於它。

  • 如果您要建立的視窗依賴於另一個視窗,則可以指定它具有父級。

  • 這是透過 CFrameWnd::Create() 方法的 pParentWnd 引數完成的。

  • 如果視窗沒有父級,則使用 NULL 值傳遞引數。

讓我們看看一個只有一個視窗的示例,並且沒有可用的父視窗,因此我們將使用 NULL 值傳遞引數,如下面的程式碼所示:

class CMyFrame : public CFrameWnd {
   public:
      CMyFrame() {
         Create(NULL, _T("MFC Application Tutorial"), WS_SYSMENU, 
            CRect(90, 120, 550, 480), NULL);
      }
};

執行上述應用程式後,您會看到相同的輸出。

Created Application Window

MFC - 對話方塊

在本章中,我們將介紹對話方塊。Windows 應用程式經常透過對話方塊與使用者通訊。CDialog 類提供了管理對話方塊的介面。Visual C++ 對話方塊編輯器使設計對話方塊和建立其對話方塊模板資源變得容易。

  • 建立對話方塊物件是一個兩階段操作:

    • 構造對話方塊物件。

    • 建立對話方塊視窗。

讓我們透過建立一個新的 Win32 專案來了解一個簡單的示例。

步驟 1 - 開啟 Visual Studio 並單擊“檔案”→“新建”→“專案”選單選項。

步驟 2 - 您現在可以看到“新建專案”對話方塊。

New Project Dialog Box

步驟 3 - 從左側窗格中選擇“模板”→“Visual C++”→“Win32”。

步驟 4 - 在中間窗格中,選擇“Win32 專案”。

步驟 5 − 在“名稱”欄位中輸入專案名稱“MFCDialogDemo”,然後單擊“確定”繼續。您將看到以下對話方塊。

MFCDialogDemo Project

步驟 6 - 單擊“下一步”。

MFCDialogDemo Setting

步驟 7 − 選擇上面給出的對話方塊中顯示的選項,然後單擊“完成”。

MFCDialogDemo Options

步驟 8 - 建立了一個空專案。

步驟 9 − 要將其設為 MFC 專案,請右鍵單擊該專案並選擇“屬性”。

MFCDialogDemo Property

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

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

步驟 12 - 新增一個新的原始檔。

步驟 13 − 右鍵單擊您的專案,然後選擇“新增”→“新建項”。

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

MFCDialogDemo Add Item

步驟 15 − 將名稱設定為 Example 並單擊新增。

步驟 16 − 要建立應用程式,我們需要新增一個類並從 MFC 的 CWinApp 派生。

#include <afxwin.h>

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

對話方塊建立

步驟 1 − 要建立對話方塊,請右鍵單擊解決方案資源管理器中的“資原始檔”資料夾,然後選擇“新增”→“資源”。

Add Resource

步驟 2 − 在“新增資源”對話方塊中,選擇“對話方塊”,然後單擊“新建”。

步驟 3 − 在實際以程式設計方式建立對話方塊之前,需要進行一些準備工作。

步驟 4 − 對話方塊可以首先手動建立為文字檔案(在資原始檔中)。

步驟 5 − 您現在可以看到在“資原始檔”下建立的 MFCDialogDemo.rc 檔案。

MFCDialogDemo FIle

步驟 6 − 資原始檔在設計器中開啟。同一個檔案可以作為文字檔案開啟。右鍵單擊資原始檔並選擇“開啟方式”。

Open With MFCDialogDemo File

步驟 7 − 選擇“原始碼(文字)”編輯器,然後單擊“新增”按鈕。

Source Code Editor

步驟 8 − 返回設計器,右鍵單擊對話方塊並選擇“屬性”。

DialogBox Select Properties

步驟 9 − 您需要從眾多選項中進行選擇。

步驟 10 − 與大多數其他控制元件一樣,必須識別對話方塊。對話方塊的識別符號 (ID) 通常以 IDD_ 開頭,讓我們將 ID 更改為 IDD_EXAMPLE_DLG。

對話方塊位置

對話方塊必須“物理”地位於應用程式上。因為對話方塊通常被建立為其他控制元件的父級,所以其位置取決於它與其父視窗或桌面的關係。

如果檢視“屬性”視窗,您會看到兩個欄位,“X 位置”和“Y 位置”。

Dialog Location
  • X 是從顯示器左邊界到對話方塊左邊界的距離。

  • Y 是從顯示器上邊界到對話方塊上邊界的距離。

預設情況下,這些欄位設定為零。您也可以按照上圖所示進行更改。

如果您將這兩個維度指定為 0,則對話方塊的左邊界和上邊界將被設定為使物件顯示在螢幕的中央。

對話方塊尺寸

對話方塊的尺寸指的是它的寬度和高度。您可以在設計器視窗中使用滑鼠調整寬度和高度。

Dialog Box Dimension

您可以在狀態列上看到寬度和高度的變化。

對話方塊方法

用於在螢幕上顯示對話方塊的基本類是 CDialog 類。要建立對話方塊,我們需要從 CDialog 派生一個類。CDialog 類本身提供了三個建構函式,如下所示:

CDialog();
CDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL);
CDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL);

讓我們建立另一個類 CExampleDlg 並從 CDialog 派生它。我們將實現其預設建構函式和解構函式,如下面的程式碼所示。

class CExampleDlg : public CDialog {
   public:
      enum { IDD = IDD_EXAMPLE_DLG };
   
      CExampleDlg();
      ~CExampleDlg();
};

CExampleDlg::CExampleDlg():CDialog(CExampleDlg::IDD) {

}

CExampleDlg::~CExampleDlg() {

}

我們需要在 CExample::InitInstance() 方法中例項化此對話方塊,如下面的程式碼所示。

BOOL CExample::InitInstance() {
   CExampleDlg myDlg;
   m_pMainWnd = &myDlg;
   
   return TRUE;
}

模態對話方塊

對話方塊有兩種型別:**無模式**和**模態**。模態和無模式對話方塊的區別在於建立和顯示它們的過程。

無模式對話方塊

  • 對於無模式對話方塊,您必須在對話方塊類中提供自己的公共建構函式。

  • 要建立無模式對話方塊,請呼叫您的公共建構函式,然後呼叫對話方塊物件的 Create 成員函式來載入對話方塊資源。

  • 您可以在建構函式呼叫期間或之後呼叫 Create。如果對話方塊資源具有 WS_VISIBLE 屬性,則對話方塊會立即出現。

  • 如果不是,則必須呼叫其 ShowWindow 成員函式。

模態對話方塊

  • 要建立模態對話方塊,請呼叫在 CDialog 中宣告的兩個公共建構函式之一。

  • 接下來,呼叫對話方塊物件的**DoModal**成員函式來顯示對話方塊並管理與它的互動,直到使用者選擇“確定”或“取消”。

  • DoModal 進行的這種管理使得對話方塊成為模態對話方塊。對於模態對話方塊,DoModal 會載入對話方塊資源。

**步驟 1** - 要以模態方式顯示對話方塊,請在 CExample::InitInstance() 事件中使用您的對話方塊變數呼叫 DoModal() 方法:

BOOL CExample::InitInstance() {
   CExampleDlg myDlg;
   m_pMainWnd = &myDlg;
   myDlg.DoModal();
   return TRUE;
}

**步驟 2** - 以下是 Example.cpp 檔案的完整實現。

#include <afxwin.h>
#include "resource.h"

class CExample : public CWinApp {
   public:
      BOOL InitInstance();
};
   
class CExampleDlg : public CDialog {
   public:
      enum { IDD = IDD_EXAMPLE_DLG };
   
      CExampleDlg();
     ~CExampleDlg();
};

CExampleDlg::CExampleDlg():CDialog(CExampleDlg::IDD) {

}

CExampleDlg::~CExampleDlg() {

}

BOOL CExample::InitInstance() {
   CExampleDlg myDlg;
   m_pMainWnd = &myDlg;
   myDlg.DoModal();
   return TRUE;
}
CExample MyApp;

**步驟 3** - 當以上程式碼編譯並執行時,您將看到以下對話方塊。

Dialog Box

基於對話方塊的應用程式

Microsoft Visual Studio 提供了一種更簡單的方法來建立主要基於對話方塊的應用程式。以下是在 Visual Studio 中使用專案模板建立對話方塊基本專案的步驟:

**步驟 1** - 開啟 Visual Studio 並單擊“檔案”→“新建”→“專案”選單選項。您將看到“新建專案”對話方塊。

Dialog Based Project Template

**步驟 2** - 從左側窗格中,選擇“模板”→“Visual C++”→“MFC”。

**步驟 3** - 在中間窗格中,選擇“MFC 應用程式”。

**步驟 4** - 在“名稱”欄位中輸入專案名稱“MFCModalDemo”,然後單擊“確定”繼續。您將看到以下對話方塊。

MFCModalDemo Application2

**步驟 5** - 單擊“下一步”。

MFCModalDemo Type

**步驟 6** - 選擇上述對話方塊中顯示的選項,然後單擊“下一步”。

MFCModalDemo Application Options

**步驟 7** - 檢查您希望在對話方塊上具有的所有選項,例如“最大化”和“最小化”框,然後單擊“下一步”。

MFCModalDemo Advanced Features

**步驟 8** - 單擊“下一步”。

MFCModalDemo Generated Classes

**步驟 9** - 它將生成這兩個類。您可以更改類的名稱,然後單擊“完成”。

**步驟 10** - 現在您可以看到 MFC 嚮導預設建立此對話方塊和專案檔案。

DialogBox Application

**步驟 11** - 執行此應用程式時,您將看到以下輸出。

MFCModalDemo Result

MFC - Windows 資源

**資源**是一個文字檔案,允許編譯器管理物件,例如圖片、聲音、滑鼠游標、對話方塊等。Microsoft Visual Studio 透過在用於程式設計的同一環境中提供必要的工具,使得建立資原始檔變得特別容易。這意味著,您通常不必使用外部應用程式來建立或配置資原始檔。以下是一些與資源相關的重要的功能。

  • 資源是向用戶提供資訊的介面元素。

  • 點陣圖、圖示、工具欄和游標都是資源。

  • 某些資源可以被操作以執行操作,例如從選單中選擇或在對話方塊中輸入資料。

  • 應用程式可以使用各種資源,這些資源彼此獨立地執行,這些資源被分組到副檔名為 *.rc 的文字檔案中。

  • 大多數資源都是透過從“新增資源”對話方塊中選擇所需的資源來建立的。

Add Resource
  • “新增資源”對話方塊提供了廣泛的資源列表,可以根據需要使用,但如果您需要某些不可用的資源,則可以在執行程式之前手動將其新增到 *.rc 檔案中。

識別符號

**識別符號**是一個符號,它是一個常量整數,其名稱通常以 ID 開頭。它由兩部分組成:一個文字字串(符號名稱)對映到一個整數值(符號值)。

  • 符號提供了一種描述性方式來引用資源和使用者介面物件,無論是在您的原始碼中還是在資源編輯器中使用它們時。

  • 當您建立新的資源或資源物件時,**資源編輯器**將為資源提供預設名稱,例如 IDC_DIALOG1,併為其分配一個值。

  • 名稱加值的定義儲存在 Resource.h 檔案中。

**步驟 1** - 讓我們看一下上一章中**CMFCDialogDemo**示例,在該示例中,我們建立了一個對話方塊,其 ID 為**IDD_EXAMPLE_DLG**。

CMFCDialogDemo

**步驟 2** - 轉到“解決方案資源管理器”,您將在“標頭檔案”下看到 resource.h 檔案。繼續在編輯器中開啟此檔案,您將看到對話方塊識別符號及其整數值。

Identifiers2

圖示

**圖示**是在視窗上使用的小圖片,代表一個應用程式。它主要用於兩種場景。

  • 在視窗的框架上,它顯示在標題欄中視窗名稱的左側。

  • 在 Windows 資源管理器、桌面、“我的電腦”或“控制面板”視窗中。

如果您檢視我們的 MFCModalDemo 示例,您會發現 Visual Studio 正在為標題欄使用預設圖示,如下面的快照所示。

Icons

您可以按照以下步驟建立自己的圖示:

**步驟 1** - 右鍵單擊您的專案並選擇“新增”→“資源”,您將看到“新增資源”對話方塊。

Select Add Resources

**步驟 2** - 選擇“圖示”並單擊“新建”按鈕,您將看到以下圖示。

Icon

**步驟 3** - 在“解決方案資源管理器”中,轉到“資源檢視”並展開 MFCModalDemo > 圖示。您將看到兩個圖示。IDR_MAINFRAME 是預設圖示,IDI_ICON1 是新建立的圖示。

**步驟 4** - 右鍵單擊新建立的圖示並選擇“屬性”。

**步驟 5** - IDI_ICON1 是此圖示的 ID,現在讓我們將其 ID 更改為 IDR_MYICON。

**步驟 6** - 現在您可以根據需要在設計器中更改此圖示。我們將使用相同的圖示。

**步驟 7** - 儲存此圖示。

**步驟 8** - 轉到 CMFCModalDemoDlg.cpp 檔案中的 CMFCModalDemoDlg 建構函式,它將如下所示。

CMFCModalDemoDlg::CMFCModalDemoDlg(CWnd* pParent /* = NULL*/)
   : CDialogEx(IDD_MFCMODALDEMO_DIALOG, pParent) {
   m_hIcon = AfxGetApp() -> LoadIcon(IDR_MAINFRAME);
}

**步驟 9** - 現在您可以看到預設圖示已載入到建構函式中。讓我們將其更改為 IDR_MYICON,如下面的程式碼所示。

CMFCModalDemoDlg::CMFCModalDemoDlg(CWnd* pParent /* = NULL*/)
   : CDialogEx(IDD_MFCMODALDEMO_DIALOG, pParent) {
   m_hIcon = AfxGetApp() -> LoadIcon(IDR_ MYICON);
}

**步驟 10** - 當以上程式碼編譯並執行時,您將看到新圖示顯示在對話方塊上。

Modal Demo

選單

**選單**允許您以邏輯且易於查詢的方式排列命令。使用選單編輯器,您可以透過直接使用與完成的應用程式中的選單欄非常相似的選單欄來建立和編輯選單。要建立選單,請按照以下步驟操作:

**步驟 1** - 右鍵單擊您的專案並選擇“新增”→“資源”。您將看到“新增資源”對話方塊。

Add Resources Menu

**步驟 2** - 選擇“選單”並單擊“新建”。您將在選單欄上看到包含“在此處鍵入”的矩形。

Type Here on Menu Bar

**步驟 3** - 編寫一些選單選項,如“檔案”、“編輯”等,如下面的快照所示。

Menu Options

**步驟 4** - 如果您在“資源檢視”中展開“選單”資料夾,您將看到選單識別符號 IDR_MENU1。右鍵單擊此識別符號並將其更改為 IDM_MAINMENU。

Menu Identifier

**步驟 5** - 儲存所有更改。

**步驟 6** - 我們需要將此選單附加到我們的對話方塊。在“解決方案資源管理器”中展開您的“對話方塊”資料夾,然後雙擊對話方塊識別符號。

Dialog Folder

**步驟 7** - 您將在“屬性”中看到“選單”欄位。從下拉列表中選擇選單識別符號,如上所示。

**步驟 8** - 執行此應用程式,您將看到以下對話方塊,其中還包含選單選項。

Menu Option

工具欄

**工具欄**是 Windows 控制元件,允許使用者透過單擊按鈕而不是使用選單來在表單上執行某些操作。

  • 工具欄提供了一組方便的按鈕,透過將最容易訪問的操作作為按鈕來簡化使用者的工作。

  • 工具欄可以將此類常見操作更靠近使用者。

  • 工具欄通常顯示在主選單下方。

  • 它們可以配備按鈕,但有時它們的按鈕或某些按鈕帶有標題。

  • 工具欄還可以配備其他型別的控制元件。

要建立工具欄,請按照以下步驟操作。

**步驟 1** - 右鍵單擊您的專案並選擇“新增”→“資源”。您將看到“新增資源”對話方塊。

Toolbar

**步驟 2** - 選擇“工具欄”並單擊“新建”。您將看到以下螢幕。

Select Toolbar

**步驟 3** - 在設計器中設計您的工具欄,如下面的螢幕截圖所示,並指定 ID。

Design Toolbar

**步驟 4** - 在 CMFCModalDemoDlg 類中新增這兩個變數。

   CToolBar m_wndToolBar;
   BOOL butD;

**步驟 5** - 以下是 CMFCModalDemoDlg.h 檔案中 CMFCModalDemoDlg 的完整實現:

class CMFCModalDemoDlg : public CDialogEx {
   // Construction
   public:
      CMFCModalDemoDlg(CWnd* pParent = NULL); // standard constructor
   // Dialog Data
   #ifdef AFX_DESIGN_TIME
      enum { IDD = IDD_MFCMODALDEMO_DIALOG };
   #endif

   protected:
      virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
   
   // Implementation
   protected:
      HICON m_hIcon;
      CToolBar m_wndToolBar;
      BOOL butD;
   
      // Generated message map functions
      virtual BOOL OnInitDialog();
      afx_msg void OnPaint();
      afx_msg HCURSOR OnQueryDragIcon();
      DECLARE_MESSAGE_MAP()
	
   public:
      afx_msg void OnBnClickedOk();
};

**步驟 6** - 更新 CMFCModalDemoDlg::OnInitDialog(),如下面的程式碼所示。

BOOL CMFCModalDemoDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();
   
   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);       // Set big icon
   SetIcon(m_hIcon, FALSE);      // Set small icon
   
   if (!m_wndToolBar.Create(this)
      || !m_wndToolBar.LoadToolBar(IDR_TOOLBAR1))
      //if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD |
      // WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS |
      // CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
      // !m_wndToolBar.LoadToolBar(IDR_TOOLBAR1)) {
         TRACE0("Failed to Create Dialog Toolbar\n");
         EndDialog(IDCANCEL);
      }
      butD = TRUE;
      CRect rcClientOld; // Old Client Rect
      CRect rcClientNew; // New Client Rect with Tollbar Added
		
      // Retrive the Old Client WindowSize
      // Called to reposition and resize control bars in the client area of a window
      // The reposQuery FLAG does not really traw the Toolbar. It only does the calculations.
      // And puts the new ClientRect values in rcClientNew so we can do the rest of the Math.
      
      GetClientRect(rcClientOld);
      RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0, reposQuery, rcClientNew);
      // All of the Child Windows (Controls) now need to be moved so the Tollbar does not cover them up.
      // Offest to move all child controls after adding Tollbar 
      CPoint ptOffset(rcClientNew.left - rcClientOld.left, rcClientNew.top - rcClientOld.top); 
		 
      CRect rcChild;
      CWnd* pwndChild = GetWindow(GW_CHILD); //Handle to the Dialog Controls
      
      while (pwndChild) // Cycle through all child controls {
         pwndChild -> GetWindowRect(rcChild); // Get the child control RECT
         ScreenToClient(rcChild);
          
         // Changes the Child Rect by the values of the claculated offset
         rcChild.OffsetRect(ptOffset);
         pwndChild -> MoveWindow(rcChild, FALSE); // Move the Child Control
         pwndChild = pwndChild -> GetNextWindow();
      }
       
      CRect rcWindow;
      // Get the RECT of the Dialog
      GetWindowRect(rcWindow);
       
      // Increase width to new Client Width
      rcWindow.right += rcClientOld.Width() - rcClientNew.Width();
       
      // Increase height to new Client Height
       rcWindow.bottom += rcClientOld.Height() - rcClientNew.Height();
      // Redraw Window
      MoveWindow(rcWindow, FALSE);
       
      // Now we REALLY Redraw the Toolbar
      RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);
       
   // TODO: Add extra initialization here

   return TRUE; // return TRUE unless you set the focus to a control
}

**步驟 7** - 執行此應用程式。您將看到以下對話方塊,其中還包含工具欄。

Toolbar4

加速鍵

**訪問鍵**是一個字母,允許使用者透過使用鍵盤而不是滑鼠來更快地執行選單操作。這通常更快,因為使用者不需要將滑鼠定位在任何位置,從而減少了執行操作所需的時間。

**步驟 1** - 要建立訪問鍵,請在選單項左側鍵入一個“&”符號。

Create an Access Key

**步驟 2** - 對所有選單選項重複此步驟。執行此應用程式並按 Alt。您將看到所有選單選項的第一個字母都帶下劃線。

Menu Option

快捷鍵

快捷鍵是高階使用者用來執行操作的鍵或鍵組合,這些操作原本需要透過選單項來完成。大多數快捷鍵都是同時按下 Ctrl 鍵和一個字母鍵的組合。例如,Ctrl + N、Ctrl + O 或 Ctrl + D。

要建立快捷鍵,在構成選單標題的字串右側,右鍵單擊選單項並選擇屬性。

在“標題”欄位中鍵入 \t 後跟所需的組合,如下所示,用於“新建”選單選項。對所有選單選項重複此步驟。

Shortcut Key

加速器表

加速器表是一個專案的列表,其中表中的每個專案都組合了識別符號、快捷鍵和一個指定加速器鍵型別的常量數字。就像其他資源一樣,可以在 .rc 檔案中手動建立加速器表。以下是建立加速器表的步驟。

步驟 1 - 要建立加速器表,請在解決方案資源管理器中右鍵單擊 *.rc 檔案。

Accelerator Table

步驟 2 - 選擇“加速器”並單擊“新建”。

Select Accelerator

步驟 3 - 單擊 ID 組合框的箭頭並選擇選單項。

Accelerator Table

步驟 4 - 從“修飾符”下拉列表中選擇 Ctrl。

步驟 5 - 單擊“鍵”框併為兩個選單選項鍵入相應的鍵。

我們還將向測試中新增“新建”選單項事件處理程式。右鍵單擊“新建”選單選項。

Event Handler

步驟 6 - 您可以指定類、訊息型別和處理程式名稱。目前,讓我們保持原樣,然後單擊“新增和編輯”按鈕。

Message Type  Handler Name

步驟 7 - 選擇“新增事件處理程式”。

步驟 8 - 您現在將在 CMFCModalDemoDlg.cpp 檔案的末尾看到新增的事件。

void CMFCModalDemoDlg::OnFileNew() {
   // TODO: Add your command handler code here
   MessageBox(L"File > New menu option");
}

步驟 9 - 現在讓我們新增一個訊息框,該訊息框將顯示簡單的選單選項訊息。

要在工作中啟動加速器表,請新增 HACCEL 變數和 ProcessMessageFilter,如下面的 CMFCModalDemoApp 中所示。

class CMFCModalDemoApp : public CWinApp {
   public:
      CMFCModalDemoApp();
   
   // Overrides
   public:
      virtual BOOL InitInstance();
      HACCEL m_hAccelTable;
      
      // Implementation

      DECLARE_MESSAGE_MAP()
      virtual BOOL ProcessMessageFilter(int code, LPMSG lpMsg);
};

步驟 10 - 載入加速器並在 CMFCModalDemoApp::InitInstance() 中進行以下呼叫。

m_hAccelTable = LoadAccelerators(AfxGetInstanceHandle(),
   MAKEINTRESOURCE(IDR_ACCELERATOR1));

步驟 11 - 這是 ProcessMessageFilter 的實現。

BOOL CMFCModalDemoApp::ProcessMessageFilter(int code, LPMSG lpMsg) {
   if (code >= 0 && m_pMainWnd && m_hAccelTable) {
      if (::TranslateAccelerator(m_pMainWnd -> m_hWnd, m_hAccelTable, lpMsg))
      return TRUE;
   }
   return CWinApp::ProcessMessageFilter(code, lpMsg);
}

步驟 12 - 當編譯並執行上述程式碼時,您將看到以下輸出。

Accelerator Result

步驟 13 - 按 Alt 鍵,然後按 F 鍵,再按 N 鍵或 Ctrl + N。您將看到以下訊息。

Accelerator Table

MFC - 屬性表

屬性表,也稱為選項卡對話方塊,是一個包含屬性頁的對話方塊。每個屬性頁都基於對話方塊模板資源幷包含控制元件。它在一個頁面上封閉,頂部有一個選項卡。選項卡命名頁面並指示其用途。使用者單擊屬性表中的選項卡以選擇一組控制元件。

要建立屬性頁,讓我們透過建立一個基於 MFC 的對話方塊專案來了解一個簡單的示例。

MFC Project

建立專案後,我們需要新增一些屬性頁。

Visual Studio 透過顯示“新增資源”對話方塊、展開“對話方塊”節點並選擇其中一個 IDD_PROPPAGE_X 項,從而輕鬆建立屬性頁的資源。

步驟 1 - 在解決方案資源管理器中右鍵單擊您的專案,然後選擇“新增”→“資源”。

IDD Propage Larg

步驟 2 - 選擇 IDD_PROPPAGE_LARGE 並單擊“新建”。

IDD Propage Larg New

步驟 3 - 讓我們將此屬性頁的 ID 和標題分別更改為IDD_PROPPAGE_1屬性頁 1,如上所示。

步驟 4 - 在設計器視窗中右鍵單擊屬性頁。

Propage in Designer Window

步驟 5 - 選擇“新增類”選項。

Propage Add Class Option

步驟 6 - 輸入類名並從基類下拉列表中選擇 CPropertyPage。

步驟 7 - 單擊“完成”繼續。

步驟 8 - 透過遵循上述步驟,再新增一個 ID 為 IDD_PROPPAGE_2、標題為屬性頁 2 的屬性頁。

步驟 9 - 您現在可以看到建立了兩個屬性頁。要實現其功能,我們需要一個屬性表。

屬性表將屬性頁組合在一起並將其保留為實體。

要建立屬性表,請按照以下步驟操作 -

步驟 1 - 右鍵單擊您的專案,然後選擇“新增”>“類”選單選項。

Create Property Sheet

步驟 2 - 從左側窗格中選擇“Visual C++”→“MFC”,從模板窗格中選擇“MFC 類”,然後單擊“新增”。

MFC Class in Template Pane

步驟 3 - 輸入類名並從基類下拉列表中選擇 CPropertySheet。

步驟 4 - 單擊“完成”繼續。

步驟 5 - 要啟動此屬性表,我們需要對我們的主專案類進行以下更改。

步驟 6 - 在 CMFCPropSheetDemo.cpp 檔案中新增以下引用。

#include "MySheet.h"
#include "PropPage1.h"
#include "PropPage2.h"

步驟 7 - 修改 CMFCPropSheetDemoApp::InitInstance() 方法,如下面的程式碼所示。

CMySheet mySheet(L"Property Sheet Demo");
CPropPage1 page1;
CPropPage2 page2;

mySheet.AddPage(&page1);
mySheet.AddPage(&page2);

m_pMainWnd = &mySheet;
INT_PTR nResponse = mySheet.DoModal();

步驟 8 - 這是 CMFCPropSheetDemo.cpp 檔案的完整實現。

// MFCPropSheetDemo.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "MFCPropSheetDemo.h"
#include "MFCPropSheetDemoDlg.h"
#include "MySheet.h"
#include "PropPage1.h"
#include "PropPage2.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMFCPropSheetDemoApp
BEGIN_MESSAGE_MAP(CMFCPropSheetDemoApp, CWinApp)
   ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CMFCPropSheetDemoApp construction

CMFCPropSheetDemoApp::CMFCPropSheetDemoApp() {

   // support Restart Manager
   m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
   // TODO: add construction code here,
   // Place all significant initialization in InitInstance
}


// The one and only CMFCPropSheetDemoApp object

CMFCPropSheetDemoApp theApp;


// CMFCPropSheetDemoApp initialization

BOOL CMFCPropSheetDemoApp::InitInstance() {
   
   // InitCommonControlsEx() is required on Windows XP if an application
   // manifest specifies use of ComCtl32.dll version 6 or later to enable
   // visual styles. Otherwise, any window creation will fail.
   INITCOMMONCONTROLSEX InitCtrls;
   InitCtrls.dwSize = sizeof(InitCtrls);
   // Set this to include all the common control classes you want to use
   // in your application.
   InitCtrls.dwICC = ICC_WIN95_CLASSES;
   InitCommonControlsEx(&InitCtrls);
   
   CWinApp::InitInstance();
   
   
   AfxEnableControlContainer();
   
   // Create the shell manager, in case the dialog contains
   // any shell tree view or shell list view controls.
   CShellManager *pShellManager = new CShellManager;

   // Activate "Windows Native" visual manager for enabling themes in MFC controls
   CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
   // Standard initialization
   // If you are not using these features and wish to reduce the size
   // of your final executable, you should remove from the following
   // the specific initialization routines you do not need
   // Change the registry key under which our settings are stored
   // TODO: You should modify this string to be something appropriate
   // such as the name of your company or organization
   SetRegistryKey(_T("Local AppWizard-Generated Applications"));
   
   CMySheet mySheet(L"Property Sheet Demo");
   CPropPage1 page1;
   CPropPage2 page2;
   
   mySheet.AddPage(&page1);
   mySheet.AddPage(&page2);
   
   m_pMainWnd = &mySheet;
   INT_PTR nResponse = mySheet.DoModal();
   if (nResponse == IDOK) {
      // TODO: Place code here to handle when the dialog is
      // dismissed with OK
   }else if (nResponse == IDCANCEL) {
      // TODO: Place code here to handle when the dialog is
      // dismissed with Cancel
   }else if (nResponse == -1) {    
      TRACE(traceAppMsg, 0, "Warning: dialog creation failed, 
        so application is terminating unexpectedly.\n");
      TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, 
        you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n");
   }

   // Delete the shell manager created above.
   if (pShellManager != NULL) {
      delete pShellManager;
   }

   // Since the dialog has been closed, return FALSE so that we exit the
   // application, rather than start the application's message pump.
   return FALSE;
}

步驟 9 - 當編譯並執行上述程式碼時,您將看到以下對話方塊。此對話方塊包含兩個屬性頁。

Property Pages

MFC - Windows 佈局

控制元件佈局非常重要,對於應用程式可用性至關重要。它用於在應用程式中排列一組 GUI 元素。在選擇佈局時,需要考慮一些重要事項 -

  • 子元素的位置。
  • 子元素的大小。

新增控制元件

讓我們建立一個新的基於對話方塊的 MFC 專案 MFCLayoutDemo。

步驟 1 - 建立專案後,您將看到以下螢幕。

Create Adding Controls

步驟 2 - 從對話方塊中刪除 TODO。

步驟 3 - 從工具箱中拖動一些控制元件,您可以在左側看到它。

(我們將拖動一個靜態文字和一個編輯控制元件,如下面的快照所示)。

MFCLayoutDemo Edit

步驟 4 - 將靜態文字的標題更改為“名稱”。

Static Text to Name

控制元件網格

控制元件網格是指導網格點,可以幫助在設計時定位您正在新增的控制元件。

要啟用控制元件網格,您需要單擊工具欄中的“切換網格”按鈕,如下面的快照所示。

Control Grid

控制元件調整大小

將控制元件新增到對話方塊後,它將採用其預設大小或您繪製的大小。為了幫助調整表單或對話方塊上控制元件的大小,Visual Studio 提供了一個由黑點組成的視覺網格。

要調整控制元件的大小,即為其指定特定的寬度或高度,請將滑鼠放在其中一個控制代碼上並將其拖動到所需的方向。

Control Resizing

您現在可以使用此點狀網格調整控制元件的大小。

控制元件位置

您在對話方塊或表單上定位的控制元件將採用其給定的位置。大多數情況下,這些位置不實用。您可以將它們移動到您選擇的任何位置。

讓我們新增更多控制元件 -

Control Position

步驟 1 - 要移動控制元件,請單擊並將其拖動到所需的方向,直到到達目標位置。

步驟 2 - 要移動一組控制元件,請先選擇它們。然後將所選內容拖動到所需位置。讓我們選擇靜態文字和編輯控制元件。

Static Texts and Edit Controls

步驟 3 - 將這些選定的控制元件移動到左側。

Move Selecred Control

Move Selecred Control

為了幫助定位控制元件,Visual Studio 提供了帶有以下按鈕的“對話方塊”工具欄。

Control Position5

步驟 1 - 讓我們透過選擇所有這些控制元件將複選框和靜態文字控制元件對齊到左側。

Align Format

步驟 2 - 選擇“格式”→“對齊”→“左對齊”。

Align Left

步驟 3 - 您現在可以看到所有這些控制元件都對齊到左側。

選項卡順序

您新增到表單或對話方塊的控制元件按新增順序排列。無論您將新控制元件放置在哪個部分或區域,新增控制元件時,它都會按順序放置在現有控制元件的末尾。如果您不修復它,使用者將難以導航控制元件。控制元件導航的順序也稱為選項卡順序。

要更改選項卡,您可以使用“格式”→“選項卡順序”選單選項,也可以使用 Ctrl + D 快捷鍵。讓我們按 Ctrl + D。

Tab Ordering

您現在可以看到將所有這些控制元件新增到此對話方塊的順序。要更改控制元件的順序或序列,請按您希望導航的順序依次單擊所有控制元件。

在此示例中,我們將首先單擊複選框,然後單擊“名稱”和“地址”編輯控制元件。然後單擊“確定”和“取消”,如下面的快照所示。

Table Ordering

讓我們執行此應用程式,您將看到以下輸出。

Tab Ordering Result

MFC - 控制元件管理

在 MFC 應用程式中,在將控制元件視覺化地新增到應用程式後,如果要在程式碼中引用它,則可以根據該控制元件或與其關聯的控制元件宣告一個變數。MFC 庫允許您為應用程式中使用的一些控制元件宣告兩種型別的變數:值或控制元件變數。

  • 一個變數用於儲存在控制元件中的資訊,也稱為控制元件變數/例項

  • 另一個變數稱為控制元件值變數。使用者可以使用此變數對該控制元件執行某種操作。

控制元件變數/例項

控制元件變數是基於管理控制元件的類的變數。例如,按鈕控制元件基於 CButton 類。

要了解在實際程式設計中這些概念,讓我們建立一個基於 MFC 對話方塊的專案 MFCControlManagement。

MFCControlManagement

建立專案後,您將在設計器視窗中看到以下對話方塊。

MFCControlManagement Created

步驟 1 - 刪除 TODO 行,並拖動一個複選框和一個編輯控制元件,如下面的快照所示。將複選框的標題更改為“啟用控制元件”。

Change Caption

步驟 2 - 右鍵單擊複選框。

MFCControlManagement Checkbox

步驟 3 - 選擇“新增變數”。

步驟 4 - 您現在可以看到“新增成員變數嚮導”。

Add Member Variable

您可以在此對話方塊上選擇不同的選項。對於複選框,變數型別為 CButton。它在此對話方塊中預設選中。

同樣,控制元件 ID 也已預設選中,現在我們需要在“類別”組合框中選擇“控制元件”,在“變數名”編輯框中鍵入 m_enableDisableCheck,然後單擊“完成”。

步驟 5 - 同樣,使用如下面的快照所示的設定新增編輯控制元件的控制元件變數。

Control Variables6

觀察對話方塊類的標頭檔案。您現在可以看到已添加了新變數。

CButton m_enableDisableCheck;
CEdit m_myEditControl;

控制元件值變數

您可以為控制元件宣告的另一種型別的變數是值變數。並非所有控制元件都提供值變數。

  • 值變數必須能夠處理其旨在引用的控制元件中儲存的值的型別。

  • 例如,由於文字控制元件用於處理文字,因此您可以為其宣告一個基於文字的資料型別。這通常是一個 CString 變數。

讓我們看看複選框和編輯控制元件的這種變數型別。

步驟 1 − 右鍵單擊複選框,然後選擇“新增變數”。

Add Variable

步驟 2 − 變數型別為 BOOL。從“類別”下拉列表中選擇“值”。

步驟 3 − 單擊“完成”繼續。

步驟 4 − 同樣,使用以下快照中所示的設定,為編輯控制元件新增值變數。

Value Variables

步驟 5 − 在變數型別中鍵入 CString,在變數名稱欄位中鍵入 m_editControlVal。

步驟 6 − 現在您可以在標頭檔案中看到這些新增的變數。

bool m_enableDisableVal;
CString m_editControlVal;

控制元件事件處理程式

將控制元件新增到應用程式後,無論您是透過視覺化方式新增還是動態建立,您還需要決定如何處理使用者可能對控制元件執行的操作。

  • 對於已與類關聯的專案對話方塊,在建立事件處理程式時,您可以利用一些快捷方式。

  • 您可以快速建立預設控制元件通知事件或任何適用的 Windows 訊息的處理程式。

讓我們看看我們在其中為複選框新增事件處理程式的相同示例。

步驟 1 − 右鍵單擊要處理通知事件的控制元件。

Event Handler1

步驟 2 − 在快捷選單上,單擊“新增事件處理程式”以顯示“事件處理程式嚮導”。

Event Handler Wizard

步驟 3 − 在“訊息型別”框中選擇要新增到“類”列表框中所選類的事件。

步驟 4 − 接受“函式處理程式名稱”框中的預設名稱,或提供您選擇的名稱。

步驟 5 − 單擊“新增並編輯”以新增事件處理程式。

步驟 6 − 現在您可以在 CMFCControlManagementDlg.cpp 檔案末尾看到添加了以下事件。

void CMFCControlManagementDlg::OnBnClickedCheck1() {
   // TODO: Add your control notification handler code here
}

控制元件管理

到目前為止,我們已經瞭解瞭如何將控制元件新增到應用程式。現在,我們將瞭解如何根據使用者需求管理這些控制元件。我們可以在特定的事件處理程式中使用控制元件變數/例項。

步驟 1 − 讓我們看看以下示例。在這裡,我們將根據複選框的選中/未選中狀態啟用/停用編輯控制元件。

步驟 2 − 我們現在添加了複選框單擊事件處理程式。以下是實現方法:

void CMFCControlManagementDlg::OnBnClickedCheck1() {
   // TODO: Add your control notification handler code here
   UpdateData(TRUE);
   if (m_enableDisableVal)
      m_myEditControl.EnableWindow(TRUE);
   else
      m_myEditControl.EnableWindow(FALSE);
}

步驟 3 − 建立對話方塊時,我們需要將以下程式碼新增到 CMFCControlManagementDlg::OnInitDialog() 中。這將管理這些控制元件。

UpdateData(TRUE);
if (m_enableDisableVal)
   m_myEditControl.EnableWindow(TRUE);
else
   m_myEditControl.EnableWindow(FALSE);

步驟 4 − 以下是 CMFCControlManagementDlg.cpp 檔案的完整實現。

// MFCControlManagementDlg.cpp : implementation file
//

#include "stdafx.h"
#include "MFCControlManagement.h"
#include "MFCControlManagementDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx {
   public:
      CAboutDlg();
	
   // Dialog Data
   #ifdef AFX_DESIGN_TIME
      enum { IDD = IDD_ABOUTBOX };
   #endif

   protected:
      virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
      
   // Implementation
   protected:
      DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) {

}
void CAboutDlg::DoDataExchange(CDataExchange* pDX) {
   CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

// CMFCControlManagementDlg dialog


CMFCControlManagementDlg::CMFCControlManagementDlg(CWnd* pParent /* = NULL*/)
   :CDialogEx(IDD_MFCCONTROLMANAGEMENT_DIALOG, pParent) , 
   m_enableDisableVal(FALSE) , m_editControlVal(_T("")) {
   m_hIcon = AfxGetApp()&rarr LoadIcon(IDR_MAINFRAME);
}

void CMFCControlManagementDlg::DoDataExchange(CDataExchange* pDX) {
   CDialogEx::DoDataExchange(pDX);
   DDX_Control(pDX, IDC_CHECK1, m_enableDisableCheck);
   DDX_Control(pDX, IDC_EDIT1, m_myEditControl);
   DDX_Check(pDX, IDC_CHECK1, m_enableDisableVal);
   DDX_Text(pDX, IDC_EDIT1, m_editControlVal);
}
BEGIN_MESSAGE_MAP(CMFCControlManagementDlg, CDialogEx)
   ON_WM_SYSCOMMAND()
   ON_WM_PAINT()
   ON_WM_QUERYDRAGICON()
   ON_BN_CLICKED(IDC_CHECK1, &CMFCControlManagementDlg::OnBnClickedCheck1)
END_MESSAGE_MAP()

// CMFCControlManagementDlg message handlers

BOOL CMFCControlManagementDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();
      
   // Add "About..." menu item to system menu.
   // IDM_ABOUTBOX must be in the system command range.
   ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
   ASSERT(IDM_ABOUTBOX < 0xF000);
      
   CMenu* pSysMenu = GetSystemMenu(FALSE);
   if (pSysMenu != NULL) {
      BOOL bNameValid;
      CString strAboutMenu;
      bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
      ASSERT(bNameValid);
      if (!strAboutMenu.IsEmpty()) {
         pSysMenu → AppendMenu(MF_SEPARATOR);
         pSysMenu → AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
      }
   }
	
   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);        // Set big icon
   SetIcon(m_hIcon, FALSE);       // Set small icon

   // TODO: Add extra initialization here
   UpdateData(TRUE);
   if (m_enableDisableVal)
      m_myEditControl.EnableWindow(TRUE);
   else
      m_myEditControl.EnableWindow(FALSE);
   return TRUE; // return TRUE unless you set the focus to a control
}
void CMFCControlManagementDlg::OnSysCommand(UINT nID, LPARAM lParam) {
   if ((nID & 0xFFF0) == IDM_ABOUTBOX) {
      CAboutDlg dlgAbout;
      dlgAbout.DoModal();
   }else {
      CDialogEx::OnSysCommand(nID, lParam);
   }
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.

void CMFCControlManagementDlg::OnPaint() {
   if (IsIconic()) {
      CPaintDC dc(this); // device context for painting
      
      SendMessage(WM_ICONERASEBKGND,
         reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
			
      // Center icon in client rectangle
      int cxIcon = GetSystemMetrics(SM_CXICON);
      int cyIcon = GetSystemMetrics(SM_CYICON);
      CRect rect;
      GetClientRect(&rect);
      int x = (rect.Width() - cxIcon + 1) / 2;
      int y = (rect.Height() - cyIcon + 1) / 2;
		
      // Draw the icon
      dc.DrawIcon(x, y, m_hIcon);
   }else {
      CDialogEx::OnPaint();
   }
}

// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMFCControlManagementDlg::OnQueryDragIcon() {
   return static_cast<HCURSOR>(m_hIcon);
}

void CMFCControlManagementDlg::OnBnClickedCheck1() {
   // TODO: Add your control notification handler code here
   UpdateData(TRUE);
   if (m_enableDisableVal)
      m_myEditControl.EnableWindow(TRUE);
   else
      m_myEditControl.EnableWindow(FALSE);
}

步驟 5 − 編譯並執行上述程式碼後,您將看到以下輸出。複選框預設情況下未選中。這也將停用編輯控制元件。

Controls Management

步驟 6 − 選中“啟用控制元件”複選框。這將自動啟用編輯控制元件。

Control Management

MFC - Windows 控制元件

Windows 控制元件是使用者可以與之互動以輸入或操作資料的物件。它們通常出現在對話方塊或工具欄中。有各種型別的控制元件:

  • 基於文字的控制元件用於向用戶顯示文字或向用戶請求文字。

  • 基於列表的控制元件顯示專案列表。

  • 基於進度的控制元件用於顯示操作的進度。

  • 靜態控制元件可用於顯示顏色、圖片或不經常適合上述類別的內容。

序號 控制元件和描述
1 靜態控制元件

靜態控制元件是一個向用戶顯示資訊的物件,無需使用者的直接干預。它可以用來顯示顏色、幾何圖形或圖片,例如圖示、點陣圖或動畫。

2 動畫控制元件

動畫控制元件是一個視窗,用於顯示 AVI 格式的音訊剪輯。AVI 剪輯是一系列點陣圖幀,就像電影一樣。動畫控制元件只能播放簡單的 AVI 剪輯,並且不支援聲音。它由CAnimateCtrl類表示。

3 按鈕

按鈕是使用者單擊以啟動操作的物件。按鈕控制元件由CButton 類表示。

4 點陣圖按鈕

點陣圖按鈕在其表面上顯示圖片或圖片和文字。這通常是為了使按鈕更明確。點陣圖按鈕是使用CBitmapButton 類建立的,該類派生自 CButton。

5 命令按鈕

命令按鈕是普通按鈕的增強版。它在左側顯示一個綠色箭頭圖示,然後是常規大小的標題。在主標題下方,它可以顯示另一個較小的標題,作為提示提供更多資訊。

6 靜態文字

靜態控制元件顯示文字字串、框、矩形、圖示、游標、點陣圖或增強型圖元檔案。它由CStatic 類表示。它可以用於標記、框定或分隔其他控制元件。靜態控制元件通常不接收輸入也不提供輸出。

7 列表框

列表框顯示專案列表,例如使用者可以檢視和選擇的的檔名。列表框由CListBox 類表示。在單選列表框中,使用者只能選擇一個專案。在多選列表框中,可以選擇一系列專案。當用戶選擇一個專案時,該專案會被突出顯示,並且列表框會向父視窗傳送通知訊息。

8 組合框

組合框由列表框與靜態控制元件或編輯控制元件組合而成。它由CComboBox 類表示。控制元件的列表框部分可以始終顯示,也可以僅在使用者選擇控制元件旁邊的下拉箭頭時下拉。

9 單選按鈕

單選按鈕是一個控制元件,顯示為一個圓圈周圍的點。實際上,單選按鈕伴隨著一個或多個其他單選按鈕,這些按鈕作為一組顯示並執行。

10 複選框

複選框是一個 Windows 控制元件,允許使用者將專案的真值設定為真或假。

11 影像列表

影像列表是相同大小的影像的集合,每個影像都可以透過其基於零的索引來引用。影像列表用於有效地管理大量圖示或點陣圖。影像列表由CImageList 類表示。

12 編輯框

編輯框是使用者可以在其中輸入文字的矩形子視窗。它由CEdit 類表示。

13 富文字編輯

富文字編輯控制元件是一個視窗,使用者可以在其中輸入和編輯文字。文字可以分配字元和段落格式,並且可以包含嵌入的 OLE 物件。它由CRichEditCtrl 類表示。

14 組框

組框是一個靜態控制元件,用於設定控制元件的可視或程式設計組。該控制元件是一個矩形,將其他控制元件組合在一起。

15 微調按鈕

微調按鈕控制元件(也稱為上下控制元件)是一對箭頭按鈕,使用者可以單擊這些按鈕來增加或減少值,例如滾動位置或伴隨控制元件中顯示的數字。它由CSpinButtonCtrl 類表示。

16 管理上下控制元件

它管理上下控制元件。

17 進度控制元件

進度條控制元件是一個視窗,應用程式可以使用它來指示冗長操作的進度。它由一個矩形組成,隨著操作的進行,矩形會從左到右逐漸填充系統高亮顏色。它由CProgressCtrl 類表示。

18 進度條

進度條是一個視窗,應用程式可以使用它來指示操作的進度。

19 定時器

定時器是一個非空間物件,它使用來自計算機或應用程式的重複時間間隔。為了工作,每個時間間隔,控制元件都會向作業系統傳送訊息。與大多數其他控制元件不同,MFC 定時器既沒有按鈕來表示它,也沒有類。要建立定時器,只需呼叫 CWnd::SetTimer() 方法即可。此函式呼叫為您的應用程式建立了一個定時器。與其他控制元件一樣,定時器使用識別符號。

20 日期和時間選擇器

日期和時間選擇器控制元件 (CDateTimeCtrl) 實現了一種直觀且易於識別的輸入或選擇特定日期的方法。控制元件的主要介面在功能上類似於組合框。但是,如果使用者展開控制元件,則會顯示月曆控制元件(預設情況下),允許使用者指定特定日期。選擇日期後,月曆控制元件會自動消失。

21 圖片

如果您需要為應用程式顯示圖片,Visual C++ 提供了一個專門的控制元件用於此目的。

22 影像編輯器

影像編輯器具有一套廣泛的建立和編輯影像的工具,以及幫助您建立工具欄點陣圖的功能。除了點陣圖、圖示和游標之外,您還可以使用“影像”選單上的命令和“影像編輯器”工具欄上的工具編輯 GIF 或 JPEG 格式的影像。

23 滑塊控制元件

滑塊控制元件(也稱為軌跡條)是一個包含滑塊和可選刻度的視窗。當用戶使用滑鼠或方向鍵移動滑塊時,控制元件會發送通知訊息以指示更改。滑塊有兩種型別:水平和垂直。它由CSliderCtrl 類表示。

24 捲軸

捲軸是一個圖形控制元件元素,可以透過單擊箭頭在兩個方向上沿著控制元件滾動連續的文字、圖片或其他任何內容。此控制元件可以採用兩個方向之一:水平或垂直。它由CScrollBar類表示。

25 樹形控制元件

樹形檢視控制元件是一個視窗,用於顯示專案的層次列表,例如文件中的標題、索引中的條目或磁碟上的檔案和目錄。每個專案都包含一個標籤和一個可選的點陣圖影像,並且每個專案都可以有一系列與其關聯的子專案。透過單擊一個專案,使用者可以展開和摺疊關聯的子專案列表。它由CTreeCtrl類表示。

26 列表控制元件

封裝列表檢視控制元件的功能,列表檢視控制元件顯示專案的集合,每個專案都包含一個圖示(來自影像列表)和一個標籤。它由CListCtrl類表示。列表控制元件包括使用四種檢視之一來顯示專案列表。

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

MFC - ActiveX控制元件

ActiveX控制元件容器是一個父程式,它為ActiveX(以前稱為OLE)控制元件提供執行環境。

  • ActiveX控制元件是使用Microsoft ActiveX技術的控制元件。

  • ActiveX不是一種程式語言,而是一組關於應用程式如何共享資訊的規則。

  • 程式設計師可以使用多種語言開發ActiveX控制元件,包括C、C++、Visual Basic和Java。

  • 您可以建立能夠包含ActiveX控制元件的應用程式,無論是否使用MFC,但使用MFC更容易。

讓我們來看一個在基於MFC對話方塊的應用程式中新增ActiveX控制元件的簡單示例。

步驟1 - 在設計器視窗中右鍵單擊對話方塊,然後選擇“插入ActiveX控制元件”。

Insert Activex Control

步驟2 - 選擇“Microsoft圖片剪輯控制元件”,然後單擊“確定”。

Microsoft Picture Control

步驟3 - 調整圖片控制元件的大小,並在“屬性”視窗中單擊“圖片”欄位。

步驟4 - 瀏覽包含圖片的資料夾。選擇任何圖片。

步驟5 - 當您執行此應用程式時,您將看到以下輸出。

Insert Activex

讓我們來看另一個簡單的例子。

步驟1 - 在設計器視窗中右鍵單擊對話方塊。

Designer Window

步驟2 - 選擇“插入ActiveX控制元件”。

Designer Window

步驟3 - 選擇“Microsoft進度條控制元件6.0”,單擊“確定”。

步驟4 - 選擇進度條,並在“屬性”視窗中將其“方向”設定為“1 - ccOrientationVertical”。

步驟5 - 為進度條新增控制元件變數。

Designer Window

步驟6 - 在OnInitDialog()中新增以下程式碼

m_progBarCtrl.SetScrollRange(0,100,TRUE);
m_progBarCtrl.put_Value(53);

步驟7 - 當您再次執行此應用程式時,您將看到進度條也以垂直方向顯示。

Designer Window

MFC - 檔案系統

在本章中,我們將討論檔案系統的各個組成部分。

驅動器

驅動器是連線到計算機的物理裝置,以便儲存資訊。邏輯磁碟、邏輯卷或虛擬磁碟(簡稱VD或vdisk)是一種虛擬裝置,它在計算機系統中的一個或多個物理磁碟驅動器上提供可用儲存容量的區域。驅動器可以是硬碟、CD ROM、DVD ROM、快閃記憶體(USB)驅動器、儲存卡等。

您想要執行的主要操作之一是獲取計算機上的驅動器列表。

讓我們透過建立一個新的基於MFC對話方塊的應用程式來看一個簡單的例子。

步驟1 - 從工具箱中拖動一個按鈕,將其“標題”更改為“獲取驅動器資訊”。

步驟2 - 刪除靜態控制元件(TODO行)的“標題”,並將它的ID更改為IDC_STATIC_TEXT。

Static Caption

步驟3 - 右鍵單擊按鈕,然後選擇“新增事件處理程式”。

Static Caption

步驟4 - 選擇BN_CLICKED訊息型別,然後單擊“新增和編輯”按鈕。

步驟5 - 為靜態文字控制元件新增值變數m_strDrives。

Static Caption

為了支援計算機上的驅動器,Win32庫提供了Microsoft Window的GetLogicalDrives()函式,該函式將檢索當前計算機上所有驅動器的列表。

步驟6 - 當以上程式碼編譯並執行時,您將看到以下輸出。

Static Caption

步驟7 - 當您單擊按鈕時,您可以看到計算機上的所有驅動器。

Static Caption

目錄

在計算中,目錄是檔案系統編目結構,其中包含對其他計算機檔案的引用,以及可能的其他目錄。目錄是物理位置。它可以處理驅動器上不可用的操作。

讓我們透過建立一個新的基於MFC對話方塊的應用程式來看一個簡單的例子

步驟1 - 從工具箱中拖動三個按鈕。將其“標題”更改為“建立目錄”、“刪除目錄”和“移動目錄”。

步驟2 - 將這些按鈕的ID更改為IDC_BUTTON_CREATEIDC_BUTTON_DELETEIDC_BUTTON_MOVE

步驟3 - 刪除TODO行。

Directories

步驟4 - 為每個按鈕新增事件處理程式。

步驟5 - 要建立目錄,可以呼叫Win32庫的CreateDirectory()方法。

步驟6 - 以下是建立按鈕事件處理程式的實現,在其中我們將建立一個目錄,然後建立另外兩個子目錄。

void CMFCDirectoriesDemoDlg::OnBnClickedButtonCreate() {
   // TODO: Add your control notification handler code here
   SECURITY_ATTRIBUTES saPermissions;

   saPermissions.nLength = sizeof(SECURITY_ATTRIBUTES);
   saPermissions.lpSecurityDescriptor = NULL;
   saPermissions.bInheritHandle = TRUE;

   if (CreateDirectory(L"D:\\MFCDirectoryDEMO", &saPermissions) == TRUE)
      AfxMessageBox(L"The directory was created.");
   CreateDirectory(L"D:\\MFCDirectoryDEMO\\Dir1", NULL);
   CreateDirectory(L"D:\\MFCDirectoryDEMO\\Dir2", NULL);
}

步驟7 - 要刪除目錄,可以呼叫Win32庫的RemoveDirectory()函式。以下是刪除按鈕事件處理程式的實現。

void CMFCDirectoriesDemoDlg::OnBnClickedButtonDelete() {
   // TODO: Add your control notification handler code here
   if (RemoveDirectory(L"D:\\MFCDirectoryDEMO\\Dir1") == TRUE)
      AfxMessageBox(L"The directory has been deleted");
}

步驟8 - 如果要移動目錄,也可以呼叫相同的MoveFile()函式。以下是移動按鈕事件處理程式的實現,在其中我們將首先建立新目錄,然後將Dir2移動到該目錄。

void CMFCDirectoriesDemoDlg::OnBnClickedButtonMove() {
   // TODO: Add your control notification handler code here
   CreateDirectory(L"D:\\MFCDirectory", NULL);

   if (MoveFile(L"D:\\MFCDirectoryDEMO\\Dir1", L"D:\\MFCDirectory\\Dir1") == TRUE)
      AfxMessageBox(L"The directory has been moved");
}

步驟9 - 當以上程式碼編譯並執行時,您將看到以下輸出。

Directories

步驟10 - 當您單擊“建立目錄”按鈕時,它將建立這些目錄。

Directories

步驟11 - 當您單擊“刪除目錄”按鈕時,它將刪除Dir1。

Directories

檔案處理

MFC應用程式中的大多數檔案處理都是與名為CArchive的類結合執行的。CArchive類充當應用程式與用於儲存資料或使其可用的介質之間的中繼。它允許您以永久二進位制形式(通常是磁碟儲存)儲存複雜的網路物件,這些物件在這些物件被刪除後仍然存在。

以下是CArchive類中的方法列表:

以下是用於儲存和檢索資料的運算子列表

序號 名稱 & 描述

1

運算子<<

將物件和基本型別儲存到存檔中。

2

運算子>>

從存檔中載入物件和基本型別。

讓我們透過建立一個新的基於MFC對話方塊的應用程式來看一個簡單的例子。

步驟1 - 拖動一個編輯控制元件和兩個按鈕,如下面的快照所示。

New MFC

步驟2 - 為編輯控制元件新增控制元件變數m_editCtrl和值變數m_strEdit

步驟3 - 為“開啟”和“儲存”按鈕新增單擊事件處理程式。

步驟4 - 以下是事件處理程式的實現。

void CMFCFileProcessingDlg::OnBnClickedButtonOpen() {
   // TODO: Add your control notification handler code here
   UpdateData(TRUE);
   
   CFile file;
   
   file.Open(L"ArchiveText.rpr", CFile::modeRead);
   if(file) {
      CArchive ar(&file, CArchive::load);
   
      ar >> m_strEdit;
   
      ar.Close();
      file.Close();
   }
   UpdateData(FALSE);
}

void CMFCFileProcessingDlg::OnBnClickedButtonSave() {
   // TODO: Add your control notification handler code here
   UpdateData(TRUE);

   if (m_strEdit.GetLength() == 0) {
      AfxMessageBox(L"You must enter the name of the text.");
      return;
   }
   CFile file;
   
   file.Open(L"ArchiveText.rpr", CFile::modeCreate | CFile::modeWrite);
   CArchive ar(&file, CArchive::store);
   ar << m_strEdit;
   
   ar.Close();
   file.Close();
}

步驟 5 - 當上述程式碼編譯並執行時,您將看到以下輸出。

New MFC

步驟6 - 輸入一些內容並單擊“儲存”。它將以二進位制格式儲存資料。

New MFC

步驟7 - 從編輯控制元件中刪除文字。當您單擊“開啟”時,觀察相同的文字是否再次載入。

MFC - 標準 I/O

MFC庫提供了自己的檔案處理版本。這是透過名為CStdioFile的類完成的。CStdioFile類派生自CFile。它可以處理Unicode文字檔案以及普通的多位元組文字檔案的讀取和寫入。

以下是可初始化CStdioFile物件的建構函式列表:

CStdioFile();
CStdioFile(CAtlTransactionManager* pTM);
CStdioFile(FILE* pOpenStream);
CStdioFile(LPCTSTR lpszFileName, UINT nOpenFlags);
CStdioFile(LPCTSTR lpszFileName, UINT nOpenFlags, CAtlTransactionManager* pTM);

以下是CStdioFile中的方法列表:

序號 名稱 & 描述

1

開啟

過載。Open設計用於與預設的CStdioFile建構函式一起使用(覆蓋CFile::Open)。

2

讀取字串

讀取一行文字。

3

查詢

定位當前檔案指標。

4

寫入字串

寫入一行文字。

讓我們再次透過建立一個新的基於MFC對話方塊的應用程式來檢視一個簡單的示例。

步驟1 - 拖動一個編輯控制元件和兩個按鈕,如下面的快照所示。

Snapshot

步驟2 - 為編輯控制元件新增值變數m_strEditCtrl

Snapshot

步驟3 - 為“開啟”和“儲存”按鈕新增單擊事件處理程式。

步驟4 - 以下是事件處理程式的實現。

void CMFCStandardIODlg::OnBnClickedButtonOpen() {
   
   // TODO: Add your control notification handler code here
   UpdateData(TRUE);

   CStdioFile file;
   file.Open(L"D:\\MFCDirectoryDEMO\\test.txt", CFile::modeRead | CFile::typeText);
   
   file.ReadString(m_strEditCtrl);
   file.Close();
   UpdateData(FALSE);
}

void CMFCStandardIODlg::OnBnClickedButtonSave() {
   
   // TODO: Add your control notification handler code here
   UpdateData(TRUE);
   CStdioFile file;
   if (m_strEditCtrl.GetLength() == 0) {

      AfxMessageBox(L"You must specify the text.");
      return;
   }
   file.Open(L"D:\\MFCDirectoryDEMO\\test.txt", CFile::modeCreate |
      CFile::modeWrite | CFile::typeText);
   file.WriteString(m_strEditCtrl);
   file.Close();
}

步驟 5 - 當上述程式碼編譯並執行時,您將看到以下輸出。

Snapshot

步驟6 - 輸入一些內容並單擊“儲存”。它將資料儲存到*.txt檔案中。

Snapshot

步驟7 - 如果您檢視檔案的位置,您將看到它包含test.txt檔案。

Snapshot

步驟8 - 現在,關閉應用程式。執行相同的應用程式。當您單擊“開啟”時,相同的文字將再次載入。

步驟9 - 它首先開啟檔案,讀取檔案,然後更新編輯控制元件。

MFC - 文件/檢視

文件/檢視架構是用於建立基於Microsoft Foundation Classes庫的應用程式的基礎。它允許您區分構成計算機程式的不同部分,包括使用者在應用程式中看到的內容以及使用者將要處理的文件。這是透過結合在一起作為整體工作的單獨類來完成的。

構成文件/檢視架構的部分是框架、一個或多個文件以及檢視。這些實體組合在一起構成一個可用的應用程式。

檢視

檢視是使用者在其上工作以完成其工作的平臺。為了讓使用者在應用程式上執行任何操作,您必須提供一個檢視,該檢視是一個基於CView類的物件。您可以直接使用派生自CView的類之一,也可以從CView或其子類之一派生自己的自定義類。

檔案

文件類似於一個桶。對於計算機應用程式,文件儲存使用者的資料。要建立此架構的文件部分,您必須從CDocument類派生一個物件。

框架

顧名思義,框架是構建塊、結構和專案邊界的組合。框架為視窗提供“物理”存在。它還定義了物件相對於Windows桌面的位置。

單文件介面 (SDI)

表示式單文件介面或SDI指的是隻能向用戶呈現一個檢視的文件。這意味著應用程式一次不能顯示多個文件。如果您想檢視當前應用程式的另一種型別的文件,則必須建立應用程式的另一個例項。記事本和寫字板是SDI應用程式的示例。

讓我們透過建立一個新的基於MFC對話方塊的應用程式來檢視單文件介面或SDI的簡單示例。

步驟1 - 讓我們建立一個新的MFC應用程式MFCSDIDemo,並使用以下設定。

SDI

步驟2 - 從應用程式型別中選擇“單文件”,從專案樣式中選擇“MFC標準”。

步驟3 - 單擊“完成”繼續。

步驟4 - 專案建立完成後,執行應用程式,您將看到以下輸出。

SDI

多文件介面 (MDI)

如果使用者可以在應用程式中開啟多個文件而無需關閉它,則該應用程式被稱為多文件介面或MDI。為了提供此功能,應用程式提供了一個父框架,充當計算機程式的主框架。在此框架內,應用程式允許建立具有單獨框架的檢視,使每個檢視與其他檢視區分開來。

讓我們透過建立一個新的基於MFC對話方塊的應用程式來檢視多文件介面或MDI的簡單示例。

步驟1 - 讓我們建立一個新的MFC應用程式MFCMDIDemo,並使用以下設定。

MDI

步驟2 - 從應用程式型別中選擇“多文件”,從專案樣式中選擇“MFC標準”。

步驟3 - 單擊“完成”繼續。

步驟4 - 專案建立完成後,執行應用程式,您將看到以下輸出。

MDI

步驟5 - 當您單擊“檔案”→“新建”選單選項時,它將建立另一個子視窗,如下面的快照所示。

MDI

步驟6 - 在多文件介面 (MDI) 應用程式中,每個應用程式都有一個主框架。在這種情況下,一個CMDIFrameWnd,以及每個文件一個派生自CMDIChildWnd的子框架。

MFC - 字串

字串是表示字元序列的物件。C風格字元字串起源於C語言,並在C++中繼續得到支援。

  • 此字串實際上是一個以空字元'\0'結尾的一維字元陣列。

  • 空終止字串包含構成字串的字元,後跟一個空字元。

以下是字元陣列的簡單示例。

char word[12] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0' };

以下是另一種表示方式。

char word[] = "Hello, World";

Microsoft Foundation Class (MFC) 庫提供了一個名為CString的類來操作字串。以下是CString的一些重要特性。

  • CString沒有基類。

  • CString物件包含一個可變長度的字元序列。

  • CString使用類似於Basic的語法提供函式和運算子。

  • 連線和比較運算子以及簡化的記憶體管理使CString物件比普通字元陣列更容易使用。

以下是CString的建構函式。

序號 方法和描述
1

CString

以各種方式構造CString物件

以下是陣列方法列表:

序號 方法和描述
1

GetLength

返回CString物件中的字元數。

2

IsEmpty

測試CString物件是否不包含任何字元。

3

清空

強制字串長度為0。

4

GetAt

返回指定位置的字元。

5

SetAt

在指定位置設定字元。

以下是比較方法列表:

序號 方法和描述
1

比較

比較兩個字串(區分大小寫)。

2

CompareNoCase

比較兩個字串(不區分大小寫)。

以下是提取方法列表:

序號 方法和描述
1

中間

提取字串的中間部分(如Basic MID$函式)。

2

左邊

提取字串的左側部分(如Basic LEFT$函式)。

3

右邊

提取字串的右側部分(如Basic RIGHT$函式)。

4

SpanIncluding

從字串中提取字元,這些字元位於給定的字元集中。

5

SpanExcluding

從字串中提取不在給定字元集中的字元。

以下是轉換方法列表。

序號 方法和描述
1

MakeUpper

將此字串中的所有字元轉換為大寫字元。

2

MakeLower

將此字串中的所有字元轉換為小寫字元。

3

MakeReverse

反轉此字串中的字元。

4

格式

像sprintf一樣格式化字串。

5

TrimLeft

從字串中修剪前導空白字元。

6

TrimRight

從字串中修剪尾隨空白字元。

以下是搜尋方法列表。

序號 方法和描述
1

查詢

在較大的字串內查詢字元或子字串。

2

ReverseFind

在較大的字串內查詢字元;從結尾開始。

3

FindOneOf

從集合中查詢第一個匹配的字元。

以下是緩衝區訪問方法列表。

序號 方法和描述
1

GetBuffer

返回指向CString中字元的指標。

2

GetBufferSetLength

返回指向CString中字元的指標,截斷到指定的長度。

3

ReleaseBuffer

釋放GetBuffer返回的緩衝區的控制權

4

FreeExtra

透過釋放之前分配給字串的任何額外記憶體來刪除此字串物件的任何開銷。

5

LockBuffer

停用引用計數並保護緩衝區中的字串。

6

UnlockBuffer

啟用引用計數並釋放緩衝區中的字串。

以下是Windows特定方法列表。

序號 方法和描述
1

AllocSysString

從CString資料分配BSTR。

2

SetSysString

使用來自CString物件的資料設定現有的BSTR物件。

3

LoadString

從Windows CE資源載入現有的CString物件。

以下是CString物件的各種操作:

建立字串

您可以透過使用字串文字或建立CString類的例項來建立字串。

BOOL CMFCStringDemoDlg::OnInitDialog() {

   CDialogEx::OnInitDialog();

   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);         // Set big icon
   SetIcon(m_hIcon, FALSE);       // Set small icon

   CString string1 = _T("This is a string1");
   CString string2("This is a string2");

   m_strText.Append(string1 + L"\n");
   m_strText.Append(string2);

   UpdateData(FALSE);

   return TRUE; // return TRUE unless you set the focus to a control
}

編譯並執行上述程式碼後,您將看到以下輸出。

Create String

空字串

您可以透過使用空字串文字或使用CString::Empty()方法來建立空字串。您還可以使用布林屬性isEmpty來檢查字串是否為空。

BOOL CMFCStringDemoDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);            // Set big icon
   SetIcon(m_hIcon, FALSE);           // Set small icon

   CString string1 = _T("");
   CString string2;
   string2.Empty();

   if(string1.IsEmpty())
      m_strText.Append(L"String1 is empty\n");
   else
      m_strText.Append(string1 + L"\n");
   
   if(string2.IsEmpty())
      m_strText.Append(L"String2 is empty");
   else
      m_strText.Append(string2);
   UpdateData(FALSE);
   return TRUE; // return TRUE unless you set the focus to a control
}

編譯並執行上述程式碼後,您將看到以下輸出。

Empty String

字串連線

要連線兩個或多個字串,您可以使用+運算子連線兩個字串或使用CString::Append()方法。

BOOL CMFCStringDemoDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);              // Set big icon
   SetIcon(m_hIcon, FALSE);              // Set small icon

   //To concatenate two CString objects
   CString s1 = _T("This ");           // Cascading concatenation
   s1 += _T("is a ");
   CString s2 = _T("test");
   CString message = s1;
   message.Append(_T("big ") + s2);
   // Message contains "This is a big test".

   m_strText = L"message: " + message;

   UpdateData(FALSE);

   return TRUE; // return TRUE unless you set the focus to a control
}

編譯並執行上述程式碼後,您將看到以下輸出。

String Concatination

字串長度

要查詢字串的長度,您可以使用CString::GetLength()方法,該方法返回CString物件中的字元數。

BOOL CMFCStringDemoDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();
   
   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);              // Set big icon
   SetIcon(m_hIcon, FALSE);              // Set small icon

   CString string1 = _T("This is string 1");
   int length = string1.GetLength();
   CString strLen;

   strLen.Format(L"\nString1 contains %d characters", length);
   m_strText = string1 + strLen;

   UpdateData(FALSE);

   return TRUE; // return TRUE unless you set the focus to a control
}

編譯並執行上述程式碼後,您將看到以下輸出。

String Length

字串比較

要比較兩個字串變數,您可以使用==運算子

BOOL CMFCStringDemoDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();
   
   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);            // Set big icon
   SetIcon(m_hIcon, FALSE);          // Set small icon

   CString string1 = _T("Hello");
   CString string2 = _T("World");

   CString string3 = _T("MFC Tutorial");
   CString string4 = _T("MFC Tutorial");

   if (string1 == string2)
      m_strText = "string1 and string1 are same\n";
   else
      m_strText = "string1 and string1 are not same\n";

   if (string3 == string4)
      m_strText += "string3 and string4 are same";
   else
      m_strText += "string3 and string4 are not same";

   UpdateData(FALSE);

   return TRUE; // return TRUE unless you set the focus to a control
}

編譯並執行上述程式碼後,您將看到以下輸出。

String Comparison

MFC - CArray

CArray 是一種集合,最適合用於以隨機或非順序方式訪問的資料。CArray 類支援類似於 C 陣列的陣列,但可以根據需要動態縮小和增長。

  • 陣列索引始終從位置 0 開始。

  • 您可以決定是修復上限還是在新增超過當前邊界的元素時啟用陣列擴充套件。

  • 即使某些元素為空,記憶體也會連續分配到上限。

以下是 CArray 物件的不同操作:

建立 CArray 物件

要建立 CArray 值或物件的集合,您必須首先確定集合的值型別。您可以使用現有的基本資料型別,例如 int、CString、double 等,如下所示:

CArray<CString, CString>strArray;

新增專案

要新增專案,可以使用 CArray::Add() 函式。它在陣列末尾新增一個專案。在 OnInitDialog() 中,建立 CArray 物件並新增三個名稱,如下面的程式碼所示。

CArray<CString, CString>strArray;

//Add names to CArray
strArray.Add(L"Ali");
strArray.Add(L"Ahmed");
strArray.Add(L"Mark");

檢索專案

要檢索任何專案,可以使用 CArray::GetAt() 函式。此函式採用一個整數引數作為陣列的索引。

步驟 1 - 讓我們看一個簡單的示例,它將檢索所有名稱。

//Retrive names from CArray
   for (int i = 0; i < strArray.GetSize(); i++) {
      m_strText.Append(strArray.GetAt(i) + L"\n");
   }

步驟 2 - 以下是 CMFCCArrayDlg::OnInitDialog() 的完整實現

BOOL CMFCCArrayDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);               // Set big icon
   SetIcon(m_hIcon, FALSE);             // Set small icon

   // TODO: Add extra initialization here
   CArray<CString, CString>strArray;
   
   //Add names to CArray
   strArray.Add(L"Ali");
   strArray.Add(L"Ahmed");
   strArray.Add(L"Mark");
   
   //Retrive names from CArray
   for (int i = 0; i < strArray.GetSize(); i++) {
      m_strText.Append(strArray.GetAt(i) + L"\n");
   }
   
   UpdateData(FALSE);
   return TRUE; // return TRUE unless you set the focus to a control
}

步驟3 - 當以上程式碼編譯並執行時,您將看到以下輸出。

Retrieve Items

在中間新增專案

要在陣列中間新增專案,可以使用 CArray::.InsertAt() 函式。它採用兩個引數 - 第一個引數是索引,第二個引數是值。

讓我們在索引 1 處插入一個新專案,如下面的程式碼所示。

BOOL CMFCCArrayDlg::OnInitDialog() {
   
   CDialogEx::OnInitDialog();
   
   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);             // Set big icon
   SetIcon(m_hIcon, FALSE);            // Set small icon

   // TODO: Add extra initialization here
   CArray<CString, CString>strArray;
   //Add names to CArray
   strArray.Add(L"Ali");
   strArray.Add(L"Ahmed");
   strArray.Add(L"Mark");

   strArray.InsertAt(1, L"Allan");

   //Retrive names from CArray
   for (int i = 0; i < strArray.GetSize(); i++) {
      m_strText.Append(strArray.GetAt(i) + L"\n");
   }

   UpdateData(FALSE);
   return TRUE; // return TRUE unless you set the focus to a control
}

編譯並執行上述程式碼後,您將看到以下輸出。您現在可以看到 Allan 作為第二個索引新增的名稱。

Add Items

更新專案值

要更新陣列中間的專案,可以使用 CArray::.SetAt() 函式。它採用兩個引數 - 第一個引數是索引,第二個引數是值。

讓我們更新陣列中的第三個元素,如下面的程式碼所示。

BOOL CMFCCArrayDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);                 // Set big icon
   SetIcon(m_hIcon, FALSE);               // Set small icon

   // TODO: Add extra initialization here
   CArray<CString, CString>strArray;

   //Add names to CArray
   strArray.Add(L"Ali");
   strArray.Add(L"Ahmed");
   strArray.Add(L"Mark");
  
   strArray.InsertAt(1, L"Allan");
   
   strArray.SetAt(2, L"Salman");
   
   //Retrive names from CArray
   for (int i = 0; i < strArray.GetSize(); i++) {
      m_strText.Append(strArray.GetAt(i) + L"\n");
   }

   UpdateData(FALSE);
   return TRUE; // return TRUE unless you set the focus to a control
}

編譯並執行上述程式碼後,您將看到以下輸出。您現在可以看到第三個元素的值已更新。

Update Items

複製陣列

要將整個陣列複製到另一個 CArray 物件,可以使用 CArray::Copy() 函式。

步驟 1 - 讓我們建立另一個數組並將第一個陣列中的所有元素複製到該陣列中,如下面的程式碼所示。

BOOL CMFCCArrayDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   // Add "About..." menu item to system menu.

   // IDM_ABOUTBOX must be in the system command range.
   ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
   ASSERT(IDM_ABOUTBOX < 0xF000);
   CMenu* pSysMenu = GetSystemMenu(FALSE);
   if (pSysMenu != NULL) {
      BOOL bNameValid;
      CString strAboutMenu;
      bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
      ASSERT(bNameValid);
      if (!strAboutMenu.IsEmpty()) {
         pSysMenu→AppendMenu(MF_SEPARATOR);
         pSysMenu→AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
      }
   }
   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);               // Set big icon
   SetIcon(m_hIcon, FALSE);              // Set small icon

   // TODO: Add extra initialization here
   CArray<CString, CString>strArray;
   //Add names to CArray
   strArray.Add(L"Ali");
   strArray.Add(L"Ahmed");
   strArray.Add(L"Mark");

   strArray.InsertAt(1, L"Allan");

   strArray.SetAt(2, L"Salman");

   CArray<CString, CString>strArray2;
   strArray2.Copy(strArray);
   //Retrive names from CArray
   for (int i = 0; i < strArray2.GetSize(); i++) {
      m_strText.Append(strArray2.GetAt(i) + L"\n");
   }

   UpdateData(FALSE);
   return TRUE; // return TRUE unless you set the focus to a control
}

您現在可以看到我們已從第二個陣列中檢索了元素,並且輸出相同,因為我們使用了複製函式。

Copy Array

刪除專案

要刪除任何特定專案,可以使用 CArray::RemoveAt() 函式。要從列表中刪除所有元素,可以使用 CArray::RemoveAll() 函式。

讓我們從陣列中刪除第二個元素。

BOOL CMFCCArrayDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   SetIcon(m_hIcon, TRUE);             // Set big icon
   SetIcon(m_hIcon, FALSE);            // Set small icon

   // TODO: Add extra initialization here
   CArray<CString, CString>strArray;

   //Add names to CArray
   strArray.Add(L"Ali");
   strArray.Add(L"Ahmed");
   strArray.Add(L"Mark");

   strArray.InsertAt(1, L"Allan");

   strArray.SetAt(2, L"Salman");

   CArray<CString, CString>strArray2;
   strArray2.Copy(strArray);

   strArray2.RemoveAt(1);

   //Retrive names from CArray
   for (int i = 0; i < strArray2.GetSize(); i++) {
      m_strText.Append(strArray2.GetAt(i) + L"\n");
   }

   UpdateData(FALSE);
   return TRUE; // return TRUE unless you set the focus to a control
}

編譯並執行上述程式碼後,您將看到以下輸出。您現在可以看到 Allan 的名稱不再是陣列的一部分。

Remove Items

MFC - 連結列表

連結列表是一種線性資料結構,其中每個元素都是一個單獨的物件。列表的每個元素(我們將其稱為節點)包含兩個專案 - 資料和對下一個節點的引用。最後一個節點對 null 的引用。

連結列表是一種資料結構,由一組節點組成,這些節點共同表示一個序列。它是一種使用結構儲存資料的方式,以便程式設計師可以在需要時自動建立一個新的儲存資料的地方。它的一些主要特徵是:

  • 連結列表是一系列包含專案的連結。

  • 每個連結都包含到另一個連結的連線。

  • 列表中的每個專案都稱為節點。

  • 如果列表至少包含一個節點,則一個新節點將被定位為列表中的最後一個元素。

  • 如果列表只有一個節點,則該節點表示第一個和最後一個專案。

連結列表有兩種型別:

單向連結列表

單向連結列表是一種資料結構。在單向連結列表中,列表中的每個節點都儲存節點的內容以及指向列表中下一個節點的指標或引用。

Single Linked List

雙向連結列表

雙向連結列表是一種連結資料結構,由一組稱為節點的順序連結記錄組成。每個節點包含兩個欄位,它們分別引用序列中前一個節點和下一個節點。

Double Linked List

CList 類

MFC 提供了一個類CList,它是一個模板連結列表實現,並且可以完美執行。CList 列表的行為類似於雙向連結列表。型別為 POSITION 的變數是列表的關鍵。您可以使用 POSITION 變數作為迭代器順序遍歷列表,並作為書籤來儲存位置。

以下是 CList 物件的不同操作:

建立 CList 物件

要建立 CList 值或物件的集合,您必須首先確定集合的值型別。您可以使用現有的基本資料型別,例如 int、CString、double 等,如下面的程式碼所示。

CList<double, double>m_list;

新增專案

要新增專案,可以使用 CList::AddTail() 函式。它在列表末尾新增一個專案。要將元素新增到列表的開頭,可以使用 CList::AddHead() 函式。在 OnInitDialog() CList 中,建立物件並新增四個值,如下面的程式碼所示。

CList<double, double>m_list;

//Add items to the list
m_list.AddTail(100.75);
m_list.AddTail(85.26);
m_list.AddTail(95.78);
m_list.AddTail(90.1);

檢索專案

型別為 POSITION 的變數是列表的關鍵。您可以使用 POSITION 變數作為迭代器順序遍歷列表。

步驟 1 - 要從列表中檢索元素,我們可以使用以下程式碼,它將檢索所有值。

//iterate the list
POSITION pos = m_list.GetHeadPosition();
while (pos) { 
   double nData = m_list.GetNext(pos);
   CString strVal;
   strVal.Format(L"%.2f\n", nData);
   m_strText.Append(strVal);
}

步驟 2 - 以下是完整的 CMFCCListDemoDlg::OnInitDialog() 函式。

BOOL CMFCCListDemoDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);             // Set big icon
   SetIcon(m_hIcon, FALSE);             // Set small icon

   // TODO: Add extra initialization here
   CList<double, double>m_list;

   //Add items to the list
   m_list.AddTail(100.75);
   m_list.AddTail(85.26);
   m_list.AddTail(95.78);
   m_list.AddTail(90.1);

   //iterate the list
   POSITION pos = m_list.GetHeadPosition();
   while (pos) {
      double nData = m_list.GetNext(pos);
      CString strVal;
      strVal.Format(L"%.f\n", nData);
      m_strText.Append(strVal);
   }

   UpdateData(FALSE);
 
   return TRUE; // return TRUE unless you set the focus to a control
}

步驟3 - 當以上程式碼編譯並執行時,您將看到以下輸出。

Retrieve

在中間新增專案

要在列表中間新增專案,可以使用 CList::.InsertAfter() 和 CList::.InsertBefore() 函式。它採用兩個引數 - 第一個引數是位置(可以在哪裡新增),第二個引數是值。

步驟 1 - 讓我們插入一個新專案,如下面的程式碼所示。

BOOL CMFCCListDemoDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();
   
   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);             // Set big icon
   SetIcon(m_hIcon, FALSE);          // Set small icon

   // TODO: Add extra initialization here
   CList<double, double>m_list;

   //Add items to the list
   m_list.AddTail(100.75);
   m_list.AddTail(85.26);
   m_list.AddTail(95.78);
   m_list.AddTail(90.1);

   POSITION position = m_list.Find(85.26);
   m_list.InsertBefore(position, 200.0);
   m_list.InsertAfter(position, 300.0);

   //iterate the list
   POSITION pos = m_list.GetHeadPosition();
   while (pos) {
      double nData = m_list.GetNext(pos);
      CString strVal;
      strVal.Format(L"%.2f\n", nData);
      m_strText.Append(strVal);
   }

   UpdateData(FALSE);

   return TRUE; // return TRUE unless you set the focus to a control
}

步驟 2 - 您現在可以看到我們首先檢索了值 85.26 的位置,然後在該值之前和之後插入了一個元素。

步驟3 - 當以上程式碼編譯並執行時,您將看到以下輸出。

Adding Item

更新專案值

要更新陣列中間的專案,可以使用 CArray::.SetAt() 函式。它採用兩個引數 - 第一個引數是位置,第二個引數是值。

讓我們將列表中的 300.00 更新為 400,如下面的程式碼所示。

BOOL CMFCCListDemoDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);              // Set big icon
   SetIcon(m_hIcon, FALSE);            // Set small icon

   // TODO: Add extra initialization here
   CList<double, double>m_list;

   //Add items to the list
   m_list.AddTail(100.75);
   m_list.AddTail(85.26);
   m_list.AddTail(95.78);
   m_list.AddTail(90.1);

   POSITION position = m_list.Find(85.26);
   m_list.InsertBefore(position, 200.0);
   m_list.InsertAfter(position, 300.0);

   position = m_list.Find(300.00);
   m_list.SetAt(position, 400.00);

   //iterate the list
   POSITION pos = m_list.GetHeadPosition();
   while (pos) {
      double nData = m_list.GetNext(pos);
      CString strVal;
      strVal.Format(L"%.2f\n", nData);
      m_strText.Append(strVal);
   }

   UpdateData(FALSE);

   return TRUE; // return TRUE unless you set the focus to a control
}

編譯並執行上述程式碼後,您將看到以下輸出。您現在可以看到 300.00 的值已更新為 400.00。

Updating Item

刪除專案

要刪除任何特定專案,可以使用 CList::RemoveAt() 函式。要從列表中刪除所有元素,可以使用 CList::RemoveAll() 函式。

讓我們刪除值為 95.78 的元素。

BOOL CMFCCListDemoDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);              // Set big icon
   SetIcon(m_hIcon, FALSE);             // Set small icon

   // TODO: Add extra initialization here
   CList<double, double>m_list;

   //Add items to the list
   m_list.AddTail(100.75);
   m_list.AddTail(85.26);
   m_list.AddTail(95.78);
   m_list.AddTail(90.1);

   POSITION position = m_list.Find(85.26);
   m_list.InsertBefore(position, 200.0);
   m_list.InsertAfter(position, 300.0);
   
   position = m_list.Find(300.00);
   m_list.SetAt(position, 400.00);

   position = m_list.Find(95.78);
   m_list.RemoveAt(position);

   //iterate the list
   POSITION pos = m_list.GetHeadPosition();
   while (pos) {
      double nData = m_list.GetNext(pos);
      CString strVal;
      strVal.Format(L"%.2f\n", nData);
      m_strText.Append(strVal);
   }
   UpdateData(FALSE);
   
   return TRUE; // return TRUE unless you set the focus to a control
}

編譯並執行上述程式碼後,您將看到以下輸出。您現在可以看到 95.78 的值不再是列表的一部分。

Removing Item

MFC - 資料庫類

資料庫是資訊的集合,這些資訊經過組織,以便可以輕鬆地訪問、管理和更新。基於 ODBC 的 MFC 資料庫類旨在提供對任何可使用 ODBC 驅動程式訪問的資料庫的訪問。由於這些類使用 ODBC,因此您的應用程式可以訪問許多不同資料格式和不同本地/遠端配置中的資料。

您不必編寫專門的程式碼來處理不同的資料庫管理系統 (DBMS)。只要您的使用者擁有他們要訪問的資料的相應 ODBC 驅動程式,他們就可以使用您的程式來操作儲存在那裡的表中的資料。資料來源是由某些資料庫管理系統 (DBMS) 託管的資料的特定例項。示例包括 Microsoft SQL Server、Microsoft Access 等。

CDatabase

MFC 提供了一個類CDatabase,它表示與資料來源的連線,您可以透過它來操作資料來源。您的應用程式可以同時啟用一個或多個 CDatabase 物件。

讓我們透過建立一個新的基於MFC對話方塊的應用程式來看一個簡單的例子。

步驟1 - 將TODO行的標題更改為從資料庫檢索資料,並拖動一個按鈕和一個列表控制元件,如下面的快照所示。

Retrieve Data From DB

步驟2 - 為按鈕新增單擊事件處理程式,併為列表控制元件新增控制變數m_ListControl。

步驟3 - 我們有一個簡單的資料庫,其中包含一個Employees表和一些記錄,如下面的快照所示。

Employees Table

步驟4 - 我們需要包含以下標頭檔案,以便可以使用CDatabase類。

#include "odbcinst.h"
#include "afxdb.h"

插入查詢

SQL INSERT INTO語句用於向資料庫中的表新增新的資料行。

步驟1 - 要新增新記錄,我們將使用CDatabase類的ExecuteSQL()函式,如下面的程式碼所示。

CDatabase database;
CString SqlString;
CString strID, strName, strAge;
CString sDriver = L"MICROSOFT ACCESS DRIVER (*.mdb)";
CString sDsn;
CString sFile = L"D:\\Test.mdb";
// You must change above path if it's different
int iRec = 0;

// Build ODBC connection string
sDsn.Format(L"ODBC;DRIVER={%s};DSN='';DBQ=%s", sDriver, sFile);
TRY {
   // Open the database
   database.Open(NULL,false,false,sDsn);

   SqlString = "INSERT INTO Employees (ID,Name,age) VALUES (5,'Sanjay',69)";
   database.ExecuteSQL(SqlString);
   // Close the database
   database.Close();
}CATCH(CDBException, e) {
   // If a database exception occured, show error msg
   AfxMessageBox(L"Database error: " + e→m_strError);
}
END_CATCH;

步驟2 - 當上述程式碼編譯並執行時,您將看到資料庫中添加了一條新記錄。

Insert Queue

檢索記錄

要在MFC應用程式中檢索上述表,我們將在按鈕事件處理程式中實現與資料庫相關的操作,如下面的步驟所示。

步驟1 - 要使用CDatabase,請構造一個CDatabase物件並呼叫其Open()函式。這將開啟連線。

步驟2 - 為操作連線的資料來源構造CRecordset物件,並將記錄集建構函式傳遞給您的CDatabase物件。

步驟3 - 使用完連線後,呼叫Close函式並銷燬CDatabase物件。

void CMFCDatabaseDemoDlg::OnBnClickedButtonRead() {
   // TODO: Add your control notification handler code here
   CDatabase database;
   CString SqlString;
   CString strID, strName, strAge;
   CString sDriver = "MICROSOFT ACCESS DRIVER (*.mdb)";
   CString sFile = L"D:\\Test.mdb";
   // You must change above path if it's different
   int iRec = 0;

   // Build ODBC connection string
   sDsn.Format("ODBC;DRIVER={%s};DSN='';DBQ=%s",sDriver,sFile);
   TRY {
      // Open the database
      database.Open(NULL,false,false,sDsn);

      // Allocate the recordset
      CRecordset recset( &database );

      // Build the SQL statement
      SqlString = "SELECT ID, Name, Age " "FROM Employees";

      // Execute the query
	  
      recset.Open(CRecordset::forwardOnly,SqlString,CRecordset::readOnly);
      // Reset List control if there is any data
      ResetListControl();
      // populate Grids
      ListView_SetExtendedListViewStyle(m_ListControl,LVS_EX_GRIDLINES);

      // Column width and heading
      m_ListControl.InsertColumn(0,"Emp ID",LVCFMT_LEFT,-1,0);
      m_ListControl.InsertColumn(1,"Name",LVCFMT_LEFT,-1,1);
      m_ListControl.InsertColumn(2, "Age", LVCFMT_LEFT, -1, 1);
      m_ListControl.SetColumnWidth(0, 120);
      m_ListControl.SetColumnWidth(1, 200);
      m_ListControl.SetColumnWidth(2, 200);

      // Loop through each record
      while( !recset.IsEOF() ) {
         // Copy each column into a variable
         recset.GetFieldValue("ID",strID);
         recset.GetFieldValue("Name",strName);
         recset.GetFieldValue("Age", strAge);

         // Insert values into the list control
         iRec = m_ListControl.InsertItem(0,strID,0);
         m_ListControl.SetItemText(0,1,strName);
         m_ListControl.SetItemText(0, 2, strAge);

         // goto next record
         recset.MoveNext();
      }
      // Close the database
      database.Close();
   }CATCH(CDBException, e) {
      // If a database exception occured, show error msg
      AfxMessageBox("Database error: "+e→m_strError);
   }
   END_CATCH; 
}

// Reset List control
void CMFCDatabaseDemoDlg::ResetListControl() {
   m_ListControl.DeleteAllItems();
   int iNbrOfColumns;
   CHeaderCtrl* pHeader = (CHeaderCtrl*)m_ListControl.GetDlgItem(0);
   if (pHeader) {
      iNbrOfColumns = pHeader→GetItemCount();
   }
   for (int i = iNbrOfColumns; i >= 0; i--) {
      m_ListControl.DeleteColumn(i);
   }
}

步驟4 - 這是標頭檔案。

// MFCDatabaseDemoDlg.h : header file
//

#pragma once
#include "afxcmn.h"


// CMFCDatabaseDemoDlg dialog
class CMFCDatabaseDemoDlg : public CDialogEx {
   // Construction
   public:
      CMFCDatabaseDemoDlg(CWnd* pParent = NULL);    // standard constructor

   // Dialog Data
   #ifdef AFX_DESIGN_TIME
      enum { IDD = IDD_MFCDATABASEDEMO_DIALOG };
   #endif

   protected:
      virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
      void ResetListControl();

   // Implementation
   protected:
      HICON m_hIcon;

      // Generated message map functions
      virtual BOOL OnInitDialog();
      afx_msg void OnPaint();
      afx_msg HCURSOR OnQueryDragIcon();
      DECLARE_MESSAGE_MAP()
   public:
      CListCtrl m_ListControl;
      afx_msg void OnBnClickedButtonRead();
};

步驟 5 - 當上述程式碼編譯並執行時,您將看到以下輸出。

Retrieve Record

步驟6 - 按下讀取按鈕以執行資料庫操作。它將檢索Employees表。

Retrieve Record

更新記錄

SQL UPDATE查詢用於修改表中現有的記錄。您可以將WHERE子句與UPDATE查詢一起使用來更新選定的行,否則所有行都將受到影響。

步驟1 - 讓我們透過更新ID等於5的Age來了解一個簡單的示例。

SqlString = L"UPDATE Employees SET Age = 59 WHERE ID = 5;";
database.ExecuteSQL(SqlString);

步驟2 - 這是按鈕單擊事件的完整程式碼。

void CMFCDatabaseDemoDlg::OnBnClickedButtonRead() {
   // TODO: Add your control notification handler code here
   CDatabase database;
   CString SqlString;
   CString strID, strName, strAge;
   CString sDriver = L"MICROSOFT ACCESS DRIVER (*.mdb)";
   CString sDsn;
   CString sFile =
      L"C:\\Users\\Muhammad.Waqas\\Downloads\\Compressed\\ReadDB_demo\\Test.mdb";
   // You must change above path if it's different
   int iRec = 0;

   // Build ODBC connection string
   sDsn.Format(L"ODBC;DRIVER={%s};DSN='';DBQ=%s", sDriver, sFile);
   TRY {
      // Open the database
      database.Open(NULL,false,false,sDsn);

      // Allocate the recordset
      CRecordset recset(&database);

      SqlString = L"UPDATE Employees SET Age = 59 WHERE ID = 5;";

      database.ExecuteSQL(SqlString);

      SqlString = "SELECT ID, Name, Age FROM Employees";

      // Build the SQL statement
      SqlString = "SELECT ID, Name, Age FROM Employees";

      // Execute the query
      recset.Open(CRecordset::forwardOnly,SqlString,CRecordset::readOnly);

      // Reset List control if there is any data
      ResetListControl();
      // populate Grids
      ListView_SetExtendedListViewStyle(m_listCtrl,LVS_EX_GRIDLINES);

      // Column width and heading
      m_listCtrl.InsertColumn(0,L"Emp ID",LVCFMT_LEFT,-1,0);
      m_listCtrl.InsertColumn(1,L"Name",LVCFMT_LEFT,-1,1);
      m_listCtrl.InsertColumn(2, L"Age", LVCFMT_LEFT, -1, 1);
      m_listCtrl.SetColumnWidth(0, 120);
      m_listCtrl.SetColumnWidth(1, 200);
      m_listCtrl.SetColumnWidth(2, 200);

      // Loop through each record
      while (!recset.IsEOF()) {
         // Copy each column into a variable
         recset.GetFieldValue(L"ID",strID);
         recset.GetFieldValue(L"Name",strName);
         recset.GetFieldValue(L"Age", strAge);

         // Insert values into the list control
         iRec = m_listCtrl.InsertItem(0,strID,0);
         m_listCtrl.SetItemText(0,1,strName);
         m_listCtrl.SetItemText(0, 2, strAge);

         // goto next record
         recset.MoveNext();
      }

      // Close the database
      database.Close();
   }CATCH(CDBException, e) {
      // If a database exception occured, show error msg
      AfxMessageBox(L"Database error: " + e→m_strError);
   }
   END_CATCH;
}

步驟3 - 當以上程式碼編譯並執行時,您將看到以下輸出。

Retrieve Record

步驟4 - 按下讀取按鈕以執行資料庫操作。它將檢索以下Employees表。

Update Record

步驟5 - 您現在可以看到年齡已從69更新為59。

刪除記錄

SQL DELETE查詢用於從表中刪除現有記錄。您可以將WHERE子句與DELETE查詢一起使用來刪除選定的行,否則所有記錄都將被刪除。

步驟1 - 讓我們透過刪除ID等於3的記錄來了解一個簡單的示例。

SqlString = L"DELETE FROM Employees WHERE ID = 3;";

database.ExecuteSQL(SqlString);

步驟2 - 這是按鈕單擊事件的完整程式碼。

void CMFCDatabaseDemoDlg::OnBnClickedButtonRead() {
   // TODO: Add your control notification handler code here
   CDatabase database;
   CString SqlString;
   CString strID, strName, strAge;
   CString sDriver = L"MICROSOFT ACCESS DRIVER (*.mdb)";
   CString sDsn;
   CString sFile =
       L"C:\\Users\\Muhammad.Waqas\\Downloads\\Compressed\\ReadDB_demo\\Test.mdb";

   // You must change above path if it's different
   int iRec = 0;

   // Build ODBC connection string
   sDsn.Format(L"ODBC;DRIVER={%s};DSN='';DBQ=%s", sDriver, sFile);
   TRY {
      // Open the database
      database.Open(NULL,false,false,sDsn);

      // Allocate the recordset
      CRecordset recset(&database);

      SqlString = L"DELETE FROM Employees WHERE ID = 3;";

      database.ExecuteSQL(SqlString);

      SqlString = "SELECT ID, Name, Age FROM Employees";

      // Build the SQL statement
      SqlString = "SELECT ID, Name, Age FROM Employees";

      // Execute the query
      recset.Open(CRecordset::forwardOnly,SqlString,CRecordset::readOnly);

      // Reset List control if there is any data
      ResetListControl();
      // populate Grids
      ListView_SetExtendedListViewStyle(m_listCtrl,LVS_EX_GRIDLINES);
      // Column width and heading
      m_listCtrl.InsertColumn(0,L"Emp ID",LVCFMT_LEFT,-1,0);
      m_listCtrl.InsertColumn(1,L"Name",LVCFMT_LEFT,-1,1);
      m_listCtrl.InsertColumn(2, L"Age", LVCFMT_LEFT, -1, 1);
      m_listCtrl.SetColumnWidth(0, 120);
      m_listCtrl.SetColumnWidth(1, 200);
      m_listCtrl.SetColumnWidth(2, 200);

      // Loop through each record
      while (!recset.IsEOF()) {
         // Copy each column into a variable
         recset.GetFieldValue(L"ID",strID);
         recset.GetFieldValue(L"Name",strName);
         recset.GetFieldValue(L"Age", strAge);

         // Insert values into the list control
         iRec = m_listCtrl.InsertItem(0,strID,0);
         m_listCtrl.SetItemText(0,1,strName);
         m_listCtrl.SetItemText(0, 2, strAge);

         // goto next record
         recset.MoveNext();
      }
      // Close the database
      database.Close();
   }CATCH(CDBException, e) {
      // If a database exception occured, show error msg
      AfxMessageBox(L"Database error: " + e→m_strError);
   }
   END_CATCH;
}

步驟3 - 當以上程式碼編譯並執行時,您將看到以下輸出。

Retrieve Record

步驟4 - 按下讀取按鈕以執行資料庫操作。它將檢索Employees表。

Update Record

MFC - 序列化

序列化是將物件寫入或讀取到永續性儲存介質(如磁碟檔案)的過程。序列化非常適合需要在程式執行期間或之後維護結構化資料(如C++類或結構)狀態的情況。

在執行檔案處理時,值通常是基本型別(char、short、int、float或double)。同樣,我們可以一次一個地單獨儲存許多值。此技術不包括從(作為…的變數)類建立的物件。

MFC庫對序列化提供了高階支援。它從CObject類開始,該類是大多數MFC類的祖先,並配備了Serialize()成員函式。

讓我們透過建立一個新的MFC專案來了解一個簡單的示例。

步驟1 - 刪除TODO行並設計您的對話方塊,如下面的快照所示。

Remove TODO Line

步驟2 - 為所有編輯控制元件新增值變數。對於提到的Emp ID和Age,值型別為整數,如下面的快照所示。

Serialization Add Var

步驟3 - 為這兩個按鈕新增事件處理程式。

步驟4 - 現在讓我們新增一個簡單的Employee類,我們需要對其進行序列化。這是標頭檔案中Employee類的宣告。

class CEmployee : public CObject {
   public:
      int empID;
      CString empName;
      int age;
      CEmployee(void);
      ~CEmployee(void);
   private:

   public:
      void Serialize(CArchive& ar);
      DECLARE_SERIAL(CEmployee);
};

步驟5 - 這是源(*.cpp)檔案中Employee類的定義。

IMPLEMENT_SERIAL(CEmployee, CObject, 0)
CEmployee::CEmployee(void) {

}

CEmployee::~CEmployee(void) {

}

void CEmployee::Serialize(CArchive& ar) {
   CObject::Serialize(ar);

   if (ar.IsStoring())
      ar << empID << empName << age;
   else
      ar >> empID >> empName >> age;
}

步驟6 - 這是儲存按鈕事件處理程式的實現。

void CMFCSerializationDlg::OnBnClickedButtonSave() {
   // TODO: Add your control notification handler code here
   UpdateData(TRUE);
   CEmployee employee;
   CFile file;
   file.Open(L"EmployeeInfo.hse", CFile::modeCreate | CFile::modeWrite);
   CArchive ar(&file, CArchive::store);
   employee.empID = m_id;
   employee.empName = m_strName;
   employee.age = m_age;
   employee.Serialize(ar);
   ar.Close();
}

步驟7 - 這是開啟按鈕事件處理程式的實現。

void CMFCSerializationDlg::OnBnClickedButtonOpen() {
   // TODO: Add your control notification handler code here
   UpdateData(TRUE);

   CFile file;

   file.Open(L"EmployeeInfo.hse", CFile::modeRead);
   CArchive ar(&file, CArchive::load);
   CEmployee employee;

   employee.Serialize(ar);

   m_id = employee.empID;
   m_strName = employee.empName;
   m_age = employee.age;
   ar.Close();
   file.Close();

   UpdateData(FALSE);
}

步驟8 - 當上述程式碼編譯並執行時,您將看到以下輸出。

Serialization Result

步驟9 - 在所有欄位中輸入資訊,然後單擊儲存並關閉此程式。

Serialization Insert Info

步驟10 - 它將儲存資料。再次執行應用程式並單擊開啟。它將載入Employee資訊。

Serialization Save Info

MFC - 多執行緒

Microsoft Foundation Class (MFC)庫提供對多執行緒應用程式的支援。執行緒是程序中的執行路徑。當您啟動記事本時,作業系統會建立一個程序並開始執行該程序的主執行緒。當此執行緒終止時,程序也將終止。

如果需要,您可以在應用程式中建立其他執行緒。MFC應用程式中的所有執行緒都由CWinThread物件表示。在大多數情況下,您甚至不必顯式建立這些物件;而是呼叫框架輔助函式AfxBeginThread,它將為您建立CWinThread物件。

讓我們透過建立一個新的基於MFC對話方塊的應用程式來看一個簡單的例子。

步驟1 - 將靜態控制元件的標題和ID分別更改為單擊“啟動執行緒”按鈕IDC_STATIC_TEXT

步驟2 - 拖動兩個按鈕併為這些按鈕新增單擊事件處理程式。

Start Thread Button

步驟3 - 為靜態文字控制元件新增控制變數。

步驟4 - 現在在CMFCMultithreadingDlg.cpp檔案的開頭新增以下三個全域性變數。

int currValue;
int maxValue;
BOOL stopNow;

步驟5 - 在CMFCMultithreadingDlg類中新增WM_TIMER訊息。

這是OnTimer()的實現

void CMFCMultithreadingDlg::OnTimer(UINT_PTR nIDEvent) {
   // TODO: Add your message handler code here and/or call default
   CString sStatusMsg;
   sStatusMsg.Format(L"Running: %d", currValue);
   m_ctrlStatus.SetWindowText(sStatusMsg);

   CDialogEx::OnTimer(nIDEvent);
}

步驟6 - 現在新增一個示例函式,用於在CMFCMultithreadingDlg類中的AfxBeginThread中使用。

UINT MyThreadProc(LPVOID Param) {
   while (!stopNow && (currValue < maxValue)) {
      currValue++;
      Sleep(50);     // would do some work here
   }
   
   return TRUE;
}

步驟7 - 這是“啟動執行緒”按鈕的事件處理程式的實現,它將啟動執行緒。

void CMFCMultithreadingDlg::OnBnClickedButtonStart() {
   // TODO: Add your control notification handler code here
   currValue = 0;
   maxValue = 5000;
   stopNow = 0;
   m_ctrlStatus.SetWindowText(L"Starting...");
   SetTimer(1234, 333, 0); // 3 times per second

   AfxBeginThread(MyThreadProc, 0); // <<== START THE THREAD
}

步驟8 - 這是“停止執行緒”按鈕的事件處理程式的實現,它將停止執行緒。

void CMFCMultithreadingDlg::OnBnClickedButtonStop() {
   
   // TODO: Add your control notification handler code here
   stopNow = TRUE;
   KillTimer(1234);
   m_ctrlStatus.SetWindowText(L"Stopped");
}

步驟9 - 這是完整的原始檔。

// MFCMultithreadingDlg.cpp : implementation file
//

#include "stdafx.h"
#include "MFCMultithreading.h"
#include "MFCMultithreadingDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CMFCMultithreadingDlg dialog

int currValue;
int maxValue;
BOOL stopNow;

CMFCMultithreadingDlg::CMFCMultithreadingDlg(CWnd* pParent /* = NULL*/)
   : CDialogEx(IDD_MFCMULTITHREADING_DIALOG, pParent) {
   m_hIcon = AfxGetApp() -> LoadIcon(IDR_MAINFRAME);
}
void CMFCMultithreadingDlg::DoDataExchange(CDataExchange* pDX) {
   CDialogEx::DoDataExchange(pDX);
   DDX_Control(pDX, IDC_STATIC_TEXT, m_ctrlStatus);
}

BEGIN_MESSAGE_MAP(CMFCMultithreadingDlg, CDialogEx)
   ON_WM_PAINT()
   ON_WM_QUERYDRAGICON()
   ON_BN_CLICKED(IDC_BUTTON_START,
      &CMFCMultithreadingDlg::OnBnClickedButtonStart)
   ON_WM_TIMER()
   ON_BN_CLICKED(IDC_BUTTON_STOP,
      &CMFCMultithreadingDlg::OnBnClickedButtonStop)
END_MESSAGE_MAP()

// CMFCMultithreadingDlg message handlers

BOOL CMFCMultithreadingDlg::OnInitDialog() {
   CDialogEx::OnInitDialog();

   // Set the icon for this dialog. The framework does this automatically
   // when the application's main window is not a dialog
   SetIcon(m_hIcon, TRUE);        // Set big icon
   SetIcon(m_hIcon, FALSE);       // Set small icon

   // TODO: Add extra initialization here

   return TRUE; // return TRUE unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.

void CMFCMultithreadingDlg::OnPaint() {
   if (IsIconic()) {
      CPaintDC dc(this); // device context for painting
      SendMessage(WM_ICONERASEBKGND,
         reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
			
      // Center icon in client rectangle
      int cxIcon = GetSystemMetrics(SM_CXICON);
      int cyIcon = GetSystemMetrics(SM_CYICON);
      CRect rect;
      GetClientRect(&rect);
      int x = (rect.Width() - cxIcon + 1) / 2;
      int y = (rect.Height() - cyIcon + 1) / 2;

      // Draw the icon
      dc.DrawIcon(x, y, m_hIcon);
   }else {
      CDialogEx::OnPaint();
   }
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMFCMultithreadingDlg::OnQueryDragIcon() {
   return static_cast<HCURSOR>(m_hIcon);
}

UINT /*CThreadDlg::*/MyThreadProc(LPVOID Param) //Sample function for using in
AfxBeginThread {
   while (!stopNow && (currValue < maxValue)) {
      currValue++;
      Sleep(50); // would do some work here
   }
   return TRUE;
}
void CMFCMultithreadingDlg::OnBnClickedButtonStart() {
   // TODO: Add your control notification handler code here
   currValue = 0;
   maxValue = 5000;
   stopNow = 0;
   m_ctrlStatus.SetWindowText(L"Starting...");
   SetTimer(1234, 333, 0); // 3 times per second

   AfxBeginThread(MyThreadProc, 0); // <<== START THE THREAD
}

void CMFCMultithreadingDlg::OnTimer(UINT_PTR nIDEvent) {
   // TODO: Add your message handler code here and/or call default
   CString sStatusMsg;
   sStatusMsg.Format(L"Running: %d", currValue);
   m_ctrlStatus.SetWindowText(sStatusMsg);

   CDialogEx::OnTimer(nIDEvent);
}

void CMFCMultithreadingDlg::OnBnClickedButtonStop() {
   // TODO: Add your control notification handler code here
   stopNow = TRUE;
   KillTimer(1234);
   m_ctrlStatus.SetWindowText(L"Stopped");
}

步驟10 - 當上述程式碼編譯並執行時,您將看到以下輸出。

Multithreading

步驟11 - 現在單擊“啟動執行緒”按鈕。

Start Thread

步驟12 - 單擊“停止執行緒”按鈕。它將停止執行緒。

Stop Thread

MFC - 網際網路程式設計

Microsoft提供了許多用於程式設計客戶端和伺服器應用程式的API。許多新的應用程式正在為Internet編寫,並且隨著技術、瀏覽器功能和安全選項的變化,將編寫新的應用程式型別。您的自定義應用程式可以檢索資訊並在Internet上提供資料。

MFC提供了一個CSocket類,用於使用Windows Sockets編寫網路通訊程式。

以下是CSocket類中的方法列表。

序號 名稱 & 描述

1

Attach

將SOCKET控制代碼附加到CSocket物件。

2

CancelBlockingCall

取消當前正在進行的阻塞呼叫。

3

Create

建立套接字。

4

FromHandle

給定SOCKET控制代碼,返回指向CSocket物件的指標。

5

IsBlocking

確定是否正在進行阻塞呼叫。

讓我們透過建立一個MFS SDI應用程式來了解一個簡單的示例。

MFCServer

步驟1 - 在名稱欄位中輸入MFCServer,然後單擊確定。

MFCServer

步驟2 - 在“高階功能”選項卡上,選中“Windows套接字”選項。

步驟3 - 建立專案後,新增一個新的MFC類CServerSocket。

MFCServer

步驟4 - 選擇CSocket作為基類,然後單擊“完成”。

步驟5 - 新增更多MFC類CReceivingSocket。

MFCServer

步驟6 - CRecevingSocket將接收來自客戶端的傳入訊息。

在CMFCServerApp中,標頭檔案包含以下檔案 -

#include "ServerSocket.h"
#include "MFCServerView.h"

步驟7 - 在CMFCServerApp類中新增以下兩個類變數。

CServerSocket m_serverSocket;
CMFCServerView m_pServerView;

步驟8 - 在CMFCServerApp::InitInstance()方法中,建立套接字並指定埠,然後呼叫Listen方法,如下所示。

m_serverSocket.Create(6666);
m_serverSocket.Listen();

步驟9 - 在CMFCServerView標頭檔案中包含以下標頭檔案。

#include "MFCServerDoc.h"

步驟10 - 覆蓋Socket類中的OnAccept函式。

MFCServer

步驟11 - 在類檢視中選擇CServerSocket,並在“屬性”視窗中選擇突出顯示的圖示。現在,新增OnAccept。這是OnAccept函式的實現。

void CServerSocket::OnAccept(int nErrorCode) {

   // TODO: Add your specialized code here and/or call the base class
   AfxMessageBox(L"Connection accepted");
   CSocket::OnAccept(nErrorCode);
}

步驟12 - 新增OnReceive()函式。

void CServerSocket::OnReceive(int nErrorCode) { 
   
   // TODO: Add your specialized code here and/or call the base class
   AfxMessageBox(L"Data Received");
   CSocket::OnReceive(nErrorCode);
}

步驟13 - 在CReceivingSocket類中新增OnReceive()函式。

右鍵單擊解決方案資源管理器中的CMFCServerView類,然後選擇新增→新增函式。

MFCServer

步驟14 - 輸入上述資訊,然後單擊“完成”。

步驟15 - 在CMFCServerView標頭檔案中新增以下CStringArray變數。

CStringArray m_msgArray;

步驟16 - 這是AddMsg()函式的實現。

void CMFCServerView::AddMsg(CString message) {

   m_msgArray.Add(message);
   Invalidate();
}

步驟17 - 更新建構函式,如下面的程式碼所示。

CMFCServerView::CMFCServerView() {

   ((CMFCServerApp*)AfxGetApp()) -> m_pServerView = this;
}

步驟18 - 這是OnDraw()函式的實現,它顯示訊息。

void CMFCServerView::OnDraw(CDC* pDC) {

   int y = 100;
   for (int i = 0; m_msgArray.GetSize(); i++) {
   
      pDC->TextOut(100, y, m_msgArray.GetAt(i));
      y += 50;
   }
   CMFCServerDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here
}

步驟19 - 伺服器端現在已完成。它將接收來自客戶端的訊息。

建立客戶端應用程式

步驟1 - 讓我們為客戶端應用程式建立一個新的基於MFC對話方塊的應用程式。

Client Side

Client Side

步驟2 - 在“高階功能”選項卡上,選中“Windows套接字”選項,如上所示。

步驟3 - 建立專案後,設計您的對話方塊,如下面的快照所示。

Client Side

步驟4 - 為“連線”和“傳送”按鈕新增事件處理程式。

步驟5 - 為所有三個編輯控制元件新增值變數。對於埠編輯控制元件,選擇變數型別UINT。

Client Side

步驟6 - 新增用於連線和傳送訊息的MFC類。

Client Side

步驟7 - 在標頭檔案CMFCClientDemoApp類中包含CClientSocket類的標頭檔案並新增類變數。同樣,在CMFCClientDemoDlg標頭檔案中也新增類變數。

CClientSocket m_clientSocket;

步驟8 - 這是“連線”按鈕事件處理程式的實現。

void CMFCClientDemoDlg::OnBnClickedButtonConnect() {

   // TODO: Add your control notification handler code here
   UpdateData(TRUE);
   m_clientSocket.Create();
   if (m_clientSocket.Connect(m_ipAddress, m_port)) {
      AfxMessageBox(L"Connection Successfull");
   }else {
      AfxMessageBox(L"Connection Failed");
   }
   DWORD error = GetLastError();
}

步驟9 - 這是“傳送”按鈕事件處理程式的實現。

void CMFCClientDemoDlg::OnBnClickedButtonSend() {

   // TODO: Add your control notification handler code here
   UpdateData(TRUE);
   if (m_clientSocket.Send(m_message.GetBuffer(m_message.GetLength()), m_message.GetLength())) {
   
   }else {
      AfxMessageBox(L"Failed to send message");
   }
}

步驟10 - 首先執行伺服器應用程式,然後執行客戶端應用程式。輸入本地主機IP和埠,然後單擊“連線”。

Client Side

步驟11 - 您現在將在伺服器端看到訊息,如下面的快照所示。

Client Side

MFC - GDI

Windows提供各種繪圖工具供在裝置環境中使用。它提供用於繪製線條的筆、用於填充內部的畫刷和用於繪製文字的字型。MFC提供與Windows中的繪圖工具等效的圖形物件類。

繪圖

裝置上下文是 Windows 中的一種資料結構,包含有關裝置(如顯示器或印表機)的繪圖屬性的資訊。所有繪圖呼叫都是透過裝置上下文物件進行的,該物件封裝了 Windows 用於繪製線條、形狀和文字的 API。

裝置上下文允許在 Windows 中進行裝置無關的繪圖。裝置上下文可用於繪製到螢幕、印表機或圖元檔案。

CDC 是 MFC 中進行繪圖最基礎的類。CDC 物件提供成員函式來執行基本的繪圖步驟,以及用於處理與視窗客戶區關聯的顯示上下文的成員。

序號 名稱 & 描述

1

AbortDoc

終止當前列印作業,擦除應用程式自上次呼叫 StartDoc 成員函式以來寫入裝置的所有內容。

2

AbortPath

關閉並丟棄裝置上下文中的任何路徑。

3

AddMetaFileComment

將註釋從緩衝區複製到指定的增強格式圖元檔案。

4

AlphaBlend

顯示具有透明或半透明畫素的點陣圖。

5

AngleArc

繪製一條線段和一個弧線,並將當前位置移動到弧線的終點。

6

Arc

繪製橢圓弧。

7

ArcTo

繪製橢圓弧。此函式類似於 Arc,但會更新當前位置。

8

Attach

將 Windows 裝置上下文附加到此 CDC 物件。

9

BeginPath

在裝置上下文中開啟路徑括號。

10

BitBlt

從指定的裝置上下文複製點陣圖。

11

Chord

繪製弦(一個由橢圓和線段的交點限定的封閉圖形)。

12

CloseFigure

關閉路徑中的開放圖形。

13

CreateCompatibleDC

建立一個與另一個裝置上下文相容的記憶體裝置上下文。您可以使用它在記憶體中準備影像。

14

CreateDC

為特定裝置建立裝置上下文。

15

CreateIC

為特定裝置建立資訊上下文。這提供了一種快速獲取有關裝置資訊的方法,而無需建立裝置上下文。

16

DeleteDC

刪除與此 CDC 物件關聯的 Windows 裝置上下文。

17

DeleteTempMap

CWinApp 空閒時間處理程式呼叫,以刪除由 FromHandle 建立的任何臨時 CDC 物件。還分離裝置上下文。

18

Detach

將 Windows 裝置上下文從此 CDC 物件分離。

19

DPtoHIMETRIC

將裝置單位轉換為 HIMETRIC 單位。

20

DPtoLP

將裝置單位轉換為邏輯單位。

21

Draw3dRect

繪製一個三維矩形。

22

DrawDragRect

在矩形被拖動時擦除並重繪它。

23

DrawEdge

繪製矩形的邊框。

24

DrawEscape

訪問影片顯示的繪圖功能,這些功能無法透過圖形裝置介面 (GDI) 直接訪問。

25

DrawFocusRect

以用於指示焦點的樣式繪製矩形。

26

DrawFrameControl

繪製框架控制元件。

27

DrawIcon

繪製圖標。

28

DrawState

顯示影像並應用視覺效果以指示狀態。

29

DrawText

在指定的矩形中繪製格式化文字。

30

DrawTextEx

使用其他格式在指定的矩形中繪製格式化文字。

31

Ellipse

繪製橢圓。

32

EndDoc

結束由 StartDoc 成員函式啟動的列印作業。

33

EndPage

通知裝置驅動程式頁面即將結束。

34

EndPath

關閉路徑括號並將括號定義的路徑選入裝置上下文。

35

EnumObjects

列舉裝置上下文中可用的筆和刷子。

36

Escape

允許應用程式訪問特定裝置無法透過 GDI 直接訪問的功能。還允許訪問 Windows 轉義函式。應用程式發出的轉義呼叫會被翻譯併發送到裝置驅動程式。

37

ExcludeClipRect

建立一個新的剪裁區域,該區域由現有剪裁區域減去指定的矩形組成。

38

ExcludeUpdateRgn

透過從剪裁區域中排除視窗中更新的區域來防止在視窗的無效區域內繪製。

39

ExtFloodFill

使用當前畫刷填充區域。提供比 FloodFill 成員函式更多的靈活性。

40

ExtTextOut

使用當前選定的字型在矩形區域內寫入字元字串。

41

FillPath

關閉當前路徑中的任何開放圖形,並使用當前畫刷和多邊形填充模式填充路徑的內部。

42

FillRect

使用特定的畫刷填充給定的矩形。

43

FillRgn

使用指定的畫刷填充特定區域。

44

FillSolidRect

使用純色填充矩形。

45

FlattenPath

將路徑中選定的任何曲線轉換為當前裝置上下文,並將每個曲線轉換為一系列線。

46

FloodFill

使用當前畫刷填充區域。

47

FrameRect

在矩形周圍繪製邊框。

48

FrameRgn

使用畫刷在特定區域周圍繪製邊框。

49

FromHandle

在給定裝置上下文控制代碼時返回指向 CDC 物件的指標。如果 CDC 物件未附加到控制代碼,則會建立一個臨時 CDC 物件並將其附加。

50

GetArcDirection

返回裝置上下文的當前弧線方向。

51

GetAspectRatioFilter

檢索當前縱橫比過濾器的設定。

52

GetBkColor

檢索當前背景顏色。

53

GetBkMode

檢索背景模式。

54

GetBoundsRect

返回指定裝置上下文的當前累積邊界矩形。

55

GetBrushOrg

檢索當前畫刷的原點。

56

GetCharABCWidths

檢索當前字型中給定範圍內連續字元的寬度(以邏輯單位為單位)。

57

GetCharABCWidthsI

檢索當前 TrueType 字型中指定範圍內連續字形索引的寬度(以邏輯單位為單位)。

58

GetCharacterPlacement

檢索有關字元字串的各種型別的資訊。

59

GetCharWidth

檢索當前字型中給定範圍內連續字元的分數寬度。

60

GetCharWidthI

檢索當前字型中指定範圍內連續字形索引的寬度(以邏輯座標為單位)。

61

GetClipBox

檢索當前剪裁邊界周圍最緊密的邊界矩形的尺寸。

62

GetColorAdjustment

檢索裝置上下文的顏色調整值。

63

GetCurrentBitmap

返回指向當前選定的 CBitmap 物件的指標。

64

GetCurrentBrush

返回指向當前選定的 CBrush 物件的指標。

65

GetCurrentFont

返回指向當前選定的 CFont 物件的指標。

66

GetCurrentPalette

返回指向當前選定的 CPalette 物件的指標。

48

GetCurrentPen

返回指向當前選定的 CPen 物件的指標。

67

GetCurrentPosition

檢索筆的當前位置(以邏輯座標為單位)。

68

GetDCBrushColor

檢索當前畫刷顏色。

69

GetDCPenColor

檢索當前筆顏色。

70

GetDeviceCaps

檢索有關給定顯示裝置的功能的特定於裝置的資訊。

71

GetFontData

從可縮放字型檔案檢索字型度量資訊。要檢索的資訊透過指定字型檔案中的偏移量和要返回的資訊的長度來標識。

72

GetFontLanguageInfo

返回有關指定顯示上下文當前選定字型的資訊。

73

GetGlyphOutline

檢索當前字型中輪廓字元的輪廓曲線或點陣圖。

74

GetGraphicsMode

檢索指定裝置上下文的當前圖形模式。

75

GetHalftoneBrush

檢索半色調畫刷。

76

GetKerningPairs

檢索指定裝置上下文中當前選定的字型的字元間距對。

77

GetLayout

檢索裝置上下文 (DC) 的佈局。佈局可以是從左到右(預設)或從右到左(映象)。

78

GetMapMode

檢索當前對映模式。

79

GetMiterLimit

返回裝置上下文的斜接限制。

80

GetNearestColor

檢索給定裝置可以表示的與指定邏輯顏色最接近的邏輯顏色。

81

GetOutlineTextMetrics

檢索 TrueType 字型的字型度量資訊。

82

GetOutputCharWidth

使用輸出裝置上下文檢索當前字型中連續字元組中各個字元的寬度。

83

GetOutputTabbedTextExtent

計算輸出裝置上下文中字元字串的寬度和高度。

84

GetOutputTextExtent

使用當前字型確定尺寸,計算輸出裝置上下文上文字行的寬度和高度。

85

GetOutputTextMetrics

從輸出裝置上下文檢索當前字型的度量。

86

GetPath

檢索定義選入裝置上下文中的路徑中找到的線條端點和曲線的控制點的座標。

87

GetPixel

檢索指定點處的畫素的 RGB 顏色值。

88

GetPolyFillMode

檢索當前多邊形填充模式。

89

GetROP2

檢索當前繪圖模式。

90

GetSafeHdc

返回 m_hDC,即輸出裝置上下文。

91

GetStretchBltMode

檢索當前點陣圖拉伸模式。

92

GetTabbedTextExtent

計算屬性裝置上下文中字元字串的寬度和高度。

93

GetTextAlign

檢索文字對齊標誌。

94

GetTextCharacterExtra

檢索字元間距量的當前設定。

95

GetTextColor

檢索當前文字顏色。

96

GetTextExtent

使用當前字型確定尺寸,計算屬性裝置上下文上文字行的寬度和高度。

97

GetTextExtentExPointI

檢索指定字串中適合指定空間的字元數,並用每個字元的文字範圍填充陣列。

98

GetTextExtentPointI

檢索指定字形索引陣列的寬度和高度。

99

GetTextFace

將當前字型的字型名稱複製到緩衝區中,作為以 null 結尾的字串。

100

GetTextMetrics

從屬性裝置上下文檢索當前字型的度量。

101

GetViewportExt

檢索視口的 x 和 y 範圍。

102

GetViewportOrg

檢索視口原點的 x 和 y 座標。

103

GetWindow

返回與顯示裝置上下文關聯的視窗。

104

GetWindowExt

檢索關聯視窗的 x 和 y 範圍。

105

GetWindowOrg

獲取關聯視窗原點的 x 和 y 座標。

106

GetWorldTransform

檢索當前世界空間到頁面空間的轉換。

107

GradientFill

使用漸變顏色填充矩形和三角形結構。

108

GrayString

在給定位置繪製灰顯(變灰)文字。

109

HIMETRICtoDP

將 HIMETRIC 單位轉換為裝置單位。

110

HIMETRICtoLP

將 HIMETRIC 單位轉換為邏輯單位。

111

IntersectClipRect

透過形成當前區域和矩形的交集建立一個新的剪裁區域。

112

InvertRect

反轉矩形的內容。

113

InvertRgn

反轉區域中的顏色。

114

IsPrinting

確定裝置上下文是否用於列印。

115

LineTo

從當前位置繪製一條線到(但不包括)一個點。

116

LPtoDP

將邏輯單位轉換為裝置單位。

117

LPtoHIMETRIC

將邏輯單位轉換為 HIMETRIC 單位。

118

MaskBlt

使用給定的掩碼和光柵運算組合源和目標點陣圖的顏色資料。

119

ModifyWorldTransform

使用指定的模式更改裝置上下文的 world 轉換。

120

MoveTo

移動當前位置。

121

OffsetClipRgn

移動給定裝置的剪裁區域。

122

OffsetViewportOrg

相對於當前視口原點的座標修改視口原點。

123

OffsetWindowOrg

相對於當前視窗原點的座標修改視窗原點。

124

PaintRgn

使用選定的畫刷填充區域。

125

PatBlt

建立位模式。

126

Pie

繪製一個扇形區域。

127

PlayMetaFile

在給定的裝置上播放指定元檔案的內容。PlayMetaFile 的增強版本顯示儲存在給定增強格式元檔案中的圖片。元檔案可以播放任意次數。

128

PlgBlt

執行源裝置上下文指定矩形中顏色資料的位塊傳輸到給定裝置上下文指定的平行四邊形。

129

PolyBezier

繪製一個或多個貝塞爾樣條曲線。當前位置既不使用也不更新。

130

PolyBezierTo

繪製一個或多個貝塞爾樣條曲線,並將當前位置移動到最後一個貝塞爾樣條曲線的結束點。

131

PolyDraw

繪製一組線段和貝塞爾樣條曲線。此函式更新當前位置。

132

Polygon

繪製一個由兩點或更多點(頂點)組成的多邊形,這些點透過線連線。

133

Polyline

繪製一組連線指定點的線段。

134

PolylineTo

繪製一條或多條直線,並將當前位置移動到最後一條線的結束點。

135

PolyPolygon

建立兩個或多個多邊形,這些多邊形使用當前多邊形填充模式填充。這些多邊形可能是分離的,也可能重疊。

136

PolyPolyline

繪製多個系列的連線線段。此函式既不使用也不更新當前位置。

137

PtVisible

指定給定點是否在剪裁區域內。

138

RealizePalette

將當前邏輯調色盤中的調色盤條目對映到系統調色盤。

139

Rectangle

使用當前筆繪製矩形,並使用當前畫刷填充它。

140

RectVisible

確定給定矩形的任何部分是否位於剪裁區域內。

141

ReleaseAttribDC

釋放m_hAttribDC(屬性裝置上下文)。

142

ReleaseOutputDC

釋放m_hDC(輸出裝置上下文)。

143

ResetDC

更新 m_hAttribDC 裝置上下文。

144

RestoreDC

將裝置上下文恢復到SaveDC儲存的先前狀態。

145

RoundRect

使用當前筆繪製具有圓角的矩形,並使用當前畫刷填充它。

146

SaveDC

儲存裝置上下文的當前狀態。

147

ScaleViewportExt

相對於當前值修改視口範圍。

148

ScaleWindowExt

相對於當前值修改視窗範圍。

149

ScrollDC

水平和垂直滾動位矩形。

150

SelectClipPath

選擇當前路徑作為裝置上下文的剪裁區域,使用指定的模式將新區域與任何現有的剪裁區域組合。

151

SelectClipRgn

使用指定的模式將給定區域與當前剪裁區域組合。

152

SelectObject

選擇 GDI 繪圖物件(例如筆)。

153

SelectPalette

選擇邏輯調色盤。

154

SelectStockObject

選擇 Windows 提供的預定義的庫存筆、畫刷或字型之一。

155

SetAbortProc

設定程式設計師提供的回撥函式,如果必須中止列印作業,Windows 會呼叫該函式。

156

SetArcDirection

設定用於圓弧和矩形函式的繪製方向。

157

SetAttribDC

設定 m_hAttribDC(屬性裝置上下文)。

158

SetBkColor

設定當前背景顏色。

159

SetBkMode

設定背景模式。

160

SetBoundsRect

控制指定裝置上下文的邊界矩形資訊的累積。

161

SetBrushOrg

指定選擇到裝置上下文中的下一個畫刷的原點。

162

SetColorAdjustment

使用指定的值設定裝置上下文的顏色調整值。

163

SetDCBrushColor

設定當前畫刷顏色。

164

SetDCPenColor

設定當前筆顏色。

165

SetGraphicsMode

設定指定裝置上下文的當前圖形模式。

166

SetLayout

更改裝置上下文 (DC) 的佈局。

167

SetMapMode

設定當前對映模式。

168

SetMapperFlags

更改字型對映器在將邏輯字型對映到物理字型時使用的演算法。

169

SetMiterLimit

設定裝置上下文的斜接連線長度限制。

170

SetOutputDC

設定 m_hDC(輸出裝置上下文)。

171

SetPixel

將指定點處的畫素設定為指定顏色的最接近近似值。

172

SetPixelV

將指定座標處的畫素設定為指定顏色的最接近近似值。SetPixelVSetPixel 更快,因為它不需要返回實際繪製的點的顏色值。

173

SetPolyFillMode

設定多邊形填充模式。

175

SetROP2

設定當前繪圖模式。

176

SetStretchBltMode

設定點陣圖拉伸模式。

177

SetTextAlign

設定文字對齊標誌。

178

SetTextCharacterExtra

設定字元間距量。

179

SetTextColor

設定文字顏色。

180

SetTextJustification

在字串中的換行符字元中新增空格。

181

SetViewportExt

設定視口的 x 和 y 範圍。

182

SetViewportOrg

設定視口原點。

183

SetWindowExt

設定關聯視窗的 x 和 y 範圍。

184

SetWindowOrg

設定裝置上下文的視窗原點。

185

SetWorldTransform

設定當前世界空間到頁面空間的轉換。

186

StartDoc

通知裝置驅動程式新的列印作業已開始。

187

StartPage

通知裝置驅動程式新頁面已開始。

188

StretchBlt

將點陣圖從源矩形和裝置移動到目標矩形,如有必要,拉伸或壓縮點陣圖以適應目標矩形的尺寸。

189

StrokeAndFillPath

關閉路徑中任何開啟的圖形,使用當前筆描繪路徑的輪廓,並使用當前畫刷填充其內部。

190

StrokePath

使用當前筆呈現指定的路徑。

191

TabbedTextOut

在指定位置寫入字元字串,將製表符擴充套件到製表位陣列中指定的值。

192

TextOut

使用當前選定的字型在指定位置寫入字元字串。

193

TransparentBlt

將顏色資料的位塊從指定的源裝置上下文傳輸到目標裝置上下文,在傳輸中呈現指定的顏色透明。

194

UpdateColors

透過逐畫素地將客戶端區域中的當前顏色與系統調色盤匹配來更新裝置上下文的客戶端區域。

195

WidenPath

將當前路徑重新定義為如果使用當前選擇到裝置上下文中的筆描繪路徑將繪製的區域。

Lines

步驟 1 - 讓我們透過建立一個名為MFCGDIDemo的新基於 MFC 的單文件專案來了解一個簡單的示例。

Lines

步驟 2 - 建立專案後,轉到解決方案資源管理器,雙擊“原始檔”資料夾下的MFCGDIDemoView.cpp檔案。

步驟 3 - 在CMFCGDIDemoView::OnDraw()方法中繪製如下所示的線條。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   pDC->MoveTo(95, 125);
   pDC->LineTo(230, 125);
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here
}

步驟 4 - 執行此應用程式。您將看到以下輸出。

Lines

步驟 5 - CDC::MoveTo()方法用於設定線條的起始位置。

使用 LineTo() 時,程式從 MoveTo() 點開始到 LineTo() 結束。

在 LineTo() 之後,如果您不呼叫 MoveTo(),並且再次使用其他點值呼叫 LineTo(),程式將從上一個 LineTo() 繪製一條線到新的 LineTo() 點。

步驟 6 - 要繪製不同的線條,您可以使用此屬性,如下面的程式碼所示。

void CMFCGDIDemoView::OnDraw(CDC* pDC) { 
   pDC->MoveTo(95, 125);
   pDC->LineTo(230, 125);
   pDC->LineTo(230, 225);
   pDC->LineTo(95, 325);
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here 
}

步驟 7 - 執行此應用程式。您將看到以下輸出。

Lines

Polylines

折線是由一系列連線的線組成的。這些線儲存在 POINT 或 CPoint 值的陣列中。要繪製折線,可以使用 CDC::Polyline() 方法。要繪製折線,至少需要兩點。如果您定義了兩個以上的點,則第一條線之後的每一條線都將從前一點繪製到下一條點,直到包含所有點。

步驟 1 - 讓我們瞭解一個簡單的示例。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   CPoint Pt[7];
   Pt[0] = CPoint(20, 150);
   Pt[1] = CPoint(180, 150);
   Pt[2] = CPoint(180, 20);
   pDC−Polyline(Pt, 3);
   
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here
}

步驟 2 - 執行此應用程式時,您將看到以下輸出。

Polylines

Rectangles

矩形是由四個組成四個直角的邊組成的幾何圖形。與線條一樣,要繪製矩形,必須定義它的起點和終點。要繪製矩形,可以使用 CDC::Rectangle() 方法。

步驟 1 - 讓我們瞭解一個簡單的示例。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   pDC->Rectangle(15, 15, 250, 160);
   
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here
}

步驟 2 - 執行此應用程式時,您將看到以下輸出。

Rectangles

Squares

正方形是由四個組成四個直角的邊組成的幾何圖形,但每條邊的長度必須相等。

讓我們來看一個簡單的例子。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   pDC->Rectangle(15, 15, 250, 250);
   
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here
}

執行此應用程式時,您將看到以下輸出。

Squares

Pies

扇形是橢圓的一部分或一段,這意味著扇形是一個不完整的橢圓。要繪製扇形,可以使用 CDC::Pie() 方法,如下所示 -

BOOL Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);

  • (x1, y1) 點確定代表扇形的橢圓所在的矩形的左上角。(x2, y2) 點是矩形的右下角。

Pies
  • (x3, y3) 點以預設的逆時針方向指定扇形的起始角。

  • (x4, y4) 點指定扇形的結束點。

讓我們來看一個簡單的例子。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   pDC->Pie(40, 20, 226, 144, 155, 32, 202, 115);
   
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here
}

步驟 2 - 執行此應用程式時,您將看到以下輸出。

Pies

Arcs

圓弧是橢圓的一部分或一段,這意味著圓弧是一個不完整的橢圓。要繪製圓弧,可以使用 CDC::Arc() 方法。

BOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);

Arcs

CDC 類配備了 SetArcDirection() 方法。

以下是語法 -

int SetArcDirection(int nArcDirection)

序號 值 & 方向
1

AD_CLOCKWISE

圖形按順時針方向繪製

2

AD_COUNTERCLOCKWISE

圖形按逆時針方向繪製

步驟 1 - 讓我們瞭解一個簡單的示例。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   pDC->SetArcDirection(AD_COUNTERCLOCKWISE);
   pDC->Arc(20, 20, 226, 144, 202, 115, 105, 32);
   
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here
}

步驟 2 - 執行此應用程式時,您將看到以下輸出。

Arcs

Chords

到目前為止,我們繪製的圓弧被認為是開放圖形,因為它們是由具有起點和終點的線組成的(與圓或矩形不同)。是一個兩端用直線連線的圓弧。

Chords

要繪製弦,可以使用 CDC::Chord() 方法。

BOOL Chord(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);

讓我們來看一個簡單的例子。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   pDC->SetArcDirection(AD_CLOCKWISE);
   pDC->Chord(20, 20, 226, 144, 202, 115, 105, 32);
   
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here
}

執行上述應用程式時,您將看到以下輸出。

Chords

此示例中的弧方向設定為順時針方向。

顏色

顏色是增強物件美觀外觀的最基本物件之一。顏色是一個非空間物件,新增到物件中以修改其某些視覺方面。MFC 庫與 Win32 API 結合使用,提供了各種操作,您可以利用這些操作來利用顏色的各個方面。

RGB 宏的行為類似於函式,並允許您傳遞三個用逗號分隔的數值。每個值必須在 0 到 255 之間,如下面的程式碼所示。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   COLORREF color = RGB(239, 15, 225);
}

讓我們來看一個簡單的例子。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   COLORREF color = RGB(239, 15, 225);
   pDC->SetTextColor(color);
   pDC->TextOut(100, 80, L"MFC GDI Tutorial", 16);
   
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here
}

執行此應用程式時,您將看到以下輸出。

Colors

字型

CFont 封裝了 Windows 圖形裝置介面 (GDI) 字型,並提供用於操作字型的成員函式。要使用 CFont 物件,請構造一個 CFont 物件並將 Windows 字型附加到它,然後使用物件的成員函式來操作字型。

讓我們來看一個簡單的例子。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   CFont font;
   font.CreatePointFont(920, L"Garamond");
   CFont *pFont = pDC->SelectObject(&font);
   COLORREF color = RGB(239, 15, 225);
   pDC->SetTextColor(color);
   pDC->TextOut(100, 80, L"MFC GDI Tutorial", 16);
   pDC->SelectObject(pFont);
   font.DeleteObject();
   
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
   return;

   // TODO: add draw code for native data here
}

執行上述應用程式時,您將看到以下輸出。

Fonts

畫筆

畫筆是一種用於在裝置上下文中繪製線條和曲線的工具。在圖形程式設計中,畫筆也用於繪製幾何閉合形狀(如矩形或多邊形)的邊框。Microsoft Windows 考慮兩種型別的畫筆——裝飾性幾何

當畫筆只能用於繪製固定寬度(小於或等於 1 畫素)的簡單線條時,稱為裝飾性畫筆。當畫筆可以採用不同的寬度和各種端點時,它就是幾何畫筆。MFC 提供了一個類CPen,它封裝了 Windows 圖形裝置介面 (GDI) 畫筆。

讓我們來看一個簡單的例子。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   CPen pen;
   pen.CreatePen(PS_DASHDOTDOT, 1, RGB(160, 75, 90));
   pDC->SelectObject(&pen);
   pDC->Rectangle(25, 35, 250, 125);
   
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here
}

執行上述應用程式時,您將看到以下輸出。

Pens

畫刷

畫刷是一種繪圖工具,用於填充封閉的形狀或線條的內部。畫刷的行為就像拿起一桶油漆並將其倒在某個地方。MFC 提供了一個類CBrush,它封裝了 Windows 圖形裝置介面 (GDI) 畫刷。

讓我們來看一個簡單的例子。

void CMFCGDIDemoView::OnDraw(CDC* pDC) {
   CBrush brush(RGB(100, 150, 200));
   CBrush *pBrush = pDC->SelectObject(&brush);
   pDC->Rectangle(25, 35, 250, 125);
   pDC->SelectObject(pBrush);
   
   CMFCGDIDemoDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

   // TODO: add draw code for native data here
}

執行此應用程式時,您將看到以下輸出。

Brushes

MFC - 庫

是一組函式、類或其他資源,可以提供給需要已實現的實體的程式,而無需瞭解這些函式、類或資源是如何建立的或如何工作的。庫使程式設計師可以輕鬆地使用其他人或公司建立的函式、類和資源等,並相信此外部來源是可靠且高效的。與庫相關的一些獨特功能包括:

  • 庫是建立的,並且像普通的常規程式一樣工作,使用函式或其他資源並與其他程式通訊。

  • 為了實現其功能,庫包含其他程式需要完成其功能的函式。

  • 同時,庫可能會使用某些其他程式不需要的函式。

  • 使用庫的程式也稱為庫的客戶端。

您將在庫中建立或包含兩種型別的函式:

  • 內部函式僅供庫本身使用,庫的客戶端不需要訪問這些函式。

  • 外部函式是可以被庫的客戶端訪問的函式。

在您的程式中,您將處理兩種主要型別的庫:

  • 靜態庫
  • 動態庫

靜態庫

靜態庫是一個包含函式、類或資源的檔案,外部程式可以使用這些檔案來補充其功能。要使用庫,程式設計師必須建立一個到它的連結。專案可以是控制檯應用程式、Win32 應用程式或 MFC 應用程式。庫檔案具有 lib 副檔名。

步驟 1 - 讓我們透過建立一個新的 Win32 專案來了解靜態庫的一個簡單示例。

Static Library

步驟 2 - 在應用程式嚮導對話方塊上,選擇靜態庫選項。

Static Library

步驟 3 − 單擊“完成”繼續。

Static Library

步驟 4 - 右鍵單擊解決方案資源管理器中的專案,並從新增→新建項…選單選項中新增標頭檔案。

Static Library

步驟 5 - 在名稱欄位中輸入 Calculator.h,然後單擊新增。

在標頭檔案中新增以下程式碼:

#pragma once
#ifndef _CALCULATOR_H_
#define _CALCULATOR_H_
double Min(const double *Numbers, const int Count);
double Max(const double *Numbers, const int Count);
double Sum(const double *Numbers, const int Count);
double Average(const double *Numbers, const int Count);
long GreatestCommonDivisor(long Nbr1, long Nbr2);
#endif // _CALCULATOR_H_

步驟 6 - 在專案中新增源 (*.cpp) 檔案。

Static Library

步驟 7 - 在名稱欄位中輸入 Calculator.cpp,然後單擊新增。

步驟 8 - 在 *.cpp 檔案中新增以下程式碼:

#include "StdAfx.h"
#include "Calculator.h"
double Min(const double *Nbr, const int Total) {
   double Minimum = Nbr[0];
   for (int i = 0; i < Total; i++)
      if (Minimum > Nbr[i])
         Minimum = Nbr[i];
   return Minimum;
}
double Max(const double *Nbr, const int Total) {
   double Maximum = Nbr[0];
   for (int i = 0; i < Total; i++)
      if (Maximum < Nbr[i])
         Maximum = Nbr[i];
   return Maximum;
}
double Sum(const double *Nbr, const int Total) {
   double S = 0;
   for (int i = 0; i < Total; i++)
      S += Nbr[i];
   return S;
}
double Average(const double *Nbr, const int Total) {
   double avg, S = 0;
   for (int i = 0; i < Total; i++)
       S += Nbr[i];
   avg = S / Total;
   return avg;
}
long GreatestCommonDivisor(long Nbr1, long Nbr2) {
   while (true) {
      Nbr1 = Nbr1 % Nbr2;
      if (Nbr1 == 0)
         return Nbr2;
      Nbr2 = Nbr2 % Nbr1;
      if (Nbr2 == 0)
         return Nbr1;
   }
}

步驟 9 - 從主選單構建此庫,方法是單擊生成→生成 MFCLib

Static Library

步驟 10 - 庫成功構建後,它將顯示上述訊息。

步驟 11 - 要從庫中使用這些函式,讓我們從檔案→新建→專案中新增另一個基於 MFC 的對話方塊應用程式。

Static Library

步驟 12 - 轉到 MFCLib\Debug 資料夾,並將標頭檔案和 *.lib 檔案複製到 MFCLibTest 專案,如下面的快照所示。

Static Library

步驟 13 - 要將庫新增到當前專案,請在主選單上單擊專案→新增現有項,然後選擇 MFCLib.lib。

步驟 14 - 設計您的對話方塊,如下面的快照所示。

Static Library

步驟 15 - 為兩個值為 double 型別的編輯控制元件新增值變數。

Static Library

步驟 16 - 為位於對話方塊末尾的靜態文字控制元件新增值變數。

Static Library

步驟 17 - 為計算按鈕新增事件處理程式。

要新增來自庫的功能,我們需要在 CMFCLibTestDlg.cpp 檔案中包含標頭檔案。

#include "stdafx.h"
#include "MFCLibTest.h"
#include "MFCLibTestDlg.h"
#include "afxdialogex.h"
#include "Calculator.h"

步驟 18 - 以下是按鈕事件處理程式的實現。

void CMFCLibTestDlg::OnBnClickedButtonCal() {
   // TODO: Add your control notification handler code here
   UpdateData(TRUE);
   CString strTemp;
   double numbers[2];
   numbers[0] = m_Num1;
   numbers[1] = m_Num2;

   strTemp.Format(L"%.2f", Max(numbers,2));
   m_strText.Append(L"Max is:\t" + strTemp);

   strTemp.Format(L"%.2f", Min(numbers, 2));
   m_strText.Append(L"\nMin is:\t" + strTemp);
   
   strTemp.Format(L"%.2f", Sum(numbers, 2));
   m_strText.Append(L"\nSum is:\t" + strTemp);

   strTemp.Format(L"%.2f", Average(numbers, 2));
   m_strText.Append(L"\nAverage is:\t" + strTemp);

   strTemp.Format(L"%d", GreatestCommonDivisor(m_Num1, m_Num2));
   m_strText.Append(L"\nGDC is:\t" + strTemp);

   UpdateData(FALSE);
}

步驟 19 - 編譯並執行上述程式碼後,您將看到以下輸出。

Static Library

步驟 20 - 在編輯欄位中輸入兩個值,然後單擊計算。現在,您將看到計算庫結果後的結果。

Static Library

動態庫

Win32 DLL 是一個庫,可以提供給在 Microsoft Windows 計算機上執行的程式。作為一個普通的庫,它由一組函式和/或其他資源組成,這些函式和/或其他資源分組在一個檔案中。

DLL 的縮寫代表動態連結庫。這意味著,與靜態庫相反,DLL 允許程式設計師決定何時以及如何將其他應用程式連結到此類庫。

例如,DLL 允許不同的應用程式根據需要使用其庫。實際上,在不同程式設計環境中建立的應用程式可以使用儲存在一個特定 DLL 中的函式或資源。因此,應用程式動態連結到庫。

步驟 1 - 讓我們透過建立一個新的 Win32 專案來了解一個簡單的示例。

Dynamic Library

步驟 2 - 在應用程式型別部分,單擊 DLL 單選按鈕。

Dynamic Library

步驟 3 − 單擊“完成”繼續。

步驟 4 - 在 MFCDynamicLib.cpp 檔案中新增以下函式,並使用以下方法公開其定義:

extern "C" _declspec(dllexport)

步驟 5 - 為將在 DLL 外部訪問的每個函式使用 _declspec(dllexport) 修飾符。

// MFCDynamicLib.cpp : Defines the exported functions for the DLL application.//

#include "stdafx.h"

extern "C" _declspec(dllexport) double Min(const double *Numbers, const int Count);
extern "C" _declspec(dllexport) double Max(const double *Numbers, const int Count);
extern "C" _declspec(dllexport) double Sum(const double *Numbers, const int Count);
extern "C" _declspec(dllexport) double Average(const double *Numbers, const int Count);
extern "C" _declspec(dllexport) long GreatestCommonDivisor(long Nbr1, long Nbr2);

double Min(const double *Nbr, const int Total) {
   double Minimum = Nbr[0];
   for (int i = 0; i < Total; i++)
      if (Minimum > Nbr[i])
         Minimum = Nbr[i];
   return Minimum;
}
double Max(const double *Nbr, const int Total) {
   double Maximum = Nbr[0];
   for (int i = 0; i < Total; i++)
      if (Maximum < Nbr[i])
         Maximum = Nbr[i];
   return Maximum;
}
double Sum(const double *Nbr, const int Total) {
   double S = 0;
   for (int i = 0; i < Total; i++)
      S += Nbr[i];
   return S;
}
double Average(const double *Nbr, const int Total){
   double avg, S = 0;
   for (int i = 0; i < Total; i++)
      S += Nbr[i];
   avg = S / Total;
   return avg;
}
long GreatestCommonDivisor(long Nbr1, long Nbr2) {
   while (true) {
      Nbr1 = Nbr1 % Nbr2;
      if (Nbr1 == 0)
         return Nbr2;
      Nbr2 = Nbr2 % Nbr1;
      if (Nbr2 == 0)
         return Nbr1;
   }
}

步驟 6 - 要建立 DLL,請在主選單上單擊生成>生成 MFCDynamicLib

Dynamic Library

步驟 7 - 成功建立 DLL 後,您將看到輸出視窗中顯示一條訊息。

步驟 8 - 開啟 Windows 資源管理器,然後開啟當前專案的 Debug 資料夾。

步驟 9 - 請注意,已建立了一個具有 dll 副檔名的檔案和另一個具有 lib 副檔名的檔案。

Dynamic Library

步驟 10 − 要使用 dll 副檔名測試此檔案,我們需要從“檔案”→“新建”→“專案”建立一個新的基於 MFC 對話方塊的應用程式。

Dynamic Library

步驟 11 − 進入 MFCDynamicLib\Debug 資料夾,並將 *.dll 和 *.lib 檔案複製到 MFCLibTest 專案中,如下面的快照所示。

Dynamic Library

步驟 12 − 要將 DLL 新增到當前專案中,請在主選單上單擊“專案”→“新增現有項”,然後選擇 MFCDynamicLib.lib 檔案。

步驟 13 − 設計您的對話方塊,如下面的快照所示。

Dynamic Library

步驟 14 − 為兩個編輯控制元件新增值為 double 型別的變數。

Dynamic Library

步驟 15 − 為對話方塊末尾的靜態文字控制元件新增變數。

Dynamic Library

步驟 16 − 為“計算”按鈕新增事件處理程式。

步驟 17 − 在使用 DLL 的專案中,每個將被訪問的函式都必須使用 _declspec(dllimport) 修飾符進行宣告。

步驟 18 − 在 MFCLibTestDlg.cpp 檔案中新增以下函式宣告。

extern "C" _declspec(dllimport) double Min(const double *Numbers, const int Count);
extern "C" _declspec(dllimport) double Max(const double *Numbers, const int Count);
extern "C" _declspec(dllimport) double Sum(const double *Numbers, const int Count);
extern "C" _declspec(dllimport) double Average(const double *Numbers, const int Count);
extern "C" _declspec(dllimport) long GreatestCommonDivisor(long Nbr1, long Nbr2);

步驟 19 − 以下是按鈕事件處理程式的實現。

void CMFCLibTestDlg::OnBnClickedButtonCal() {

   // TODO: Add your control notification handler code here
   UpdateData(TRUE);

   CString strTemp;
   double numbers[2];
   numbers[0] = m_Num1;
   numbers[1] = m_Num2;

   strTemp.Format(L"%.2f", Max(numbers,2));
   m_strText.Append(L"Max is:\t" + strTemp);

   strTemp.Format(L"%.2f", Min(numbers, 2));
   m_strText.Append(L"\nMin is:\t" + strTemp);

   strTemp.Format(L"%.2f", Sum(numbers, 2));
   m_strText.Append(L"\nSum is:\t" + strTemp);

   strTemp.Format(L"%.2f", Average(numbers, 2));
   m_strText.Append(L"\nAverage is:\t" + strTemp);

   strTemp.Format(L"%d", GreatestCommonDivisor(m_Num1, m_Num2));
   m_strText.Append(L"\nGDC is:\t" + strTemp);
 
   UpdateData(FALSE);
}

步驟 20 − 當以上程式碼編譯並執行後,您將看到以下輸出。

Dynamic Library

步驟 21 − 在編輯欄位中輸入兩個值,然後單擊“計算”。您現在將看到從 DLL 計算後的結果。

Dynamic Library
廣告