MFC项目训练

目录

  • Win消息机制、SDK编程基础
    • 基本概念介绍(SDK、API、句柄、消息队列、WinMain函数)
      • SDK
      • API函数
      • 窗口和句柄
      • 消息和消息队列
      • WinMain函数
    • 第一个Windows界面程序(WinAPI)
      • 设计一个窗口类
      • 注册窗口类
      • 创建窗口
      • 显示和更新窗口
    • 消息循环
      • 取消息
      • 建立消息循环
    • 窗口过程函数
    • 第一个MFC程序(CWinApp、CFrameWnd)
      • 程序执行流程
      • CWinApp应用程序类
    • 消息映射
    • unicode字符集介绍
      • 多字节字符集(8位的ANSI字符集)
      • 宽字符集(16位的Unicode字符集)
      • TEXT(_T)宏
      • TCHAR类型
    • LPCTSTR、CString、char* 和 String 是在 C++ 和特别是在 Windows 编程中常用的字符串类型,它们各自有不同的特点和用途
      • 1. LPCTSTR:
      • 2. CString:
      • 3. char*:
      • 4. String:
  • 用向导生成一个MFC应用程序
    • MFC应用程序几个重要函数的介绍
      • InitInstance函数
      • PreCreateWindow函数
      • OnCreate
      • OnDraw和OnPaint
    • 事件的添加和删除
      • 消息处理的添加
      • 工程文件增加几处改变:
  • 基于对话框编程
    • 对话框(模态和非模态)
    • 常用控件的使用
      • 静态文本框static text
      • 按钮Button
      • `编辑框Edit`
      • 关联基础变量类型
      • 组合框(下拉框)CComboBox
      • 列表视图控件 ListCtrl
      • 树视图控件 TreeCtrl
      • 添加图标资源(icon)
        • 把ico资源文件放在项目res文件夹中
        • 资源视图 -> Icon -> 添加资源
        • 导入ico文件
        • 通过代码加载图标
        • 创建图像列表
      • 树控件的相应操作
      • 标签控件 CTabCtrl
        • 添加对话框:资源视图 -> Dialog -> 右击 -> 插入 Dialog
        • 设置相应属性
        • 添加MFC类
        • 主对话框类中, 定义自定义MFC类对象,需要相应头文件
        • 主对话框类中 OnInitDialog() 做初始化工作
  • 综合案例:销售信息管理系统

Win消息机制、SDK编程基础

基本概念介绍(SDK、API、句柄、消息队列、WinMain函数)

SDK

软件开发工具包(Software Development Kit),一般都是一些被软件工程师用于为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件的开发工具的集合。

API函数

Windows操作系统提供给应用程序编程的接口(Application Programming Interface)。
Windows应用程序API函数是通过C语言实现的,所有主要的 Windows 函数都在 Windows.h 头文件中进行了声明。Windows 操作系统提供了 1000 多种 API函数。

窗口和句柄

窗口是 Windows 应用程序中一个非常重要的元素,一个 Windows 应用程序至少要有一个窗口,称为主窗口。
窗口是 Windows 应用程序与用户进行交互的接口。利用窗口可以接收用户的输入、以及显示输出。
一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、 可调边框,有的还有滚动条。
MFC项目训练_第1张图片
窗口可以有一个父窗口, 有父窗口的窗口称为子窗口。除了上图所示类型的窗口外, 对话框和消息框也是一种窗口。 在对话框上通常还包含许多子窗口, 这些子窗口的形式有按钮、 单选按钮、 复选框、 组框、 文本编辑框等。

在 Windows 应用程序中, 窗口是通过窗口句柄( HWND) 来标识的。 我们要对某个窗口进行操作, 首先就要得到这个窗口的句柄。_In_ HINSTANCE hInstance, //应用程序实例句柄

句柄( HANDLE) 是 Windows 程序中一个重要的概念, 使用也非常频繁。 在 Windows 程序中, 有各种各样的资源( 窗口、 图标、光标、画刷等), 系统在创建这些资源时会为它们分配内存, 并返回标识这些资源的标识号, 即句柄。 在后面的内容中我们还会看到图标句柄( HICON)、 光标句柄( HCURSOR) 和画刷句柄( HBRUSH)。

消息和消息队列

