MFC – 快速指南
MFC – 快速指南
MFC – 概述
Microsoft 基础类 (MFC) 库提供了一组函数、常量、数据类型和类,以简化为 Microsoft Windows 操作系统创建应用程序的过程。在本教程中,您将了解如何使用 MFC 启动和创建基于 Windows 的应用程序。
先决条件
我们假设您知道以下内容 –
- 一些关于 Windows 编程的知识。
- C++ 编程的基础知识。
- 了解面向对象编程的基础知识。
什么是 MFC?
Microsoft 基础类库 (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 后,运行安装程序。将显示以下对话框。
步骤 2 – 单击安装开始安装过程。
步骤 3 – 成功安装 Visual Studio 后,您将看到以下对话框。
步骤 4 – 关闭此对话框并根据需要重新启动计算机。
步骤 5 – 从开始菜单打开 Visual Studio,这将打开以下对话框。第一次开始时,需要一些准备时间。
步骤 6 – 接下来,您将看到 Visual Studio 的主窗口。
第 7 步– 您现在可以开始申请了。
MFC – VC++ 项目
在本章中,我们将介绍不同类型的 VC++ 项目。Visual Studio 包括多种 Visual C++ 项目模板。这些模板有助于创建基本的程序结构、菜单、工具栏、图标、引用,并包含适合您要创建的项目类型的语句。以下是模板的一些显着特征。
-
它为许多这些项目模板提供了向导,并帮助您在创建项目时自定义项目。
-
创建项目后,您可以构建和运行应用程序。
-
您不必使用模板来创建项目,但在大多数情况下,使用项目模板更有效。
-
修改提供的项目文件和结构比从头创建它们更容易。
在 MFC 中,您可以使用以下项目模板。
Sr.No. | 项目模板和描述 |
---|---|
1 |
MFC Application MFC 应用程序是基于 Microsoft 基础类 (MFC) 库的 Windows 可执行应用程序。创建 MFC 应用程序的最简单方法是使用 MFC 应用程序向导。 |
2 |
MFC ActiveX Control ActiveX 控制程序是模块化程序,旨在为父应用程序提供特定类型的功能。例如,您可以创建一个控件,例如在对话框、工具栏或网页上使用的按钮。 |
3 |
MFC DLL MFC DLL 是一个二进制文件,它充当可以由多个应用程序同时使用的共享函数库。创建 MFC DLL 项目的最简单方法是使用 MFC DLL 向导。 |
以下是一些通用模板,也可用于创建 MFC 应用程序 –
Sr.No. | 项目模板和描述 |
---|---|
1 |
Empty Project 项目是构建应用程序所需的一切的逻辑容器。然后,如有必要,您可以向解决方案添加更多新项目或现有项目。 |
2 |
Custom Wizard Visual C++ 自定义向导是在您需要创建新的自定义向导时使用的工具。创建自定义向导的最简单方法是使用自定义向导。 |
MFC – 入门
在本章中,我们将看一个有效的 MFC 示例。要创建 MFC 应用程序,您可以使用向导来自定义您的项目。您还可以从头开始创建应用程序。
使用项目模板创建项目
以下是使用 Visual Studio 中可用的项目模板创建项目的步骤。
步骤 1 – 打开 Visual Studio,然后单击文件 → 新建 → 项目菜单选项。
第 2 步– 您现在可以看到“新建项目”对话框已打开。
步骤 3 – 从左窗格中,选择模板 → Visual C++ → MFC
步骤 4 – 在中间窗格中,选择 MFC 应用程序。
第 5 步– 在“名称”字段中输入项目名称“MFCDemo”,然后单击“确定”继续。您将看到以下对话框。
步骤 6 – 单击下一步。
步骤 7 – 选择上面给出的对话框中显示的选项,然后单击下一步。
步骤 8 – 取消选中所有选项并单击完成按钮。
您现在可以看到 MFC 向导默认创建了这个对话框和项目文件。
步骤 9 – 运行此应用程序,您将看到以下输出。
从头开始创建项目
您还可以从头开始创建 MFC 应用程序。要创建 MFC 应用程序,您需要按照以下步骤操作。
步骤 1 – 打开 Visual Studio,然后单击文件 → 新建 → 项目菜单选项。
第 2 步– 您现在可以看到“新建项目”对话框。
步骤 3 – 从左侧窗格中,选择模板 → Visual C++ → 常规。
步骤 4 – 在中间窗格中,选择 Empty
步骤 5 – 在名称字段中输入项目名称“MFCDemoFromScratch”,然后单击“确定”继续。您将看到创建了一个空项目。
步骤 6 – 要使其成为 MFC 项目,请右键单击该项目并选择“属性”。
步骤 7 – 在左侧部分,单击配置属性 → 常规。
步骤 8 – 在“项目默认值”部分中选择“在共享 DLL 中使用 MFC”选项,然后单击“确定”。
步骤 9 – 因为它现在是一个空项目;我们需要添加一个 C++ 文件。因此,右键单击该项目并选择 Add → New Item…
步骤 10 –在中间窗格中选择C++ 文件 (.cpp)并在名称字段中输入文件名,然后单击添加按钮。
步骤 11 – 您现在可以看到在 Source Files 文件夹下添加的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 步– 您现在可以看到“新建项目”对话框。
步骤 3 – 从左窗格中,选择模板 → Visual C++ → Win32。
步骤 4 – 在中间窗格中,选择 Win32 项目。
第 5 步– 在“名称”字段中输入项目名称“MFCWindowDemo”,然后单击“确定”继续。您将看到以下对话框。
步骤 6 – 单击下一步。
步骤 7 – 选择上面给出的对话框中显示的选项,然后单击完成。
步骤 8 – 创建一个空项目。
步骤 9 – 要使其成为 MFC 项目,请右键单击该项目并选择“属性”。
步骤 10 – 在左侧部分,单击配置属性 → 常规。
步骤 11 – 在“项目默认值”部分中选择“在共享 DLL 中使用 MFC”选项,然后单击“确定”。
步骤 12 – 添加一个新的源文件。
步骤 13 – 右键单击您的项目并选择添加 → 新项目…
步骤 14 – 在模板部分,单击 C++ 文件 (.cpp)。
步骤 15 – 将名称设置为示例,然后单击添加。
窗口创建
任何应用程序都有两个主要部分 –
- 班级
- 框架或窗口
让我们使用以下步骤创建一个窗口 –
步骤 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 步– 当我们运行上述应用程序时,将创建以下窗口。
窗户样式
窗口样式是控制窗口外观、边框、最小化或最大化状态或其他调整大小状态等功能的特性。
Sr.No. | 风格和描述 |
---|---|
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 – 当您运行此应用程序时,将创建以下窗口。
您现在可以看到最小化、最大化和关闭选项不再出现。
窗口位置
为了定位显示器上显示的东西,计算机使用类似于笛卡尔坐标系的坐标系,但原点位于屏幕的左上角。使用这个坐标系,任何点都可以通过它与屏幕左上角的水平轴和垂直轴的距离来定位。
所述的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 构造函数中指定的那样。最后两个参数是窗口的大小。
视窗父母
在现实世界中,许多应用程序是由不同的 Windows 组成的。当应用程序使用各种 Windows 时,大多数对象都依赖于特定的对象。它可能是创建的第一个窗口或您指定的另一个窗口。这样的窗口被称为父窗口。所有其他窗口直接或间接依赖于它。
-
如果您创建的窗口依赖于另一个窗口,您可以指定它有一个父窗口。
-
这是通过 CFrameWnd::Create() 方法的 pParentWnd 参数完成的。
-
如果 Window 没有父级,则使用 NULL 值传递参数。
让我们看一个只有一个 Window 的示例,并且没有可用的父 Window,因此我们将使用 NULL 值传递参数,如下面的代码所示 –
class CMyFrame : public CFrameWnd { public: CMyFrame() { Create(NULL, _T("MFC Application Tutorial"), WS_SYSMENU, CRect(90, 120, 550, 480), NULL); } };
当您运行上述应用程序时,您会看到相同的输出。
MFC – 对话框
在本章中,我们将介绍对话框。Windows 应用程序经常通过对话框与用户通信。CDialog 类提供了管理对话框的接口。Visual C++ 对话框编辑器使设计对话框和创建对话框模板资源变得容易。
-
创建对话框对象是一个两阶段的操作 –
-
构造对话框对象。
-
创建对话窗口。
-
让我们通过创建一个新的 Win32 项目来查看一个简单的示例。
步骤 1 – 打开 Visual Studio,然后单击文件 → 新建 → 项目菜单选项。
第 2 步– 您现在可以看到“新建项目”对话框。
步骤 3 – 从左窗格中,选择模板 → Visual C++ → Win32。
步骤 4 – 在中间窗格中,选择 Win32 项目。
步骤 5 – 在名称字段中输入项目名称“MFCDialogDemo”,然后单击“确定”继续。您将看到以下对话框。
步骤 6 – 单击下一步。
步骤 7 – 选择上面给出的对话框中显示的选项,然后单击完成。
步骤 8 – 创建一个空项目。
步骤 9 – 要使其成为 MFC 项目,请右键单击该项目并选择“属性”。
步骤 10 – 在左侧部分,单击配置属性 → 常规。
步骤 11 – 在“项目默认值”部分中选择“在共享 DLL 中使用 MFC”选项,然后单击“确定”。
步骤 12 – 添加一个新的源文件。
步骤 13 – 右键单击您的项目并选择添加 → 新项目。
步骤 14 – 在模板部分,单击 C++ 文件 (.cpp)
步骤 15 – 将名称设置为示例,然后单击添加。
步骤 16 – 要创建应用程序,我们需要添加一个类并从 MFC 的 CWinApp 派生它。
#include <afxwin.h> class CExample : public CWinApp { public: BOOL InitInstance(); };
对话框创建
步骤 1 – 要创建对话框,请右键单击解决方案资源管理器中的资源文件文件夹,然后选择添加 → 资源。
步骤 2 – 在添加资源对话框中,选择对话框并单击新建。
步骤 3 – 在实际以编程方式创建对话框之前,需要一些准备工作。
步骤 4 – 首先可以手动创建一个对话框作为文本文件(在资源文件中)。
步骤 5 – 您现在可以看到在资源文件下创建的 MFCDialogDemo.rc 文件。
步骤 6 – 资源文件在设计器中打开。同样可以作为文本文件打开。右键单击资源文件并选择打开方式。
步骤 7 – 选择源代码(文本)编辑器并单击添加按钮。
步骤 8 – 返回设计器并右键单击对话框并选择属性。
步骤 9 – 您需要从众多选项中进行选择。
步骤 10 – 与大多数其他控件一样,必须标识一个对话框。对话框的标识符(ID)通常以 IDD_ 开头,我们将 ID 更改为 IDD_EXAMPLE_DLG。
对话框位置
对话框必须“物理地”位于应用程序上。因为对话框通常是作为其他控件的父级创建的,所以它的位置取决于它与其父窗口或桌面的关系。
如果您查看“属性”窗口,您会看到两个字段,X Pos 和 Y Pos。
-
X 是显示器左边框到对话框左边框的距离。
-
Y 是显示器上边框到对话框上边框的距离。
默认情况下,这些字段设置为零。您也可以如上所示进行更改。
如果您将这两个尺寸指定为 0,则对话框的左边框和上边框将被设置为使对象出现在屏幕的中间。
对话框尺寸
对话框的尺寸是指其宽度和高度。您可以在设计器窗口中借助鼠标调整宽度和高度。
您可以在状态栏上看到宽度和高度的变化。
对话框方法
用于在屏幕上显示对话框的基类是 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; }
模态对话框
有两种类型的对话框 – modeless和modal。模态对话框和非模态对话框的不同之处在于用于创建和显示它们的过程。
无模式对话框
-
对于无模式对话框,您必须在对话框类中提供自己的公共构造函数。
-
要创建无模式对话框,请调用公共构造函数,然后调用对话框对象的 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;
Step 3 – 编译并执行上述代码后,您将看到以下对话框。
基于对话框的应用程序
Microsoft Visual Studio 提供了一种更简单的方法来创建主要基于对话框的应用程序。以下是使用 Visual Studio 中可用的项目模板创建对话框基础项目的步骤 –
步骤 1 – 打开 Visual Studio,然后单击文件 → 新建 → 项目菜单选项。您可以看到“新建项目”对话框。
步骤 2 – 从左窗格中,选择模板 → Visual C++ → MFC。
步骤 3 – 在中间窗格中,选择 MFC 应用程序。
第 4 步– 在名称字段中输入项目名称“MFCModalDemo”,然后单击“确定”继续。您将看到以下对话框。
步骤 5 – 单击下一步。
步骤 6 – 选择上面对话框中显示的选项,然后单击下一步。
步骤 7 – 检查您在对话框中选择的所有选项,例如最大化和最小化框,然后单击下一步。
步骤 8 – 单击下一步。
步骤 9 – 它将生成这两个类。您可以更改类的名称,然后单击完成。
步骤 10 – 您现在可以看到 MFC 向导默认创建此对话框和项目文件。
步骤 11 – 当您运行此应用程序时,您将看到以下输出。
MFC – Windows 资源
一个资源是一个文本文件,可以让编译器来管理对象,如图片,声音,鼠标光标,对话框等微软的Visual Studio可以通过使用程序的同一环境中提供必要的工具创建一个资源文件特别容易。这意味着,您通常不必使用外部应用程序来创建或配置资源文件。以下是与资源相关的一些重要功能。
-
资源是向用户提供信息的界面元素。
-
位图、图标、工具栏和光标都是资源。
-
可以操纵某些资源来执行操作,例如从菜单中选择或在对话框中输入数据。
-
应用程序可以使用彼此独立运行的各种资源,这些资源被分组到具有 *.rc 扩展名的文本文件中。
-
大多数资源是通过从“添加资源”对话框中选择所需的资源来创建的。
-
“添加资源”对话框提供了可根据要求使用的大量资源列表,但如果您需要一些不可用的资源,则可以在执行程序之前将其手动添加到 *.rc 文件中。
身份标识
一个标识符是一个符号,其是恒定的整数,其名称通常与ID开始。它由两部分组成 – 映射到整数值(符号值)的文本字符串(符号名称)。
-
符号提供了一种在源代码中以及在资源编辑器中使用它们时引用资源和用户界面对象的描述方式。
-
创建新资源或资源对象时,资源编辑器会为资源提供一个默认名称,例如 IDC_DIALOG1,并为其分配一个值。
-
名称加值定义存储在 Resource.h 文件中。
步骤 1 – 让我们看看上一章中的 CMFCDialogDemo示例,在该示例中我们创建了一个对话框,其 ID 为IDD_EXAMPLE_DLG。
步骤 2 – 转到解决方案资源管理器,您将在头文件下看到 resource.h 文件。继续在编辑器中打开此文件,您将看到对话框标识符及其整数值。
图标
一个图标是代表应用的窗口上使用的小图片。它用于两个主要场景。
-
在窗口的框架上,它显示在标题栏窗口名称的左侧。
-
在 Windows 资源管理器、桌面、我的电脑或控制面板窗口中。
如果您查看我们的 MFCModalDemo 示例,您将看到 Visual Studio 使用默认图标作为标题栏,如下面的快照所示。
您可以按照以下步骤创建自己的图标 –
步骤 1 – 右键单击您的项目并选择添加 → 资源,您将看到添加资源对话框。
步骤 2 – 选择图标并单击新建按钮,您将看到以下图标。
步骤 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 – 编译并执行上述代码后,您将看到新图标显示在对话框中。
菜单
菜单允许您以合乎逻辑且易于查找的方式排列命令。使用菜单编辑器,您可以通过直接使用与完成的应用程序中的菜单栏非常相似的菜单栏来创建和编辑菜单。要创建菜单,请按照以下步骤操作 –
步骤 1 – 右键单击您的项目并选择添加 → 资源。您将看到“添加资源”对话框。
步骤 2 – 选择菜单并单击新建。您将在菜单栏上看到包含“在此处键入”的矩形。
步骤 3 – 编写一些菜单选项,如文件、编辑等,如下面的快照所示。
步骤 4 – 如果您在资源视图中展开菜单文件夹,您将看到菜单标识符 IDR_MENU1。右键单击此标识符并将其更改为 IDM_MAINMENU。
步骤 5 – 保存所有更改。
第 6 步– 我们需要将此菜单附加到我们的对话框中。在解决方案资源管理器中展开您的 Dialog 文件夹并双击对话框标识符。
步骤 7 – 您将在“属性”中看到菜单字段。从下拉菜单中选择菜单标识符,如上所示。
步骤 8 – 运行此应用程序,您将看到以下对话框,其中还包含菜单选项。
工具栏
一个工具栏是一个Windows控件,它允许用户通过点击一个按钮,而不是使用菜单执行窗体上的一些行动。
-
工具栏提供了一组方便的按钮,通过将最容易访问的操作作为按钮来简化用户的工作。
-
工具栏可以使此类常见操作更接近用户。
-
工具栏通常显示在主菜单下。
-
他们可以配备按钮,但有时他们的按钮或他们的一些按钮有一个标题。
-
工具栏还可以配备其他类型的控件。
要创建工具栏,请执行以下步骤。
步骤 1 – 右键单击您的项目并选择添加 → 资源。您将看到“添加资源”对话框。
步骤 2 – 选择工具栏并单击新建。您将看到以下屏幕。
第 3 步– 在设计器中设计您的工具栏,如下面的屏幕截图所示,并指定 ID。
步骤 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 – 运行此应用程序。您将看到以下对话框,其中也包含工具栏。
加速器
一个访问键是一个字母,它允许用户通过使用键盘代替鼠标进行菜单操作速度更快。这通常更快,因为用户不需要将鼠标放在任何地方,这减少了执行操作所需的时间。
步骤 1 – 要创建访问键,请在菜单项的左侧键入与号“&”。
步骤 2 – 对所有菜单选项重复此步骤。运行此应用程序并按 Alt。您将看到所有菜单选项的第一个字母都带有下划线。
快捷键
快捷键是高级用户用来执行本来会在菜单项上完成的操作的一个键或一组键。大多数快捷键是同时按下 Ctrl 键和字母键的组合。例如,Ctrl + N、Ctrl + O 或 Ctrl + D。
要创建快捷方式,请在构成菜单标题的字符串的右侧,右键单击菜单项并选择属性。
在标题字段中键入 \t 后跟所需的组合,如下所示的新建菜单选项。对所有菜单选项重复该步骤。
加速器表
Accelerator Table 是一个项目列表,其中表的每个项目都组合了一个标识符、一个快捷键和一个指定加速键类型的常数。就像其他资源一样,可以在 .rc 文件中手动创建加速器表。以下是创建加速器表的步骤。
步骤 1 – 要创建加速器表,请右键单击解决方案资源管理器中的 *.rc 文件。
步骤 2 – 选择加速器并单击新建。
步骤 3 – 单击 ID 组合框的箭头并选择菜单项。
步骤 4 – 从修饰符下拉列表中选择 Ctrl。
步骤 5 – 单击“密钥”框并为两个菜单选项键入相应的密钥。
我们还将向测试添加新菜单项事件处理程序。右键单击新建菜单选项。
步骤 6 – 您可以指定类、消息类型和处理程序名称。现在,让我们保持原样,然后单击“添加和编辑”按钮。
步骤 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 – 编译并执行上述代码后,您将看到以下输出。
步骤 13 – 按 Alt 按钮,然后按 F 键,然后按 N 键或 Ctrl + N。您将看到以下消息。
MFC – 属性表
一个属性表,也被称为标签对话框中,是包含属性页的对话框。每个属性页都基于一个对话框模板资源并包含控件。它附在一个页面上,顶部有一个选项卡。该选项卡命名页面并指明其用途。用户单击属性表中的选项卡以选择一组控件。
要创建属性页,让我们通过创建一个基于对话框的 MFC 项目来查看一个简单的示例。
创建项目后,我们需要添加一些属性页。
通过显示“添加资源”对话框、展开“对话框”节点并选择 IDD_PROPPAGE_X 项之一,Visual Studio 可以轻松地为属性页创建资源。
步骤 1 – 在解决方案资源管理器中右键单击您的项目,然后选择添加 → 资源。
步骤 2 – 选择 IDD_PROPPAGE_LARGE 并单击新建。
第 3 步– 让我们将此属性页的 ID 和标题分别更改为IDD_PROPPAGE_1和属性页 1,如上所示。
步骤 4 – 右键单击设计器窗口中的属性页。
步骤 5 – 选择添加类选项。
步骤 6 – 输入类名并从基类下拉列表中选择 CPropertyPage。
步骤 7 – 单击完成继续。
步骤 8 – 按照上述步骤添加一个带有 ID IDD_PROPPAGE_2 和标题属性页面 2 的属性页面。
步骤 9 – 您现在可以看到创建的两个属性页面。为了实现它的功能,我们需要一个属性表。
属性表将属性页组合在一起并将其保留为实体。
要创建属性表,请按照以下步骤操作 –
步骤 1 – 右键单击您的项目并选择添加 > 类菜单选项。
步骤 2 – 从左窗格中选择 Visual C++ → MFC,在模板窗格中选择 MFC 类,然后单击添加。
步骤 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; }
Step 9 – 编译并执行上述代码后,您将看到以下对话框。此对话框包含两个属性页。
MFC – 窗口布局
控件的布局对于应用程序的可用性非常重要和关键。它用于在您的应用程序中排列一组 GUI 元素。选择布局时需要考虑一些重要的事情 –
- 子元素的位置。
- 子元素的大小。
添加控件
让我们创建新的基于对话框的 MFC 项目 MFCLayoutDemo。
步骤 1 – 创建项目后,您将看到以下屏幕。
步骤 2 – 从对话框中删除 TODO。
步骤 3 – 从工具箱中拖动一些控件,您可以在左侧看到这些控件。
(我们将拖动一个静态文本和一个编辑控件,如下面的快照所示)。
步骤 4 – 将静态文本的标题更改为名称。
控制网格
控件网格是引导网格点,它可以帮助定位您在设计时添加的控件。
要启用控制网格,您需要单击工具栏中的切换网格按钮,如下面的快照所示。
控制调整大小
将控件添加到对话框后,它会采用默认大小或绘制时使用的大小。为了帮助调整窗体或对话框上控件的大小,Visual Studio 提供了一个由黑点组成的可视网格。
要调整控件的大小,即为其指定特定的宽度或高度,请将鼠标放在其中一个手柄上并沿所需方向拖动。
您现在可以借助此虚线网格调整控件的大小。
控制位置
您在对话框或表单上放置的控件占据它们给定的位置。大多数时候,这些职位并不实用。您可以将它们移动到您选择的任何位置。
让我们添加更多控件 –
步骤 1 – 要移动控件,请单击并沿所需方向拖动它,直到它到达预期位置。
步骤 2 – 要移动一组控件,首先选择它们。然后将选择拖动到所需位置。让我们选择静态文本和编辑控件。
步骤 3 – 将这些选定的控件移动到左侧。
为了帮助定位控件,Visual Studio 提供了带有以下按钮的对话框工具栏。
步骤 1 – 让我们通过选择所有这些控件将复选框和静态文本控件向左对齐。
步骤 2 – 选择格式 → 对齐 → 左边。
第 3 步– 您现在可以看到所有这些控件都向左对齐。
标签排序
添加到窗体或对话框中的控件按添加顺序排列。当您添加控件时,无论您放置新控件的部分或区域如何,它都会按顺序放置在现有控件的末尾。如果您不修复它,用户将很难导航控件。控件导航的顺序也称为 Tab 键顺序。
要更改选项卡,您可以使用格式 → 选项卡顺序菜单选项,也可以使用 Ctrl + D 快捷方式。让我们按 Ctrl + D。
您现在可以看到所有这些控件添加到此对话框的顺序。要更改控件的顺序或顺序,请按要导航的顺序单击所有控件。
在此示例中,我们将首先单击复选框,然后单击名称和地址编辑控件。然后单击确定和取消,如下面的快照所示。
让我们运行此应用程序,您将看到以下输出。
MFC – 控制管理
在 MFC 应用程序中,在将控件可视化地添加到应用程序后,如果您想在代码中引用它,您可以声明一个基于该控件或与该控件关联的变量。MFC 库允许您为应用程序中使用的某些控件声明两种类型的变量,即值或控件变量。
-
一个变量用于存储在控件中的信息,也称为Control Variable/Instance。
-
另一个变量称为控制值变量。用户可以使用此变量对该控件执行某种操作。
控制变量/实例
控制变量是基于管理控件的类的变量。例如,按钮控件基于 CButton 类。
为了在实际编程中看到这些概念,让我们创建一个基于 MFC 对话框的项目 MFCControlManagement。
创建项目后,您将在设计器窗口中看到以下对话框。
步骤 1 – 删除 TODO 行并拖动一个复选框和一个编辑控件,如下面的快照所示。将复选框的标题更改为启用控制。
步骤 2 – 右键单击复选框。
步骤 3 – 选择添加变量。
第 4 步– 您现在可以看到添加成员变量向导。
您可以在此对话框中选择不同的选项。对于复选框,变量类型是 CButton。在此对话框中默认选中它。
同样,控件ID也是默认选中的,现在我们需要在Category组合框中选择Control,在Variable Name编辑框中输入m_enableDisableCheck,点击finish。
步骤 5 – 同样,添加编辑控件的控制变量,其设置如下面的快照所示。
观察对话框类的头文件。您可以看到现在已经添加了新变量。
CButton m_enableDisableCheck; CEdit m_myEditControl;
控制值变量
您可以为控件声明的另一种类型的变量是值变量。并非所有控件都提供值变量。
-
值变量必须能够处理存储在它要引用的控件中的值的类型。
-
例如,因为基于文本的控件用于处理文本,您可以为其声明基于文本的数据类型。这通常是一个 CString 变量。
让我们看看复选框和编辑控件的这种类型的变量。
步骤 1 – 右键单击复选框并选择添加变量。
步骤 2 – 变量类型是 BOOL。从类别下拉列表中选择值。
步骤 3 – 单击完成继续。
步骤 4 – 同样,使用以下快照所示的设置为编辑控件添加值变量。
第 5 步– 在变量类型中键入 CString,在变量名字段中键入 m_editControlVal。
步骤 6 – 您现在可以在头文件中看到这些变量。
bool m_enableDisableVal; CString m_editControlVal;
控制事件处理程序
将控件添加到应用程序后,无论是直观地添加它还是动态创建它,您还将决定如何处理用户可以在控件上执行的可能操作。
-
对于已经与类关联的项目对话框,您可以在创建事件处理程序时利用一些快捷方式。
-
您可以为默认控件通知事件或任何适用的 Windows 消息快速创建处理程序。
让我们看一下为复选框添加事件处理程序的相同示例。
步骤 1 – 右键单击要处理通知事件的控件。
步骤 2 – 在快捷菜单上,单击添加事件处理程序以显示事件处理程序向导。
步骤 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()→ 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); }
Step 5 – 编译并执行上述代码后,您将看到以下输出。默认情况下未选中该复选框。这也会禁用编辑控件。
步骤 6 – 检查启用控制复选框。这将自动启用编辑控件。
MFC – Windows 控制
Windows 控件是用户可以与之交互以输入或操作数据的对象。它们通常出现在对话框或工具栏上。有各种类型的控件 –
-
阿基于文本控制其被用于显示文本到来自用户的用户或请求的文本。
-
一个清单为基础的控制显示项目的清单。
-
一个基于进度控制是用来显示行动的进展情况。
-
一个静态控制,可以用来显示色彩,画面或一些不适合经常在上述类别。
Sr.No. | 控制和描述 |
---|---|
1 | Static Control
静态控件是一种无需用户直接干预即可向用户显示信息的对象。它可用于显示颜色、几何形状或图片,例如图标、位图或动画。 |
2 | Animation Control
动画控件是一个以 AVI 格式显示音频剪辑的窗口。AVI 剪辑是一系列位图帧,就像电影一样。动画控件只能播放简单的 AVI 片段,不支持声音。它由CAnimateCtrl类表示。 |
3 | Button
甲按钮是用户点击发起动作的对象。按钮控件由CButton 类表示。 |
4 | Bitmap Button
甲图按钮显示画面或在其表面上的图象和文本。这通常是为了使按钮更加明确。位图按钮是使用从 CButton 派生的CBitmapButton 类创建的。 |
5 | Command Button
甲命令按钮是常规按钮的增强版本。它在左侧显示一个绿色箭头图标,后跟常规大小的标题。在主标题下,它可以显示另一个较小的标题,作为提供更多信息的提示。 |
6 | Static Text
甲静态控制显示文本串,框,矩形,图标,光标,位图或增强型图元。它由CStatic 类表示。它可用于标记、装箱或分隔其他控件。静态控制通常不接受输入也不提供输出。 |
7 | List Box
甲列表框显示的项目,如文件名的列表,使得用户可以查看和选择。列表框由CListBox 类表示。在单选列表框中,用户只能选择一项。在多选列表框中,可以选择一系列项目。当用户选择一个项目时,它会突出显示,并且列表框会向父窗口发送通知消息。 |
8 | Combo Boxes
一个组合框由一个列表框一个静态控件或编辑控件相结合的。它由CComboBox 类表示。控件的列表框部分可以一直显示,也可以仅在用户选择控件旁边的下拉箭头时才下拉。 |
9 | Radio Buttons
甲单选按钮是作为点由圆框包围的显示的控制。实际上,一个单选按钮伴随着一个或多个其他单选按钮,它们作为一个组出现和运行。 |
10 | Checkboxes
复选框是一个 Windows 控件,允许用户将项目的值设置或更改为 true 或 false。 |
11 | Image Lists
一个图像列表是相同大小的图像,其中的每一个可以通过其基于零的索引被称为的集合。图像列表用于有效管理大量图标或位图。图像列表由CImageList 类表示。 |
12 | Edit Box
一个编辑框是一个长方形的子窗口中,用户可以输入文本。它由CEdit 类表示。 |
13 | Rich Edit
一个丰富的编辑控件是用户可以输入和编辑文本的窗口。文本可以指定字符和段落格式,并且可以包括嵌入的 OLE 对象。它由CRichEditCtrl 类表示。 |
14 | Group Box
甲组框是用于设定的控制的可见或程序组的静态控制。该控件是一个将其他控件组合在一起的矩形。 |
15 | Spin Button
甲微调按钮控制(也称为上下控制)是一对箭头按钮,用户可以点击以递增或递减的值,诸如滚动位置或显示在一个配对控制一个数字。它由CSpinButtonCtrl 类表示。 |
16 | Managing the Updown Control
它管理上下控制。 |
17 | Progress Control
甲进度条控制是,一个应用程序可以使用以指示冗长的操作的进度的窗口。它由一个从左到右逐渐填充的矩形组成,随着操作的进行,系统会突出显示颜色。它由CProgressCtrl 类表示。 |
18 | Progress Bars
一个进度条是一个应用程序可以使用指示操作的进度的窗口。 |
19 | Timer
甲计时器是使用重复的时间流逝从计算机或fromyour应用非空间对象。为了工作,每隔一段时间,控件就会向操作系统发送一条消息。与大多数其他控件不同,MFC 计时器既没有代表它的按钮,也没有一个类。要创建计时器,您只需调用 CWnd::SetTimer() 方法。此函数调用为您的应用程序创建一个计时器。与其他控件一样,计时器使用标识符。 |
20 | Date & Time Picker
日期和时间选择器控件 ( CDateTimeCtrl ) 实现了一种直观且可识别的输入或选择特定日期的方法。该控件的主界面在功能上类似于组合框。但是,如果用户展开控件,则会出现一个月历控件(默认情况下),允许用户指定特定日期。选择日期后,月历控件会自动消失。 |
21 | Picture
如果您需要为您的应用程序显示图片,Visual C++ 为该目的提供了一个特殊的控件。 |
22 | Image Editor
该图像编辑器拥有一套广泛的用于创建和编辑图像的工具,wellas功能,以帮助您创建工具栏位图。除了位图、图标和光标,您还可以使用图像菜单上的命令和图像编辑器工具栏上的工具编辑 GIF 或 JPEG 格式的图像。 |
23 | Slider Controls
甲滑块控制(也被称为跟踪条)是含有一个滑块和可选的刻度标记的窗。当用户使用鼠标或方向键移动滑块时,控件会发送通知消息以指示更改。有两种类型的滑块 – 水平和垂直。它由CSliderCtrl 类表示。 |
24 | Scrollbars
甲滚动条是与连续的文本,图片或其他任何能够在沿着控制两个方向通过点击箭头滚动的图形控制元素。此控件可以采用两个方向之一 – 水平或垂直。它由CScrollBar类表示。 |
25 | Tree Control
一个树视图控件是一个窗口,显示的项目,如文档中的标题,在索引中的条目,或磁盘上的文件和目录的层次列表。每个项目由一个标签和一个可选的位图图像组成,每个项目都可以有一个与其关联的子项目列表。通过单击一个项目,用户可以展开和折叠相关的子项目列表。它由CTreeCtrl类表示。 |
26 | List Control
封装了一个列表视图控件的功能,它显示一个项目的集合,每个项目由一个图标(来自一个图像列表)和一个标签组成。它由CListCtrl类表示。列表控件包括使用四个视图之一来显示项目列表。 |
MFC – 消息和事件
应用程序由各种对象组成。大多数情况下,计算机上运行着不止一个应用程序,并且不断要求操作系统执行一些任务。因为可能有如此多的请求不可预测地呈现,操作系统将它留给对象来指定他们想要什么、他们想要什么时候以及他们期望什么行为或结果。
概述
-
Microsoft Windows 操作系统无法预测一个对象需要处理什么类型的请求以及另一个对象需要什么类型的分配。
-
为了管理所有这些分配和请求,对象发送消息。
-
每个对象都有责任决定发送什么消息以及何时发送。
-
为了发送消息,控件必须创建一个事件。
-
为了区分两者,消息的名称通常以 WM_ 开头,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 项目来查看一个简单的示例。
步骤 1 – 要创建 MFC 项目,请右键单击该项目并选择“属性”。
步骤 2 – 在左侧部分,单击配置属性 → 常规。
步骤 3 – 在“项目默认值”部分中选择“在共享 DLL 中使用 MFC”选项,然后单击“确定”。
第 4 步– 我们需要添加一个新的源文件。
第 5 步– 右键单击您的项目并选择添加 → 新项目。
步骤 6 – 在模板部分,单击 C++ 文件 (.cpp)。
步骤 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 消息。
让我们看一个简单的窗口创建示例。
WM_CREATE – 当创建一个称为窗口的对象时,创建对象的框架会发送一条标识为ON_WM_CREATE的消息。
步骤 1 – 要创建 ON_WM_CREATE,添加 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); 在 DECLARE_MESSAGE_MAP() 之前,如下所示。
class CMainFrame : public CFrameWnd { public: CMainFrame(); protected: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); DECLARE_MESSAGE_MAP() };
第 2 步– 在 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) 之后和 END_MESSAGE_MAP() 之前添加 ON_WM_CREATE()
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP()
第 3 步– 这是 OnCreate() 的实现
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { // Call the base class to create the window if (CFrameWnd::OnCreate(lpCreateStruct) == 0) { // If the window was successfully created, let the user know MessageBox(L"The window has been created!!!"); // Since the window was successfully created, return 0 return 0; } // Otherwise, return -1 return -1; }
第 4 步– 现在您的 *.cpp 文件将如下面的代码所示。
#include <afxwin.h> class CMainFrame : public CFrameWnd { public: CMainFrame(); protected: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); DECLARE_MESSAGE_MAP() }; CMainFrame::CMainFrame() { // Create the window's frame Create(NULL, L"MFC Messages Demo", WS_OVERLAPPEDWINDOW, CRect(120, 100, 700, 480), NULL); } class CMessagesApp : public CWinApp { public: BOOL InitInstance(); }; BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP() int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { // Call the base class to create the window if (CFrameWnd::OnCreate(lpCreateStruct) == 0) { // If the window was successfully created, let the user know MessageBox(L"The window has been created!!!"); // Since the window was successfully created, return 0 return 0; } // Otherwise, return -1 return -1; } BOOL CMessagesApp::InitInstance() { m_pMainWnd = new CMainFrame; m_pMainWnd -> ShowWindow(SW_SHOW); m_pMainWnd -> UpdateWindow(); return TRUE; } CMessagesApp theApp;
Step 5 – 编译并执行上述代码后,您将看到以下输出。
步骤 6 – 当您单击确定时,它将显示主窗口。
命令信息
图形应用程序的主要功能之一是提供允许用户与机器交互的 Windows 控件和资源。我们将学习的控件示例有按钮、列表框、组合框等。
我们在上一课中介绍的一种资源是菜单。当用户点击它们时,这些控件和资源可以启动它们自己的消息。从 Windows 控件或资源发出的消息称为命令消息。
让我们看一个简单的命令消息示例。
为了让您的应用程序能够创建新文档,CWinApp 类提供了 OnFileNew() 方法。
afx_msg void OnFileNew(); BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_COMMAND(ID_FILE_NEW, CMainFrame::OnFileNew) END_MESSAGE_MAP()
这是方法定义 –
void CMainFrame::OnFileNew() { // Create New file }
键盘信息
甲键盘是连接到计算机硬件对象。默认情况下,它用于在控件上输入可识别的符号、字母和其他字符。键盘上的每个键都显示一个符号、一个字母或它们的组合,以指示该键的用途。用户通常按下一个键,该键向程序发送信号。
每个键都有一个操作系统可以识别的代码。此代码称为虚拟键代码。
按下一个键会导致WM_KEYDOWN或WM_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"); } }
Step 3 – 编译并执行上述代码后,您将看到以下输出。
步骤 4 – 当您按 Enter 时,它将显示以下消息。
鼠标消息
鼠标是连接到计算机的另一个对象,允许用户与机器进行交互。
-
如果按下鼠标左键,则发送 ON_WM_LBUTTONDOWN 消息。此消息的语法是 –
-
afx_msg void OnLButtonDown(UINT nFlags, CPoint point)
-
-
如果按下鼠标右键,则会发送 ON_WM_RBUTTONDOWN 消息。它的语法是 –
-
afx_msg void OnRButtonDown(UINT nFlags, CPoint point)
-
-
类似地,如果正在释放鼠标左键,则发送 ON_WM_LBUTTONUP 消息。它的语法是 –
-
afx_msg void OnLButtonUp(UINT nFlags, CPoint point)
-
-
如果正在释放鼠标右键,则发送 ON_WM_TBUTTONUP 消息。它的语法是 –
-
afx_msg void OnRButtonUp(UINT nFlags, CPoint point)
-
让我们看一个简单的例子。
Step 1 – 在 CMainFrame 类定义中添加以下两个函数,如下面的代码所示。
class CMainFrame : public CFrameWnd { public: CMainFrame(); protected: afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnRButtonUp(UINT nFlags, CPoint point); DECLARE_MESSAGE_MAP() };
步骤 2 – 添加以下两个消息映射。
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_KEYDOWN() ON_WM_LBUTTONDOWN() ON_WM_RBUTTONUP() END_MESSAGE_MAP()
第 3 步– 这是函数定义。
void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point) { CString MsgCoord; MsgCoord.Format(L"Left Button at P(%d, %d)", point.x, point.y); MessageBox(MsgCoord); } void CMainFrame::OnRButtonUp(UINT nFlags, CPoint point) { MessageBox(L"Right Mouse Button Up"); }
第 4 步– 当您运行此应用程序时,您将看到以下输出。
步骤 5 – 单击确定后,您将看到以下消息。
步骤 6 – 右键单击此窗口。现在,当您松开鼠标右键时,它将显示以下消息。
MFC – Activex 控件
的ActiveX控件容器是一个父程序用品为ActiveX(以前OLE)控制的环境下运行。
-
ActiveX 控件是使用 Microsoft ActiveX 技术的控件。
-
ActiveX 不是一种编程语言,而是一套关于应用程序如何共享信息的规则。
-
程序员可以使用多种语言开发 ActiveX 控件,包括 C、C++、Visual Basic 和 Java。
-
您可以使用或不使用 MFC 创建一个能够包含 ActiveX 控件的应用程序,但使用 MFC 更容易。
让我们看看在基于 MFC 对话框的应用程序中添加 ActiveX 控件的简单示例。
步骤 1 – 右键单击设计器窗口中的对话框并选择插入 ActiveX 控件。
步骤 2 – 选择 Microsoft Picture Clip Control,然后单击确定。
步骤 3 – 调整图片控件的大小,然后在属性窗口中,单击图片字段。
步骤 4 – 浏览包含图片的文件夹。选择任何图片。
第 5 步– 当您运行此应用程序时,您将看到以下输出。
让我们看看另一个简单的例子。
步骤 1 – 右键单击设计器窗口中的对话框。
步骤 2 – 选择插入 ActiveX 控件。
步骤 3 – 选择 Microsoft ProgressBar Control 6.0,单击确定。
步骤 4 – 选择进度条并将其在属性窗口中的方向设置为1 – ccOrientationVertical。
步骤 5 – 为进度条添加控制变量。
第 6 步– 在 OnInitDialog() 中添加以下代码
m_progBarCtrl.SetScrollRange(0,100,TRUE); m_progBarCtrl.put_Value(53);
步骤 7 – 当您再次运行此应用程序时,您也会看到垂直方向的进度条。
MFC – 文件系统
在本章中,我们将讨论文件系统的各个组件。
驱动器
甲驱动是连接到计算机,以便它能够存储信息的物理装置。逻辑磁盘、逻辑卷或虚拟磁盘(简称 VD 或 vdisk)是一种在计算机系统中的一个或多个物理磁盘驱动器上提供可用存储容量区域的虚拟设备。驱动器可以是硬盘、CD ROM、DVD ROM、闪存 (USB) 驱动器、存储卡等。
您要执行的主要操作之一是获取计算机上的驱动器列表。
让我们通过创建一个新的基于 MFC 对话框的应用程序来查看一个简单的示例。
步骤 1 – 从工具箱中拖动一个按钮,将其标题更改为获取驱动器信息。
步骤 2 – 删除静态控件的标题(TODO 行)并将其 ID 更改为 IDC_STATIC_TEXT。
步骤 3 – 右键单击按钮并选择添加事件处理程序。
步骤 4 – 选择 BN_CLICKED 消息类型,然后单击添加和编辑按钮。
步骤 5 – 为静态文本控件添加值变量 m_strDrives。
为了支持计算机上的驱动器,Win32 库提供了 Microsoft Window 的 GetLogicalDrives() 函数,该函数将检索当前计算机上所有驱动器的列表。
Step 6 – 编译并执行上述代码后,您将看到以下输出。
步骤 7 – 单击按钮时,您可以看到计算机上的所有驱动器。
目录
在计算中,目录是一种文件系统编目结构,其中包含对其他计算机文件的引用,可能还有其他目录。目录是一个物理位置。它可以处理驱动器上不可用的操作。
让我们通过创建一个新的基于 MFC 对话框的应用程序来看看一个简单的例子
步骤 1 – 从工具箱中拖动三个按钮。将他们的标题更改为创建目录、删除目录和移动目录。
步骤 2 – 将这些按钮的 ID 更改为IDC_BUTTON_CREATE、IDC_BUTTON_DELETE和IDC_BUTTON_MOVE。
步骤 3 – 删除 TODO 行。
第 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"); }
Step 9 – 编译并执行上述代码后,您将看到以下输出。
步骤 10 – 当您单击“创建目录”按钮时,它将创建这些目录。
步骤 11 – 当您单击删除目录按钮时,它将删除 Dir1。
文件处理
MFC 应用程序中的大多数文件处理是与名为CArchive的类一起执行的。CArchive 类充当应用程序和用于存储数据或使其可用的介质之间的中继。它允许您以永久二进制形式(通常是磁盘存储)保存复杂的对象网络,这些对象被删除后仍然存在。
这是 CArchive 类中的方法列表 –
这是用于存储和检索数据的运算符列表
Sr.No. | 名称和描述 |
---|---|
1 |
operator << 将对象和原始类型存储到存档中。 |
2 |
operator >> 从存档中加载对象和原始类型。 |
让我们通过创建一个新的基于 MFC 对话框的应用程序来查看一个简单的示例。
步骤 1 – 拖动一个编辑控件和两个按钮,如下面的快照所示。
步骤 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(); }
Step 5 – 编译并执行上述代码后,您将看到以下输出。
第 6 步– 写一些东西并点击保存。它将以二进制格式保存数据。
步骤 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 中的方法列表 –
Sr.No. | 名称和描述 |
---|---|
1 |
Open 超载。Open 设计用于与默认的 CStdioFile 构造函数(覆盖 CFile::Open)一起使用。 |
2 |
ReadString 读取单行文本。 |
3 |
Seek 定位当前文件指针。 |
4 |
WriteString 写入一行文本。 |
让我们通过创建一个新的基于 MFC 对话框的应用程序来再次查看一个简单的示例。
步骤 1 – 拖动一个编辑控件和两个按钮,如下面的快照所示。
步骤 2 – 添加值变量m_strEditCtrl以进行编辑控制。
步骤 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(); }
Step 5 – 编译并执行上述代码后,您将看到以下输出。
第 6 步– 写一些东西并点击保存。它将数据保存在 *.txt 文件中。
步骤 7 – 如果您查看文件的位置,您将看到它包含 test.txt 文件。
步骤 8 – 现在,关闭应用程序。运行相同的应用程序。单击“打开”时,将再次加载相同的文本。
步骤 9 – 首先打开文件,读取文件,然后更新编辑控件。
MFC – 文档视图
该文档/视图结构是用于创建基于Microsoft基础类库的应用奠定了基础。它允许您区分组成计算机程序的不同部分,包括用户将其视为应用程序的一部分以及用户将处理的文档。这是通过作为一个整体工作的单独类的组合来完成的。
组成文档/视图架构的部分是框架、一个或多个文档和视图。放在一起,这些实体构成了一个可用的应用程序。
看法
一个观点是用户正在做他或她的工作平台。为了让用户在应用程序上做任何事情,你必须提供一个视图,它是一个基于 CView 类的对象。您可以直接使用从 CView 派生的类之一,也可以从 CView 或其子类之一派生您自己的自定义类。
文档
一个文件是类似于桶。对于计算机应用程序,文档包含用户的数据。要创建此体系结构的文档部分,您必须从 CDocument 类派生一个对象。
框架
顾名思义,框架是项目的构建块、结构和边框的组合。框架为窗口提供了“物理”存在。它还定义了对象相对于 Windows 桌面的位置。
单文档界面 (SDI)
表达单文档界面或 SDI 是指只能向用户呈现一个视图的文档。这意味着应用程序一次不能显示多个文档。如果要查看当前应用程序的另一种类型的文档,则必须创建该应用程序的另一个实例。记事本和写字板是 SDI 应用程序的示例。
让我们通过创建一个新的基于 MFC 对话框的应用程序来研究单文档界面或 SDI 的简单示例。
步骤 1 – 让我们使用下面提到的设置创建一个新的 MFC 应用程序MFCSDIDemo。
步骤 2 – 从应用程序类型中选择单个文档,从项目样式中选择 MFC 标准。
步骤 3 – 单击完成继续。
第 4 步– 创建项目后,运行应用程序,您将看到以下输出。
多文档界面 (MDI)
如果用户可以在应用程序中打开多个文档而不关闭它,则应用程序称为多文档界面或 MDI。为了提供此功能,应用程序提供了一个父框架,作为计算机程序的主框架。在此框架内,应用程序允许使用单独的框架创建视图,使每个视图彼此不同。
让我们通过创建一个新的基于 MFC 对话框的应用程序来查看多文档界面或 MDI 的简单示例。
步骤 1 – 让我们使用下面提到的设置创建一个新的 MFC 应用程序MFCMDIDemo。
步骤 2 – 从应用程序类型和 MFC 标准中选择多个文档从项目样式。
步骤 3 – 单击完成继续。
第 4 步– 创建项目后,运行应用程序,您将看到以下输出。
步骤 5 – 当您单击文件 → 新建菜单选项时,它将创建另一个子窗口,如下面的快照所示。
步骤 6 – 在多文档界面 (MDI) 应用程序中,每个应用程序有一个主框架。在这种情况下,每个文档都有一个 CMDIFrameWnd 和一个 CMDIChildWnd 派生子框架。
MFC – 字符串
字符串是表示字符序列的对象。C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。
-
这个字符串实际上是一个以空字符“\0”结尾的一维字符数组。
-
以空字符结尾的字符串包含组成后跟空字符的字符串的字符。
这是字符数组的简单示例。
char word[12] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', 'char word[12] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0' };' };
以下是表示它的另一种方式。
char word[] = "Hello, World";
Microsoft 基础类 (MFC) 库提供了一个用于操作名为CString 的字符串的类。以下是 CString 的一些重要特性。
-
CString 没有基类。
-
CString 对象由可变长度的字符序列组成。
-
CString 使用类似于 Basic 的语法提供函数和运算符。
-
连接和比较运算符,连同简化的内存管理,使 CString 对象比普通字符数组更易于使用。
这是 CString 的构造函数。
Sr.No. | 方法和说明 |
---|---|
1 |
CString 以各种方式构造 CString 对象 |
这是数组方法列表 –
Sr.No. | 方法和说明 |
---|---|
1 |
GetLength 返回 CString 对象中的字符数。 |
2 |
IsEmpty 测试 CString 对象是否不包含任何字符。 |
3 |
Empty 强制字符串长度为 0。 |
4 |
GetAt 返回指定位置的字符。 |
5 |
SetAt 在指定位置设置字符。 |
这是比较方法列表 –
Sr.No. | 方法和说明 |
---|---|
1 |
Compare 比较两个字符串(区分大小写)。 |
2 |
CompareNoCase 比较两个字符串(不区分大小写)。 |
这是提取方法列表 –
Sr.No. | 方法和说明 |
---|---|
1 |
Mid 提取字符串的中间部分(如基本 MID$ 函数)。 |
2 |
Left 提取字符串的左侧部分(如 Basic LEFT$ 函数)。 |
3 |
Right 提取字符串的右侧部分(如 Basic RIGHT$ 函数)。 |
4 |
SpanIncluding 从字符串中提取给定字符集中的字符。 |
5 |
SpanExcluding 从字符串中提取不在给定字符集中的字符。 |
这是转换方法的列表。
Sr.No. | 方法和说明 |
---|---|
1 |
MakeUpper 将此字符串中的所有字符转换为大写字符。 |
2 |
MakeLower 将此字符串中的所有字符转换为小写字符。 |
3 |
MakeReverse 反转此字符串中的字符。 |
4 |
Format 像 sprintf 那样格式化字符串。 |
5 |
TrimLeft 修剪字符串中的前导空白字符。 |
6 |
TrimRight 从字符串中修剪尾随的空白字符。 |
这是搜索方法的列表。
Sr.No. | 方法和说明 |
---|---|
1 |
Find 在较大的字符串中查找字符或子字符串。 |
2 |
ReverseFind 在较大的字符串中查找字符;从最后开始。 |
3 |
FindOneOf 从集合中查找第一个匹配字符。 |
这是缓冲区访问方法的列表。
Sr.No. | 方法和说明 |
---|---|
1 |
GetBuffer 返回指向 CString 中字符的指针。 |
2 |
GetBufferSetLength 返回一个指向 CString 中字符的指针,截断到指定的长度。 |
3 |
ReleaseBuffer 释放对 GetBuffer 返回的缓冲区的控制 |
4 |
FreeExtra 通过释放先前分配给字符串的任何额外内存来消除此字符串对象的任何开销。 |
5 |
LockBuffer 禁用引用计数并保护缓冲区中的字符串。 |
6 |
UnlockBuffer 启用引用计数并释放缓冲区中的字符串。 |
这是 Windows 特定方法的列表。
Sr.No. | 方法和说明 |
---|---|
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 }
当上面的代码编译执行后,你会看到下面的输出。
空字符串
您可以通过使用空字符串文字或使用 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 }
编译并执行上述代码后,您将看到以下输出。
字符串连接
要连接两个或多个字符串,您可以使用 + 运算符连接两个字符串或 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 }
编译并执行上述代码后,您将看到以下输出。
字符串长度
要查找字符串的长度,您可以使用 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 }
编译并执行上述代码后,您将看到以下输出。
字符串比较
要比较两个字符串变量,您可以使用 == 运算符
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 }
编译并执行上述代码后,您将看到以下输出。
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 }
Step 3 – 编译并执行上述代码后,您将看到以下输出。
在中间添加项目
要在数组中间添加项目,您可以使用 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 dded 作为第二个索引。
更新项目值
要更新数组中间的项目,您可以使用 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 }
当上面的代码编译执行后,你会看到下面的输出。您现在可以看到第三个元素的值已更新。
复制数组
要将整个数组复制到另一个 CArray 对象中,可以使用 CArray::Copy() 函数。
Step1 – 让我们创建另一个数组并复制第一个数组中的所有元素,如下面的代码所示。
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 }
您现在可以看到我们已经从 2nd 数组和输出是一样的,因为我们使用了复制函数。
删除项目
要删除任何特定项目,您可以使用 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 不再是数组的一部分。
MFC – 链表
甲链表是线性数据结构,其中每个元件是一个单独的对象。列表的每个元素(我们称之为节点)都包含两个项目——数据和对下一个节点的引用。最后一个节点引用了 null。
链表是由一组节点组成的数据结构,这些节点共同表示一个序列。它是一种用结构存储数据的方法,以便程序员可以在需要时自动创建一个新位置来存储数据。它的一些显着特点是 –
-
链接列表是包含项目的链接序列。
-
每个链接都包含到另一个链接的连接。
-
列表中的每一项都称为一个节点。
-
如果列表至少包含一个节点,则新节点将定位为列表中的最后一个元素。
-
如果列表只有一个节点,则该节点表示第一项和最后一项。
有两种类型的链接列表 –
单链表
单向链表是一种数据结构。在单向链表中,链表中的每个节点都存储该节点的内容以及指向链表中下一个节点的指针或引用。
双向链表
双向链表是一种链接数据结构,由一组称为节点的顺序链接记录组成。每个节点包含两个字段,它们是对节点序列中前一个节点和下一个节点的引用。
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 变量作为迭代器来按顺序遍历列表。
Step 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 }
Step 3 – 编译并执行上述代码后,您将看到以下输出。
在中间添加项目
要在列表中间添加项目,您可以使用 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 的位置,然后在该值之前和之后插入一个元素。
Step 3 – 编译并执行上述代码后,您将看到以下输出。
更新项目值
要更新数组中间的项目,可以使用 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。
删除项目
要删除任何特定项目,您可以使用 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 的值不再是列表的一部分。
MFC – 数据库类
一个数据库是被组织,以便它可以很容易地访问,管理和更新信息的集合。基于 ODBC 的 MFC 数据库类旨在提供对任何有 ODBC 驱动程序可用的数据库的访问。由于这些类使用 ODBC,您的应用程序可以访问许多不同数据格式和不同本地/远程配置的数据。
您不必编写特殊情况代码来处理不同的数据库管理系统 (DBMS)。只要您的用户有适合他们想要访问的数据的 ODBC 驱动程序,他们就可以使用您的程序来操作存储在那里的表中的数据。数据源是由某个数据库管理系统 (DBMS) 托管的特定数据实例。示例包括 Microsoft SQL Server、Microsoft Access 等。
数据库
MFC 提供了一个CDatabase类,它表示与数据源的连接,通过它您可以对数据源进行操作。您可以在应用程序中一次激活一个或多个 CDatabase 对象。
让我们通过创建一个新的基于 MFC 对话框的应用程序来查看一个简单的示例。
步骤 1 – 将 TODO 行的标题更改为从数据库中检索数据并拖动一个按钮和一个列表控件,如下面的快照所示。
步骤 2 – 为按钮添加单击事件处理程序,并为列表控件添加控件变量 m_ListControl。
步骤 3 – 我们有一个简单的数据库,其中包含一个带有一些记录的员工表,如下面的快照所示。
第 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;
Step 2 – 编译并执行上述代码后,您将看到在您的数据库中添加了一条新记录。
检索记录
为了在 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(); };
Step 5 – 编译并执行上述代码后,您将看到以下输出。
步骤 6 – 按读取按钮执行数据库操作。它将检索员工表。
更新记录
SQL UPDATE Query 用于修改表中的现有记录。您可以将 WHERE 子句与 UPDATE 查询一起使用来更新选定的行,否则所有行都会受到影响。
第 1 步– 让我们通过更新 ID 等于 5 的年龄来查看一个简单的示例。
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; }
Step 3 – 编译并执行上述代码后,您将看到以下输出。
步骤 4 – 按读取按钮执行数据库操作。它将检索以下员工表。
第 5 步– 您现在可以看到年龄从 69 更新到 59。
删除记录
SQL DELETE 查询用于从表中删除现有记录。您可以使用带有 DELETE 查询的 WHERE 子句删除选定的行,否则所有记录都将被删除。
步骤 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; }
Step 3 – 编译并执行上述代码后,您将看到以下输出。
步骤 4 – 按读取按钮执行数据库操作。它将检索员工表。
MFC – 序列化
序列化是将对象写入或读取持久性存储介质(例如磁盘文件)的过程。序列化适用于需要在程序执行期间或之后维护结构化数据(例如 C++ 类或结构)状态的情况。
执行文件处理时,值通常是原始类型(char、short、int、float 或 double)。同样,我们可以单独保存多个值,一次一个。这种技术不包括从(作为变量)类创建的对象。
MFC 库高度支持序列化。它从 CObject 类开始,它是大多数 MFC 类的祖先,它配备了 Serialize() 成员函数。
让我们通过创建一个新的 MFC 项目来查看一个简单的示例。
步骤 1 – 删除 TODO 行并设计您的对话框,如下面的快照所示。
步骤 2 – 为所有编辑控件添加值变量。对于提到的 Emp ID 和 Age,值类型是一个整数,如下面的快照所示。
步骤 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); }
Step 8 – 编译并执行上述代码后,您将看到以下输出。
步骤 9 – 在所有字段中输入信息,然后单击保存并关闭此程序。
步骤 10 – 它将保存数据。再次运行应用程序并单击打开。它将加载员工信息。
MFC——多线程
Microsoft 基础类 (MFC) 库为多线程应用程序提供支持。线程是进程内的执行路径。当您启动记事本时,操作系统会创建一个进程并开始执行该进程的主线程。当这个线程终止时,进程也会终止。
如果需要,您可以在应用程序中创建其他线程。MFC 应用程序中的所有线程都由 CWinThread 对象表示。在大多数情况下,您甚至不必显式创建这些对象;而是调用框架辅助函数 AfxBeginThread,它会为您创建 CWinThread 对象。
让我们通过创建一个新的基于 MFC 对话框的应用程序来查看一个简单的示例。
步骤 1 – 将静态控件的标题和 ID 分别更改为单击启动线程按钮和IDC_STATIC_TEXT。
第 2 步– 拖动两个按钮并为这些按钮添加单击事件处理程序。
步骤 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 – 编译并执行上述代码后,您将看到以下输出。
步骤 11 – 现在单击“开始线程”按钮。
步骤 12 – 单击停止线程按钮。它会停止线程。
MFC – 互联网编程
Microsoft 提供了许多用于对客户端和服务器应用程序进行编程的 API。正在为 Internet 编写许多新应用程序,随着技术、浏览器功能和安全选项的变化,将编写新类型的应用程序。您的自定义应用程序可以在 Internet 上检索信息并提供数据。
MFC 提供了一个CSocket类,用于使用 Windows Sockets 编写网络通信程序。
这是 CSocket 类中的方法列表。
Sr.No. | 名称和描述 |
---|---|
1 |
Attach 将 SOCKET 句柄附加到 CSocket 对象。 |
2 |
CancelBlockingCall 取消当前正在进行的阻塞呼叫。 |
3 |
Create 创建一个套接字。 |
4 |
FromHandle 返回一个指向 CSocket 对象的指针,给定一个 SOCKET 句柄。 |
5 |
IsBlocking 确定是否正在进行阻塞调用。 |
让我们通过创建 MFS SDI 应用程序来查看一个简单的示例。
步骤 1 – 在名称字段中输入 MFCServer,然后单击确定。
步骤 2 – 在高级功能选项卡上,检查 Windows 套接字选项。
第 3 步– 创建项目后,添加一个新的 MFC 类 CServerSocket。
步骤 4 – 选择 CSocket 作为基类,然后单击完成。
第 5 步– 添加更多 MFC 类 CReceivingSocket。
第 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 函数。
步骤 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 类,然后选择添加 → AddFunction。
步骤 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 对话框的应用程序。
步骤 2 – 在高级功能选项卡上,检查 Windows 套接字选项,如上所示。
步骤 3 – 创建项目后,设计对话框,如下面的快照所示。
步骤 4 – 为连接和发送按钮添加事件处理程序。
步骤 5 – 为所有三个编辑控件添加值变量。对于端口编辑控制,选择变量类型 UINT。
步骤 6 – 添加用于连接和发送消息的 MFC 类。
步骤 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 和端口,然后单击连接。
步骤 11 – 您现在将在服务器端看到消息,如下面的快照所示。
MFC-GDI
Windows 提供了在设备上下文中使用的各种绘图工具。它提供用于绘制线条的笔、用于填充内部的画笔和用于绘制文本的字体。MFC 提供了与 Windows 中的绘图工具等效的图形对象类。
画画
设备上下文是一种 Windows 数据结构,包含有关设备(如显示器或打印机)的绘图属性的信息。所有绘图调用都是通过一个设备上下文对象进行的,该对象封装了用于绘制线条、形状和文本的 Windows API。
设备上下文允许在 Windows 中进行独立于设备的绘图。设备上下文可用于绘制到屏幕、打印机或图元文件。
CDC是在 MFC 中绘制的最基本的类。CDC 对象提供执行基本绘图步骤的成员函数,以及处理与窗口客户区关联的显示上下文的成员。
Sr. No. | 名称和描述 |
---|---|
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 从此 CDC 对象分离 Windows 设备上下文。 |
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 将当前字体的字样名称作为以空字符结尾的字符串复制到缓冲区中。 |
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 使用指定的模式更改设备上下文的世界转换。 |
120 |
MoveTo 移动当前位置。 |
121 |
OffsetClipRgn 移动给定设备的剪辑区域。 |
122 |
OffsetViewportOrg 相对于当前视口原点的坐标修改视口原点。 |
123 |
OffsetWindowOrg 相对于当前窗口原点的坐标修改窗口原点。 |
124 |
PaintRgn 用选定的画笔填充区域。 |
125 |
PatBlt 创建位模式。 |
126 |
Pie 绘制一个饼形楔子。 |
127 |
PlayMetaFile 在给定设备上播放指定元文件的内容。PlayMetaFile 的增强版本显示存储在给定增强格式元文件中的图片。图元文件可以播放任意次数。 |
128 |
PlgBlt 执行从源设备上下文中指定矩形到给定设备上下文中指定平行四边形的颜色数据位的位块传输。 |
129 |
PolyBezier 绘制一个或多个 Bzier 样条。当前位置既不使用也不更新。 |
130 |
PolyBezierTo 绘制一个或多个 Bzier 样条,并将当前位置移动到最后一个 Bzier 样条的终点。 |
131 |
PolyDraw 绘制一组线段和 Bzier 样条。此函数更新当前位置。 |
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 |
重置DC 更新 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 将指定坐标处的像素设置为与指定颜色最接近的近似值。SetPixelV比SetPixel更快,因为它不需要返回实际绘制的点的颜色值。 |
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 将当前路径重新定义为如果使用当前选择到设备上下文中的笔对路径进行描边将要绘制的区域。 |
线
第 1 步– 让我们看一个简单的例子,创建一个新的基于 MFC 的单文档项目,名称为MFCGDIDemo。
步骤 2 – 创建项目后,转到解决方案资源管理器并双击Source Files 文件夹下的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 步– 运行此应用程序。您将看到以下输出。
步骤 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 – 运行此应用程序。您将看到以下输出。
折线
多段线是一系列相连的线。这些线存储在 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 步– 当您运行此应用程序时,您将看到以下输出。
矩形
甲矩形是由四边了组成四个直角的几何图形。与直线一样,要绘制矩形,您必须定义它的起点和终点。要绘制矩形,您可以使用 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 步– 当您运行此应用程序时,您将看到以下输出。
正方形
阿方是由四边了组成四个直角的几何图形,而且每一侧的长度必须相等。
让我们看一个简单的例子。
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 }
运行此应用程序时,您将看到以下输出。
馅饼
甲饼是由两条线分隔的跨度从椭圆的中心到各一侧上的椭圆的一部分。要绘制饼图,您可以使用 CDC::Pie() 方法,如下所示 –
BOOL Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
-
(x1, y1) 点确定代表饼图的椭圆所在的矩形的左上角。(x2, y2) 点是矩形的右下角。
-
(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 步– 当您运行此应用程序时,您将看到以下输出。
弧线
弧是椭圆的一部分或一段,这意味着弧是不完整的椭圆。要绘制圆弧,您可以使用 CDC::Arc() 方法。
BOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
CDC 类配备了 SetArcDirection() 方法。
这是语法 –
int SetArcDirection(int nArcDirection)
Sr.No. | 价值与方向 |
---|---|
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 步– 当您运行此应用程序时,您将看到以下输出。
和弦
到目前为止,我们绘制的弧线被认为是开放图形,因为它们由一条有起点和终点的线组成(与没有起点和终点的圆或矩形不同)。甲和弦是一个圆弧的两端用直线连接。
要绘制和弦,您可以使用 CDC::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 }
当您运行上述应用程序时,您将看到以下输出。
本例中的弧方向设置为顺时针。
颜色
的颜色是一种能提高对象物的美学外观,最根本的对象。颜色是一种非空间对象,添加到对象以修改其某些视觉方面。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 }
运行此应用程序时,您将看到以下输出。
字体
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 }
当您运行上述应用程序时,您将看到以下输出。
钢笔
甲笔是用于绘制直线和曲线上的设备上下文的工具。在图形编程中,笔也用于绘制矩形或多边形等几何闭合形状的边界。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 }
当您运行上述应用程序时,您将看到以下输出。
画笔
甲刷是用于填写闭合形状或线的内部的绘图工具。刷子的行为就像拿起一桶油漆并将其倒在某个地方。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 }
运行此应用程序时,您将看到以下输出。
MFC – 库
一个库是一组可以提供给那些需要已实施实体,而不需要知道他们是如何创建这些函数,类或资源或如何运作程序函数,类或其他资源。库使程序员可以轻松地使用由其他人或公司创建的函数、类和资源等,并相信此外部源是可靠且高效的。与库相关的一些独特功能是 –
-
库的创建和功能类似于普通的常规程序,使用函数或其他资源并与其他程序通信。
-
为了实现其功能,库包含其他程序完成其功能所需的功能。
-
同时,库可能会使用其他程序不需要的某些功能。
-
使用库的程序也称为库的客户端。
您将在库中创建或包含两种类型的函数 –
-
内部函数仅由库本身使用,库的客户端不需要访问这些函数。
-
外部函数是库的客户端可以访问的函数。
您将在程序中处理两大类库 –
- 静态库
- 动态库
静态库
一个静态库是包含函数,类或资源外部程序可以用它来补充其功能的文件。要使用库,程序员必须创建指向它的链接。该项目可以是控制台应用程序、Win32 或 MFC 应用程序。库文件具有 lib 扩展名。
第 1 步– 让我们通过创建一个新的 Win32 项目来研究一个简单的静态库示例。
步骤 2 – 在应用程序向导对话框中,选择静态库选项。
步骤 3 – 单击完成继续。
步骤 4 – 右键单击解决方案资源管理器中的项目,然后从“添加”→“新项目”…菜单选项中添加一个头文件。
步骤 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) 文件。
步骤 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 – 通过单击Build → Build MFCLib从主菜单构建此库。
步骤 10 – 成功构建库后,它将显示上述消息。
步骤 11 – 要使用库中的这些函数,让我们添加另一个基于文件 → 新建 → 项目的 MFC 对话框应用程序。
步骤 12 – 转到 MFCLib\Debug 文件夹并将头文件和 *.lib 文件复制到 MFCLibTest 项目,如下面的快照所示。
步骤 13 – 要将库添加到当前项目,在主菜单上,单击项目 → 添加现有项目并选择 MFCLib.lib。
步骤 14 – 设计您的对话框,如下面的快照所示。
步骤 15 – 为值类型为 double 的两个编辑控件添加值变量。
步骤 16 – 为对话框末尾的静态文本控件添加值变量。
步骤 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 – 编译并执行上述代码后,您将看到以下输出。
步骤 20 – 在编辑字段中输入两个值,然后单击计算。您现在将看到从库中计算后的结果。
动态库
Win32 DLL 是一个库,可供在 Microsoft Windows 计算机上运行的程序使用。作为一个普通的库,它由分组在一个文件中的函数和/或其他资源组成。
DLL 缩写代表动态链接库。这意味着,与静态库不同,DLL 允许程序员决定何时以及如何将其他应用程序链接到此类库。
例如,DLL 允许不同的应用程序在它们认为合适和必要时使用其库。事实上,在不同编程环境中创建的应用程序可以使用存储在一个特定 DLL 中的函数或资源。因此,应用程序动态链接到库。
第 1 步– 让我们通过创建一个新的 Win32 项目来查看一个简单的示例。
步骤 2 – 在应用程序类型部分,单击 DLL 单选按钮。
步骤 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,在主菜单上,从主菜单中单击Build > Build MFCDynamicLib。
步骤 7 – 成功创建 DLL 后,您将在输出窗口中看到一条消息显示。
步骤 8 – 打开 Windows 资源管理器,然后打开当前项目的 Debug 文件夹。
步骤 9 – 请注意,已经创建了一个扩展名为 dll 的文件和另一个扩展名为 lib 的文件。
步骤 10 – 要使用 dll 扩展名测试此文件,我们需要从文件 → 新建 → 项目创建一个新的基于 MFC 对话框的应用程序。
步骤 11 – 转到 MFCDynamicLib\Debug 文件夹并将 *.dll 和 *.lib 文件复制到 MFCLibTest 项目,如下面的快照所示。
步骤 12 – 要将 DLL 添加到当前项目,在主菜单上,单击项目 → 添加现有项目,然后选择 MFCDynamicLib.lib 文件。
步骤 13 – 设计您的对话框,如下面的快照所示。
步骤 14 – 为值类型为 double 的两个编辑控件添加值变量。
步骤 15 – 为静态文本控件添加值变量,位于对话框的末尾。
步骤 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 – 编译并执行上述代码后,您将看到以下输出。
步骤 21 – 在编辑字段中输入两个值,然后单击计算。您现在将看到从 DLL 计算后的结果。