MFC项目训练

目录

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 应用程序与用户进行交互的接口。利用窗口可以接收用户的输入、以及显示输出。
一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、 可调边框,有的还有滚动条。
在这里插入图片描述
窗口可以有一个父窗口, 有父窗口的窗口称为子窗口。除了上图所示类型的窗口外, 对话框和消息框也是一种窗口。 在对话框上通常还包含许多子窗口, 这些子窗口的形式有按钮、 单选按钮、 复选框、 组框、 文本编辑框等。

在 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 <windows.h>),该程序实现的功能是创建一个窗口,并在该窗口中响应键盘及鼠标消息,程序的实现步骤为:

  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
在这里插入图片描述
std::string 转 char*
在这里插入图片描述
std::string 转 LPCTSTR
先转换为 CString,然后直接转换
在这里插入图片描述

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

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

MFC自动为我们生成了四个类,它们的继承关系如下:
在这里插入图片描述

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消息的响应函数,具体操作如下:
在这里插入图片描述

工程文件增加几处改变:

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

基于对话框编程

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

对话框(模态和非模态)

当模态对话框显示时,程序会暂停执行,直到关闭这个模态对话框之后,才能执行程序中的其他任务。
在这里插入图片描述

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

常用控件的使用

静态文本框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

常用属性设置:
在这里插入图片描述
常用接口:

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

关联基础变量类型

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

组合框(下拉框)CComboBox

添加数据

可以通过数据选项添加数据。
在这里插入图片描述
也可以通过添加变量,往下拉框里添加数据。
在这里插入图片描述
在OnInitDialog中添加变量初始化代码:

修改为不可修改的下拉框

在这里插入图片描述
下拉列表可以使用户不可以更改下拉框中的内容。

接口功能
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,当选择组合框某一项时,自动触发此事件。
在这里插入图片描述

列表视图控件 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

在这里插入图片描述
常用接口:

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

添加图标资源(icon)

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

在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述

通过代码加载图标
//加载图标
	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

在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述
样式:child

添加MFC类

在这里插入图片描述

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

在这里插入图片描述

主对话框类中 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();

在这里插入图片描述

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

  • 24
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值