Windows 程序设计是一种完全不同于传统的 DOS 方式的程序设计方法。它是一种事件驱动方式的程序设计模式,主要是基于消息的。
每一个 Windows 应用程序开始执行后, 系统都会为该程序创建一个消息队列, 这个消息队列用来存放该程序创建的窗口的消息。
例如,当用户在窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到这一事件,于是将这个事件包装成一个消息,投递到应用程序的消息队列中,等待应用程序的处理。
然后应用程序通过一个消息循环不断地从消息队列中取出消息,并进行响应。
在这个处理过程中,操作系统也会给应用程序“ 发送消息”。所谓“ 发送消息”,实际上是操作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程。

WinMain函数

当Windows操作系统启动一个程序时,它调用的就是该程序的WinMain函数( 实际是由插入到可执行文件中的启动代码调用的)。
WinMain是Windows程序的入口点函数,与DOS程序的入口点函数main的作用相同,当WinMain 函数结束或返回时,Windows应用程序结束。

第一个Windows界面程序(WinAPI)

一个完整的Win32程序(#include ),该程序实现的功能是创建一个窗口,并在该窗口中响应键盘及鼠标消息,程序的实现步骤为:

  1. WinMain函数的定义
  2. 创建一个窗口
  3. 进行消息循环
  4. 编写窗口过程函数
int WINAPI WinMain(
    _In_ HINSTANCE hInstance, //应用程序实例句柄
	_In_opt_ HINSTANCE hPrevInstance, //上一个应用程序实例句柄
	_In_ LPSTR lpCmdLine, //命令行参数 Char* argv[]
	_In_ int nShowCmd)//窗口显示的样式
{ }
  • hInstance:表示该程序当前运行的实例的句柄,这是一个数值。当程序在Windows下运行时,它唯一标识运行中的实例(注意,只有运行中的程序实例, 才有实例句柄)。一个应用程序可以运行多个实例,每运行一个实例,系统都会给该实例分配一个句柄值,并通过hInstance参数传递给 WinMain 函数。

创建一个完整的窗口,需要经过下面几个步骤:
a.设计一个窗口类
b.注册窗口类
c.创建窗口
d.显示及更新窗口

设计一个窗口类

一个完整的窗口具有许多特征, 包括光标(鼠标进入该窗口时的形状)、图标、背景色等。在创建一个窗口前, 也必须对该类型的窗口进行设计, 指定窗口的特征。在Windows中,窗口的特征就是由WNDCLASS结构体来定义的,我们只需给WNDCLASS结构体对应的成员赋值,即可完成窗口类的设计。

typedef struct tagWNDCLASSW {
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCWSTR     lpszMenuName;
    LPCWSTR     lpszClassName;
} WNDCLASSW
WNDCLASS wc;
wc.cbClsExtra = 0;//类的额外的内存,,通常为0
wc.cbWndExtra = 0;//窗口的额外内存,通常为0
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//设置背景颜色
wc.hCursor = LoadCursor(NULL, IDC_SIZEALL);//设置光标
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);//设置图标
wc.hInstance = hInstance;//应用程序实例句柄
wc.lpfnWndProc = Wndproc;//回调函数 窗口过程
wc.lpszClassName = TEXT("WINDOW");//窗口类类名
wc.lpszMenuName = NULL;//	指定菜单资源的名字。如果设置为NULL,那么基于这个窗口类创建的窗口将没有默认菜单。
wc.style = 0;//默认显示风格
  • lpfnWndProc:指定一个窗口回调函数,是一个函数的指针。
    当应用程序收到给某一窗口的消息时,就应该调用某一函数来处理这条消息。这一调用过程不用应用程序自己来实施,而由操作系统来完成,但是,回调函数本身的代码必须由应用程序自己完成。对于一条消息,操作系统调用的是接受消息的窗口所属的类型中的lpfnWndProc成员指定的函数。每一种不同类型的窗口都有自己专用的回调函数,该函数就是通过lpfnWndProc成员指定的。

回调函数的定义形式如下:

LRESULT CALLBACK WindowProc(
	HWND hWnd,		//信息所属的窗口句柄
	UINT uMsg,		//消息类型
	WPARAM wParam,	//附加信息(如键盘哪个键按下)
	LPARAM lParam	//附加信息(如鼠标点击坐标)
	);

注册窗口类

RegisterClass(&wc);

设计完窗口类(WNDCLASS)后, 需要调用RegisterClass函数对其进行注册,注册成功后,才可以创建该类型的窗口。

创建窗口

设计好窗口类并且将其成功注册之后, 即可用CreateWindow函数产生这种类型的窗口了。

	/*
	HWND CreateWindow(
  [in, optional]  lpClassName,  指定窗口类的名称
  [in, optional]  lpWindowName, 指定窗口的名字,即窗口的标题。
  [in]            dwStyle,      指定创建的窗口的样式,一般用WS_OVERLAPPEDWINDOW
  [in]            x,            显示坐标
  [in]            y,
  [in]            nWidth,       默认值CW_USEDEFAULT
  [in]            nHeight,
  [in, optional]  hWndParent,   父窗口
  [in, optional]  hMenu,        指定窗口菜单的句柄,没有,则设置为NULL。
  [in, optional]  hInstance,    窗口所属的应用程序实例的句柄,用WinMain中的形参hInstance为其赋值。
  [in, optional]  lpParam       作为WM_CREATE消息的附加参数lParam传入的数据指针。通常设置为NULL。
);
	*/
	HWND hwnd = CreateWindow(wc.lpszClassName, TEXT("这是一个标题"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

如果窗口创建成功,CreateWindow函数将返回系统为该窗口分配的句柄,否则,返回NULL。

显示和更新窗口

ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);

消息循环

在创建窗口、显示窗口、更新窗口后,我们需要编写一个消息循环,不断地从消息队列中取出消息,并进行响应。
在Windows程序中,消息是由MSG结构体来表示的。MSG结构体的定义如下:

typedef struct tagMSG {
	HWND hWnd;   //消息所属的窗口。
	UINT message;   //消息的标识符,是由一个数值来表示的,不同的消息对应不同的数值。
	WPARAM wParam;  //指定消息的附加信息
	LPARAM lParam;   //指定消息的附加信息
	DWORD time;   //标识一个消息产生时的时间。
	POINT pt;     //表示产生这个消息时光标或鼠标的坐标。
} MSG;

hWnd:消息所属的窗口。我们通常开发的程序都是窗口应用程序,一个消息一般都是与某个窗口相关联的。例如,在某个活动窗口中按下鼠标左键,产生的按键消息就是发给该窗口的。
message:消息的标识符,是由一个数值来表示的,不同的消息对应不同的数值。Windows将消息对应的数值定义为WM_XXX宏(WM是Windows Message的缩写)的形式, XXX对应某种消息的英文拼写的大写形式。例如,鼠标左键按下消息是WM_LBUTTONDOWN,键盘按下消息是WM_KEYDOWN,字符消息是 WM_CHAR……。
wParam: 指定消息的附加信息,如键盘按下会触发WM_KEYDOWN消息,但是,具体按下哪个按键需要wParam区分。
lParam:指定消息的附加信息,如鼠标左击会触发WM_LBUTTONDOWN消息,但是,具体点击的坐标需要lParam区分。

取消息

要从消息队列中取出消息,我们需要调用GetMessage()函数,该函数的原型声明如下:

BOOL GetMessage(
	LPMSG lpMsg,
	HWND hWnd,
	UINT wMsgFilterMin,
	UINT wMsgFilterMax);

参数说明:
lpMsg:指向一个消息结构体(MSG),GetMessage从线程的消息队列中取出的消息信息将保存在该结构体变量中。
hWnd:指定接收属于哪一个窗口的消息。通常我们将其设置为NULL,用于接收属于调用线程的所有窗口的窗口消息。
wMsgFilterMin:指定消息的最小值。
wMsgFilterMax:指定消息的最大值。如果wMsgFilterMin和wMsgFilterMax都设置为0, 则接收所有消息。
返回值说明:GetMessage函数接收到除 WM_QUIT 外的消息均返回非零值。对于WM_QUIT消息,该函数返回零。如果出现了错误,该函数返回-1,例如,当参数hWnd是无效的窗口句柄或lpMsg是无效的指针时。

建立消息循环

MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

TranslateMessage:用于翻译、处理和转换消息并把新消息投放到消息队列中,并且此过程不会影响原来的消息队列。
DispatechMessage:用于把收到的消息传到窗口回调函数进行分析和处理。即将消息传递给操作系统,让操作系统调用窗口回调函数,来对信息进行处理。

窗口过程函数

//回调函数

LRESULT Wndproc(
	HWND unnamedParam1, //消息所属的窗口句柄
	UINT unnamedParam2, //具体消息名称  WM_XXXX
	WPARAM unnamedParam3, //附加信息,如键盘附加消息
	LPARAM unnamedParam4  //附加信息,如鼠标附加消息
)
{	//6.处理消息(窗口过程)
	switch (unnamedParam2)
	{
	case WM_CLOSE:
		DestroyWindow(unnamedParam1); //发送另一个消息WM_DESTROY
		break;
	case WM_DESTROY:
		PostQuitMessage(0);  //导致 if (GetMessage(&msg, NULL, 0, 0) == 0),退出进程
		break;
	case WM_LBUTTONDOWN:
	{
		int x = LOWORD(unnamedParam4);
		int y = HIWORD(unnamedParam4);
		char buf[1024];
		wsprintf(buf, TEXT("x = %d , y = %d"), x, y);
		MessageBox(unnamedParam1, buf, TEXT("这是一个弹出标题"), MB_OKCANCEL);
		break;
	}
	case WM_KEYDOWN:
		MessageBox(unnamedParam1, TEXT("键盘按下"), TEXT("这是一个弹出标题"), MB_OKCANCEL);
		break;
	case WM_PAINT:
	{
		PAINTSTRUCT ps;//绘图的结构体 ,相当于painterevent
		HDC hdc = BeginPaint(unnamedParam1, &ps);
		//绘图
		TextOut(hdc, 100, 100, TEXT("hello"), strlen("hello"));
		EndPaint(unnamedParam1, &ps);
		break;
	}
		
	}
	//返回值用默认处理方式
	return DefWindowProcW(unnamedParam1, unnamedParam2, unnamedParam3, unnamedParam4);
}

第一个MFC程序(CWinApp、CFrameWnd)

程序执行流程

①程序开始时,先实例化应用程序对象(有且只有一个)
②执行程序的入口函数InitInstance()
③给框架类MyFrame对象动态分配空间(自动调用它的构造函数),在其构造函数内部,通过CWnd::Create创建窗口
④框架类对象显示窗口CWnd::ShowWindow
⑤框架类对象更新窗口CWnd::UpdateWindow
⑥保存框架类对象指针CWinThread::m_pMainWnd

CWinApp应用程序类

MFC应用程序的核心就是基于CWinApp类的应用程序对象。CWinApp提供了消息循环来检索消息并将消息调度给应用程序窗口。它还包括可被覆盖的、用来自定义应用程序行为的主要虚函数。

一个MFC程序可以有且仅有一个应用程序对象,此对象必须声明为在全局范围内有效,以便它在程序开始时即在内存中被实例化。

class MyApp : public CWinApp //应用程序类
{
public:
	virtual BOOL InitInstance();

private:

};
MyApp myapp; //创建一个全局应用程序对象,有且只有一个

BOOL MyApp::InitInstance()
{
	//创建窗口
	MyFrame* myframe = new MyFrame;
	//显示和更新
	myframe->ShowWindow(SW_SHOWNORMAL);
	myframe->UpdateWindow();
	m_pMainWnd = myframe; //保存指向应用程序主窗口的指针
	return TRUE;
}

在CWinApp中有一个名为CWinThread::m_pMainWnd的成员变量。 该变量是一个CWnd类型的指针,它保存了应用程序框架窗口对象的指针。也就是说,是指向CFramWnd对象(框架窗口类对象)的指针。

消息映射

在CWinApp中有一个名为CWinThread::m_pMainWnd的成员变量。 该变量是一个CWnd类型的指针,它保存了应用程序框架窗口对象的指针。也就是说,是指向CFramWnd对象(框架窗口类对象)的指针。

下面是是将消息映射添加到一个类中所做的全部工作:

  1. 所操作类中,声明消息映射宏。DECLARE_MESSAGE_MAP()
  2. 通过放置标识消息的宏来执行消息映射,相应的类将在对BEGIN_MESSAGE_MAP和END_MESSAGE_MAP的调用之间处理消息。

CFrameWnd是从CWnd(窗口基类)派生出来的。CFrameWnd模仿框架窗口行为,我们可以把框架窗口作为顶层窗口看待,它是应用程序与外部世界的主要接口。

BEGIN_MESSAGE_MAP(YourClass, BaseClass)
// 消息映射条目
END_MESSAGE_MAP()
YourClass:这是你正在为其定义消息映射的类名。
BaseClass:这是 YourClass 的基类。消息映射机制支持从基类继承消息处理。
消息映射条目:这些是具体的消息处理条目,定义了特定消息和响应这些消息的成员函数之间的映射。

class MyFrame : public CFrameWnd  //窗口框架类
{
public:
	MyFrame();

	//想在此窗口中有消息映射机制,提供一个声明宏
	DECLARE_MESSAGE_MAP()
	afx_msg void OnLButtonDown(UINT, CPoint);//槽函数声明  鼠标
	afx_msg void OnChar(UINT, UINT, UINT); //键盘
	afx_msg void OnPaint();//绘画
};
MyFrame::MyFrame()
{
	CFrameWnd::Create(NULL, TEXT("mfc的窗口"));
}

消息映射条目指定了当接收到特定的 Windows 消息时应该调用哪个成员函数。它们通常使用 ON_WM_ 前缀的宏来定义

//分界宏
BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)
	ON_WM_LBUTTONDOWN() //鼠标左键按下,相当于信号
	ON_WM_CHAR() //键盘按下
	ON_WM_PAINT() //绘画

END_MESSAGE_MAP()

unicode字符集介绍

多字节字符集(8位的ANSI字符集)

在Windows98以及以前的版本使用8位ANSI字符集,它类似于我们程序员熟悉的ASCII字符集。

char sz[] = "ABCDEFG";
char *psz = "ABCDEFG";

宽字符集(16位的Unicode字符集)

在WindowsNT和Windows2000后开始使用16位的Unicode字符集,它是ANSI字符集的一个超集。Unicode适用于国际市场销售的应用程序,因为它包含各种各样来自非U.S.字母表的字符,比如中文,日文,韩文,西欧语言等。

//在字符串前加字母L表示将ANSI字符集转换成Unicode字符集。
wchar_t wsz[] = L"ABCDEFG"; 
wchar_t *pwsz = L"ABCDEFG";
int len = wcslen(wsz); //测试宽字节字符串的长度

TEXT(_T)宏

MFC中的TEXT宏可以自动适应字符类型,如果定义了预处理器程序符号_UNICODE,那么编译器将使用Unicode字符,如果没用定义该预处理器程序符号,那么编译器将使用ANSI字符。

MessageBox(TEXT("鼠标左键"));
MessageBox(_T("鼠标左键"));

TCHAR类型

如果定义了_UNICODE符号TCHAR将变为wchar_t类型。如果没用定义_UNICODE符号,TCHAR将变为普通古老的char类型。

LPCTSTR、CString、char* 和 String 是在 C++ 和特别是在 Windows 编程中常用的字符串类型,它们各自有不同的特点和用途

1. LPCTSTR:

全称:Long Pointer to a Constant TCHAR String。
用途:LPCTSTR 是一个指向常量 TCHAR 字符串的指针。在 Windows API 中广泛使用。
与 Unicode 的关系:TCHAR 类型是一个依据 Unicode 设置变化的字符类型。如果定义了 Unicode (_UNICODE 宏),TCHAR 是 wchar_t(宽字符)的别名;如果没有定义 Unicode,TCHAR 是 char 的别名。因此,LPCTSTR 可以是 const char* 或 const wchar_t*,这取决于编译器的 Unicode 设置。
CString 的构造函数可以接受 LPCTSTR。
LPCTSTR 转 std::string
需要先将 LPCTSTR 转换为 CString,然后再转换为 std::string
在这里插入图片描述

2. CString:

用途:CString 是 MFC(Microsoft Foundation Classes)库中的一个类,用于处理字符串。
特点:CString 可以自动管理内存,简化了字符串操作(如连接、比较、分割等)。它能够根据 Unicode 设置自动处理宽字符和窄字符问题。
与 LPCTSTR 的关系:CString 提供了转换操作符,可以轻松地转换为 LPCTSTR,这使得它可以直接用在需要 LPCTSTR 参数的 Windows API 调用中。
MessageBox可以直接使用CString类型当参数
CString 转 char*
在这里插入图片描述
CString 转 std::string
在这里插入图片描述

你需要获取 CString 的 ANSI 版本,使用 GetBuffer 方法或者通过 CStringA。
CString cstr = _T("Example");
CStringA cstra(cstr);
const char* charStr = cstra.GetBuffer();

3. char*:

用途:char* 是指向字符的指针,在 C 和 C++ 中被用来表示 C 风格的字符串。
特点:它表示一个字符数组,通常以空字符(‘\0’)结束。手动管理这种字符串的内存可能比较复杂,需要注意内存分配和释放。
与 Unicode 的关系:char* 用于 ANSI 字符集。对于 Unicode 支持,通常需要使用 wchar_t*(宽字符指针)。
可以直接使用 CString 的构造函数。

4. String:

用途:在 C++ 标准库(STL)中,std::string 是一个类,用于表示字符串。
特点:与 CString 类似,std::string 也管理其自身的内存,使字符串操作更加容易和安全。
与 Unicode 的关系:std::string 通常用于处理 ANSI 字符集。对于 Unicode,标准库提供了 std::wstring(宽字符串版本)。
std::string 转 CString
MFC项目训练_第2张图片
std::string 转 char*
在这里插入图片描述
std::string 转 LPCTSTR
先转换为 CString,然后直接转换
在这里插入图片描述

用向导生成一个MFC应用程序

在VS中选择“文件” – “新建” – “项目”:
选择 MFC – MFC应用程序,接下来我们创建一个单文档MFC标准类型应用程序。
一路按默认值next,到最后一个页面:

MFC自动为我们生成了四个类,它们的继承关系如下:
MFC项目训练_第3张图片

MFC应用程序几个重要函数的介绍

InitInstance函数

应用程序类的一个虚函数,MFC应用程序的入口。

PreCreateWindow函数

当框架调用CreateEx函数创建窗口时,会首先调用PreCreateWindow函数。
通过修改传递给PreCreateWindow的结构体类型参数CREATESTRUCT,应用程序可以更改用于创建窗口的属性。在产生窗口之前让程序员有机会修改窗口的外观。
最后再调用CreateWindowEx函数完成窗口的创建。

OnCreate

OnCreate是一个消息响应函数,是响应WM_CREATE消息的一个函数,而WM_CREATE消息是由Create函数调用的。一个窗口创建(Create)之后,会向操作系统发送WM_CREATE消息,OnCreate()函数主要是用来响应此消息的。

OnCreate与Create的区别:
Create()负责注册并产生窗口,像动态创建控件中的Create()一样,窗口创建之后会向操作系统发送WM_CREATE消息。
OnCreate()不产生窗口,只是在窗口显示前设置窗口的属性如风格、位置等。
OnCreate()是消息WM_CREATE的消息响应函数。

OnDraw和OnPaint

OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw,一般来说,用户自己的绘图代码应放在OnDraw中。
OnPaint()是CWnd的类成员,负责响应WM_PAINT消息。
OnDraw()是CView的成员函数,没有响应消息的功能。

当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows发送WM_PAINT消息。该视图的OnPaint 处理函数通过创建CPaintDC类的DC对象来响应该消息并调用视图的OnDraw成员函数。OnPaint最后也要调用OnDraw,因此一般在OnDraw函数中进行绘制。
通常我们不必编写OnPaint处理函数。但在View类里添加了消息处理OnPaint()时,OnPaint()就会覆盖掉OnDraw()。

事件的添加和删除

消息处理的添加

在主框架类中添加WM_LBUTTONDOWN消息的响应函数,具体操作如下:
MFC项目训练_第4张图片

工程文件增加几处改变:

第一处:在框架类头文件中添加了鼠标左键消息函数的函数声明
MFC项目训练_第5张图片
第二处:在框架类cpp文件中添加了消息映射宏
MFC项目训练_第6张图片
第三处:在框架列cpp文件中添加了处理鼠标左键消息的函数定义
MFC项目训练_第7张图片
我们在此OnLButtonDown函数中添加一个MessageBox消息,鼠标左键按下弹出一个提示框,然后执行程序。我们会惊奇的发现程序并未如我们所愿弹出消息框。
因为,框架窗口是视窗口的父窗口,那么视类窗口就应该始终覆盖在框架类窗口之上。就好比框架窗口是一面墙,视类窗口就是墙纸,它始终挡在这面墙前边。也就是说,所有操作,包括鼠标单击、鼠标移动等操作都只能有视类窗口捕获。

基于对话框编程

对话框是一种特殊类型的窗口,绝大多数Windows程序都通过对话框与用户进行交互。在Visual C++中,对话框既可以单独组成一个简单的应用程序,又可以成为文档/视图结构程序的资源。
在类视图中,可以看到生成了3 个类:CAboutDlg、CDialogApp和CDialogDlg。
MFC项目训练_第8张图片
CAboutDlg:对应生成的版本信息对话框。
CDialogApp:应用程序类,从 CWinApp 继承过来,封装了初始化、运行、终止该程序的代码。
CDialogDlg:对话框类,从CdialogEx继承过来的,在程序运行时看到的对话框就是它的一个具体对象。
DoDataExchange函数:该函数主要完成对话框数据的交换和校验。
OnInitDialog函数:相当于对对话框进行初始化处理。

对话框(模态和非模态)

当模态对话框显示时,程序会暂停执行,直到关闭这个模态对话框之后,才能执行程序中的其他任务。
MFC项目训练_第9张图片

当非模态对话框显示时,运行转而执行程序中的其他任务,而不用关闭这个对话框。
非模态对话框实现方式不一样,先创建(CDialog::Create)一次,然后再显示(CWnd::ShowWindow)。
MFC项目训练_第10张图片
非模态的对话框没有阻塞功能,因此如果用创建局部变量的方法创建,函数会自动执行并销毁该对话框。所以要么new一个非模态对话框,要么在主对话框头文件声明一个。
MFC项目训练_第11张图片

常用控件的使用

静态文本框static text

静态文本框是最简单的控件,它主要用来显示文本信息,不能接受用户输入,一般不需要连接变量,也不需要处理消息。
静态文本框的重要属性有:
ID:所有静态文本框的缺省ID都是IDC_STATIC,静态ID,不响应任何消息(事件)
Caption:修改显示的内容

常用接口:
CWnd::SetWindowText 设置控件内容
CWnd::GetWindowText 获取控件内容
CStatic::SetBitmap 设置位图(后缀为bmp的图片)

接口 功能
CWnd::SetWindowText 设置控件内容
CWnd::GetWindowText 获取控件内容
CStatic::SetBitmap 设置位图(后缀为bmp的图片)
//设置静态控件内容为Tom
	m_label.SetWindowText(TEXT("Tom"));

	//获取静态控件的内容
	CString str;
	m_label.GetWindowText(str);
	MessageBox(str);

	m_img.ModifyStyle(0x1, SS_BITMAP | SS_CENTERIMAGE);
#define HBMP(filepath, width, height) (HBITMAP)LoadImage(AfxGetInstanceHandle(), filepath, IMAGE_BITMAP, width, height, LR_LOADFROMFILE | LR_CREATEDIBSECTION)
	//宽高设置按照空间的大小设置
	CRect rect;
	m_img.GetWindowRect(rect);
	m_img.SetBitmap(HBMP(TEXT("./image/1.bmp"), rect.Width(),rect.Height()));

按钮Button

按钮是最常见的、应用最广泛的一种控件。在程序执行期间,当单击某个按钮后就会执行相应的消息处理函数。
按钮的主要属性是Caption,来设置在按钮上显示的文本。
命令按钮处理的最多的消息是:BN_CLICKED,双击按钮即可跳转到处理函数。
常用接口:

接口 功能
CWnd::SetWindowTex 设置控件内容
CWnd::GetWindowText 获取控件内容
CWnd::EnableWindow 设置控件是否变灰

编辑框Edit

常用属性设置:
MFC项目训练_第12张图片
常用接口:

接口 功能
CWnd::SetWindowTex 设置控件内容
CWnd::GetWindowText 获取控件内容

关联基础变量类型

若一个编辑框连接了一个Value类别的变量,则该变量就表示这个编辑框,编辑框中显示的内容就是变量的值。
MFC项目训练_第13张图片
但是,改变了编辑框的内容并不会自动更新对应的变量的值,同样,改变了变量的值也不会自动刷新编辑框的内容。若要保持一致,需要使用UpdateData()函数更新:
若编辑框的内容改变了,则应使用语句UpdateData(TRUE) 获取对话框数据。
若变量的值改变了,则应使用语句UpdateData(FALSE) 初始化对话框控件。

组合框(下拉框)CComboBox

MFC项目训练_第14张图片
下拉列表可以使用户不可以更改下拉框中的内容

接口 功能
CComboBox::AddString 组合框添加一个字符串
CComboBox::SetCurSel 设置当前选择项(当前显示第几项),下标从0开始
CComboBox::GetCurSel 获取组合框中当前选中项的下标
CComboBox::GetLBText 获取指定位置的内容
CComboBox::DeleteString 删除指定位置的字符串
CComboBox::InsertString 在指定位置插入字符串
//添加字符串内容
	m_combo.AddString(TEXT("可乐")); 
	m_combo.AddString(TEXT("雪碧"));

	m_combo.SetCurSel(1);//显示显示第1项

	//获取组合框中当前选中项的下标
	int index = m_combo.GetCurSel(); 
	CString str;
	m_combo.GetLBText(index, str); //获取指定下标的内容
	MessageBox(str);

	m_combo.DeleteString(0); //删除第0项字符串
	
	m_combo.InsertString(0, _T("hello")); //在第0位置插入“hello”

组合框常用的事件为:CBN_SELCHANGE,当选择组合框某一项时,自动触发此事件。
MFC项目训练_第15张图片

列表视图控件 ListCtrl

常用接口:

接口 功能
CListCtrl::SetExtendedStyle 设置列表风格
CListCtrl::GetExtendedStylel 获取列表风格
CListCtrl::InsertColumn 插入某列内容,主要用于设置标题
CListCtrl::InsertItem 在某行插入新项内容
CListCtrl::SetItemText 设置某行某列的子项内容
CListCtrl::GetItemText 获取某行某列的内容
	//设置风格样式
	//LVS_EX_GRIDLINES 网格
	//LVS_EX_FULLROWSELECT 选中整行
	m_list.SetExtendedStyle(m_list.GetExtendedStyle()
		| LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);

	//插入标题
	CString head[] = { TEXT("姓名"), TEXT("年龄"), TEXT("性别") };

	//插入列
	m_list.InsertColumn(0, head[0], LVCFMT_LEFT, 100);
	m_list.InsertColumn(1, head[1], LVCFMT_LEFT, 100);
	m_list.InsertColumn(2, head[2], LVCFMT_LEFT, 100);

	//插入正文内容,先确定行,再确定列
	for (int i = 0; i < 10; i++)
	{
		CString str;
		str.Format(TEXT("张三_%d"), i );

		//确定行
		m_list.InsertItem(i, str);

		//设置列
		int j = 0;
		m_list.SetItemText(i, ++j, TEXT("男"));
		m_list.SetItemText(i, ++j, TEXT("23"));
	}

树视图控件 TreeCtrl

MFC项目训练_第16张图片
常用接口:

接口 功能
AfxGetApp() 获取应用程序对象指针
CWinApp::LoadIcon 加载自定义图标
CImageList::Create 创建图像列表
CImageList::Add 图像列表追加图标
CTreeCtrl::SetImageList 设置图形状态列表
CTreeCtrl::InsertItem 插入节点
CTreeCtrl::SelectItem 设置默认选中项
CTreeCtrl::GetSelectedItem 获取选中项
CTreeCtrl::GetItemText 获取某项内容

添加图标资源(icon)

把ico资源文件放在项目res文件夹中

MFC项目训练_第17张图片

资源视图 -> Icon -> 添加资源
导入ico文件

MFC项目训练_第18张图片
MFC项目训练_第19张图片

通过代码加载图标
//加载图标
	HICON icon[3];
	icon[0] = AfxGetApp()->LoadIconW(IDI_ICON1);
	icon[1] = AfxGetApp()->LoadIconW(IDI_ICON2);
	icon[2] = AfxGetApp()->LoadIconW(IDI_ICON3);
创建图像列表

.h 文件类中定义图形列表(CImageList)对象

CImageList m_imageList; //图像列表

OnInitDialog()函数中完成图像列表的创建、图标的追加

//图像列表,程序完毕不能释放 
	//创建
	//30, 30: 图片的宽度和高度
	//ILC_COLOR32:样式
	// 3, 3: 有多少图片写多少
	m_imageList.Create(30, 30, ILC_COLOR32, 3, 3);
	//给图像列表添加图片
	for (int i = 0; i < 3; i++)
	{
		//图片列表加载图标
		m_imageList.Add(icon[i]);
	}

树控件的相应操作

//树控件设置图片列表
	m_treeCtrl.SetImageList(&m_imageList, TVSIL_NORMAL);
	//给树创建节点
	//根节点,父节点,子节点
	//添加节点
	HTREEITEM root = m_treeCtrl.InsertItem(TEXT("根节点"), 0, 0, NULL);
	HTREEITEM parent = m_treeCtrl.InsertItem(TEXT("父节点"), 1, 1, root);
	HTREEITEM sub1 = m_treeCtrl.InsertItem(TEXT("子节点1"), 2, 2, parent);
	HTREEITEM sub2 = m_treeCtrl.InsertItem(TEXT("子节点2"), 3, 3, parent);
	//设置某个节点被选中
	m_treeCtrl.SelectItem(fathter);

标签控件 CTabCtrl

MFC项目训练_第20张图片
MFC项目训练_第21张图片

添加对话框:资源视图 -> Dialog -> 右击 -> 插入 Dialog
设置相应属性

MFC项目训练_第22张图片
样式:child

添加MFC类

MFC项目训练_第23张图片

主对话框类中, 定义自定义MFC类对象,需要相应头文件

MFC项目训练_第24张图片

主对话框类中 OnInitDialog() 做初始化工作
//给tab控件添加对话框
//IDD_DIALOG1为dlg1资源ID
	m_tabCtrl.AddPage(TEXT("系统管理"), &dlg1, IDD_DIALOG1); 
//IDD_DIALOG1为dlg2资源ID
	m_tabCtrl.AddPage(TEXT("系统设置"), &dlg2, IDD_DIALOG2); 
//显示tab控件
	m_tabCtrl.Show();

MFC项目训练_第25张图片

综合案例:销售信息管理系统

你可能感兴趣的:(MFC项目训练实战,mfc,c++)