MFC学习笔记——07-MFC_18day
在学习MFC总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
07-MFC_18day
目录:
一、课程安排
二、编程总结
三、Win消息机制、SDK编程基础
1、Windows 编程模型
2、底层实现窗口的6步骤
3、利用MFC创建窗口
4、MFC消息映射机制
5、Windows字符集介绍
6、利用向导创建MFC
四、总结
一、课程安排
第一天(Win消息机制、SDK编程基础):
1、基本概念介绍(SDK、API、句柄、消息队列、WinMain函数)
2、第一个Windows界面程序(WinAPI)
3、消息循环和窗口过程函数
4、第一个MFC程序(CWinApp、CFrameWnd)
5、消息映射
6、unicode字符集介绍
7、根据向导创建MFC应用程序
8、MFC应用程序几个重要函数的介绍
9、事件的添加和删除
第二天(对话框、常用控件、文档和视图):
1、对话框(模态和非模态)
2、常用控件的使用
a)按钮CButton
b)编辑框CEdit
c)组合框(下拉框)CComboBox
d)列表视图控件 CListCtrl
e)树视图控件 CTreeCtrl
f)标签控件 CTabCtrl
第三天(综合案例:销售信息管理系统)
二、编程总结
编程环境:VS2015
1、代码自动对齐:Ctrl + a—》Ctrl + k—》Ctrl + f;
visual assist x是一款非常好用的Microsoft Visual Studio插件,它可以完全集成到您的Microsoft开发环境中,升级了您的IDE,在不改变编程习惯的同时就可以感受到Visual Assist X为您带来的好处。软件支持Microsoft Visual Studio 2003-2017,C/C++,C#,ASP,VisualBasic,Java和HTML等语言,能自动识别各种关键字、系统函数、成员变量、自动给出输入提示、自动更正大小写错误、自动标示错误等。使用Visual Assist X能够非常有助于提高用户开发过程的自动化和开发效率。
visual assist x破解版:网盘链接:https://pan.baidu.com/s/1FtpBsVgAjbRmgPhABY47xQ 密码:3qov
破解教程:
软件下载解压完成后,点击VA_X_Setup2223打开软件安装包,软件会自动识别你电脑中的Microsoft Visual Studio版本,点击Install开始安装软件。
2、VS中报错:error C2143:语法错误:缺少“:”(在“类型”的前面)
原因:VS C语言编程Issue,在switch的case的条件判断后 执行语句过多,会发生这个问题,所以需要把这些执行语句整体加个{}或编程一个函数整体。
三、Win消息机制、SDK编程基础
为什么学习MFC?
如果你是在Windows平台上做GUI开发,MFC(微软基础类库)是一个很好的选择,毕竟Windows累积用户群庞大,市场接受程度高。
基本概念解释
我们在编写标准C程序的时候,经常会调用各种库函数来辅助完成某些功能:初学者使用得最多的C库函数就是printf了,这些库函数是由你所使用的编译器厂商提供的。在Windows平台下,也有类似的函数可供调用:不同的是,这些函数是由Windows操作系统本身提供的。
1) SDK和API
SDK: 软件开发工具包(Software Development Kit),一般都是一些被软件工程师用于为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件的开发工具的集合。
API函数: Windows操作系统提供给应用程序编程的接口(Application Programming Interface)。
Windows应用程序API函数是通过C语言实现的,所有主要的 Windows 函数都在 Windows.h 头文件中进行了声明。Windows 操作系统提供了 1000 多种 API函数。
2) 窗口和句柄
窗口是 Windows 应用程序中一个非常重要的元素,一个 Windows 应用程序至少要有一个窗口,称为主窗口。
窗口是屏幕上的一块矩形区域,是 Windows 应用程序与用户进行交互的接口。利用窗口可以接收用户的输入、以及显示输出。
一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、 可调边框,有的还有滚动条。
窗口可以分为客户区和非客户区, 如上图。 客户区是窗口的一部分, 应用程序通常在客户区中显示文字或者绘制图形。
标题栏、 菜单栏、 系统菜单、 最小化框和最大化框、 可调边框统称为窗口的非客户区, 它们由 Windows 系统来管理, 而应用程序则主要管理客户区的外观及操作。
窗口可以有一个父窗口, 有父窗口的窗口称为子窗口。除了上图所示类型的窗口外, 对话框和消息框也是一种窗口。 在对话框上通常还包含许多子窗口, 这些子窗口的形式有按钮、 单选按钮、 复选框、 组框、 文本编辑框等。
在 Windows 应用程序中, 窗口是通过窗口句柄( HWND) 来标识的。 我们要对某个窗口进行操作, 首先就要得到这个窗口的句柄。
句柄( HANDLE) 是 Windows 程序中一个重要的概念, 使用也非常频繁。 在 Windows 程序中, 有各种各样的资源( 窗口、 图标、光标,画刷等), 系统在创建这些资源时会为它们分配内存, 并返回标识这些资源的标识号, 即句柄。 在后面的内容中我们还会看到图标句柄( HICON)、 光标句柄( HCURSOR) 和画刷句柄( HBRUSH)。
3) 消息与消息队列
Windows 程序设计是一种完全不同于传统的 DOS 方式的程序设计方法。它是一种事件驱动方式的程序设计模式,主要是基于消息的。
每一个 Windows 应用程序开始执行后, 系统都会为该程序创建一个消息队列, 这个消息队列用来存放该程序创建的窗口的消息。
例如,当用户在窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到这一事件,于是将这个事件包装成一个消息,投递到应用程序的消息队列中,等待应用程序的处理。
然后应用程序通过一个消息循环不断地从消息队列中取出消息,并进行响应。
在这个处理过程中,操作系统也会给应用程序“ 发送消息”。所谓“ 发送消息”,实际上是操作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程。
4) WinMain函数
当Windows操作系统启动一个程序时,它调用的就是该程序的WinMain函数( 实际是由插入到可执行文件中的启动代码调用的)。 WinMain是Windows程序的入口点函数,与DOS程序的入口点函数main的作用相同,当WinMain 函数结束或返回时,Windows应用程序结束。
1、Windows 编程模型
一个完整的Win32程序(#include <windows.h>),该程序实现的功能是创建一个窗口,并在该窗口中响应键盘及鼠标消息,程序的实现步骤为:
1)WinMain函数的定义
2)创建一个窗口
3)进行消息循环
4)编写窗口过程函数
2、底层实现窗口的6步骤
1 #include <windows.h> //底层实现窗口头文件 2 3 // 6、处理消息(窗口过程) 4 // CALLBACK 代表 __stdcall 参数传递顺序 从右往左 依次入栈 ,并且在函数返回前自动清空 堆栈内容 5 // WindowProc的名字要和(1、设计窗口)wc.lpfnWndProc = WindowProc的名字相同 6 LRESULT CALLBACK WindowProc( 7 HWND hwnd, //消息所属窗口句柄 8 UINT uMsg, // 具体消息名称 WM_XXX 9 WPARAM wParam, // 键盘附加消息 10 LPARAM lParam //鼠标附加消息 11 ) 12 { 13 14 switch (uMsg) 15 { 16 case WM_CLOSE: 17 DestroyWindow(hwnd); //触发 WM_DESTROY 约定俗成一个事情: 函数名 xxxWindow消息,不会放到消息队列中,而是直接执行 18 break; 19 case WM_DESTROY: 20 PostQuitMessage(0); //发送退出消息 21 break; 22 case WM_LBUTTONDOWN: //鼠标左键按下消息 23 { 24 int xPos; 25 int yPos; 26 xPos = LOWORD(lParam); 27 yPos = HIWORD(lParam); 28 29 //打印操作 通常同MessageBox 30 31 TCHAR buf[1024]; 32 wsprintf(buf, TEXT(" x = %d,y = %d"), xPos, yPos); 33 // 所属窗口 显示内容 标题内容 关联按键类型 34 MessageBox(hwnd, buf, TEXT("鼠标按下"), MB_OK); 35 } 36 break; 37 case WM_KEYDOWN: //键盘消息 38 39 MessageBox(hwnd, TEXT("键盘按下"), TEXT("键盘消息"), MB_OK); 40 break; 41 42 case WM_PAINT: //绘图消息 43 { 44 PAINTSTRUCT ps; //绘图结构体 45 HDC hdc = BeginPaint(hwnd, &ps); 46 //绘制文字 47 TextOut(hdc, 100, 100, TEXT("helloworld"), strlen("helloworld")); 48 EndPaint(hwnd, &ps); 49 } 50 break; 51 default: 52 break; 53 } 54 55 56 //默认方式处理 57 return DefWindowProc(hwnd, uMsg, wParam, lParam); 58 } 59 60 61 62 // WINAPI 代表 __stdcall 参数传递顺序 从右往左 依次入栈 ,并且在函数返回前自动清空 堆栈内容 63 // WinMain函数入口 64 int WINAPI WinMain( 65 HINSTANCE hInstance, // 应用程序实例句柄 66 HINSTANCE hPrevInstance, // 前一个应用程序实例句柄,在win32环境下,基本值NULL,不起作用 67 LPSTR lpCmdLine, // char * argv[] 命令行参数数组 68 int nShowCmd) // 窗口显示命令 最大化最小化.. 69 { 70 //实现底层窗口 6步骤 71 72 // 1、设计窗口类 73 // 2、注册窗口类 74 // 3、创建窗口类 75 // 4、显示和更新窗口 76 // 5、通过循环取消息 77 // 6、处理消息(窗口过程) 78 79 80 //1、 设计窗口 81 WNDCLASS wc; 82 wc.cbClsExtra = 0; //类额外的内存 通常为0 83 wc.cbWndExtra = 0; //窗口额外的内存,通常为0 84 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //设置背景 85 wc.hCursor = LoadCursor(NULL, IDC_HAND);//设置光标 如果第一个参数为NULL,代表使用系统提供的默认光标 86 wc.hIcon = LoadIcon(NULL, IDI_WARNING); //设置图标 如果第一个参数为NULL,代表使用系统提供的默认图标 87 wc.hInstance = hInstance;//当前实例句柄,WinMain函数中形参即可 88 wc.lpfnWndProc = WindowProc; //窗口过程函数 回调函数 名称可以随机起 89 wc.lpszClassName = TEXT("WINDOW");//指定窗口类名 90 wc.lpszMenuName = NULL;//菜单名 没有填NULL 91 wc.style = 0; // 0代表默认风格 92 93 //2、 注册窗口类 94 RegisterClass(&wc); 95 96 //3、创建窗口 97 /* 98 lpClassName, 类名 99 lpWindowName, 窗口名 100 dwStyle, 显示风格 WS_OVERLAPPEDWINDOW 101 x, y,\ 创建窗口起始坐标 CW_USEDEFAULT 102 nWidth, nHeight, 创建窗口默认宽高 CW_USEDEFAULT 103 hWndParent, 父窗口 NULL 104 hMenu, 菜单 NULL 105 hInstance, 实例句柄 hInstance 106 lpParam 其他参数 NULL 107 */ 108 HWND hwnd = CreateWindow(wc.lpszClassName, TEXT("TEXT WINDOW"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); 109 110 //4、 显示和更新 111 ShowWindow(hwnd, SW_SHOWNORMAL); 112 UpdateWindow(hwnd); 113 114 115 //5、通过循环取消息 116 /* 117 HWND hwnd; //主窗口 118 UINT message; //消息名称 WM_XXXX (WINDOW MESSAGE) 119 WPARAM wParam; // 附加消息 键盘 120 LPARAM lParam; // 附加消息 鼠标 左右键 121 DWORD time; // 消息产生时间 122 POINT pt; // 附加消息 鼠标 x y坐标 123 */ 124 MSG msg; 125 126 while (GetMessage(&msg, NULL, 0, 0))//代码优化 127 { 128 /* 129 参数 130 _Out_ LPMSG lpMsg, 消息结构体 131 _In_opt_ HWND hWnd, NULL 捕获所有窗口消息 132 _In_ UINT wMsgFilterMin, 过滤最小消息数量 133 _In_ UINT wMsgFilterMax); 过滤最大消息数量 0 都写0 代表捕获所有消息 134 */ 135 //if (GetMessage(&msg, NULL, 0, 0) == FALSE) 136 //{ 137 // break; 138 //} 139 140 //翻译消息 141 TranslateMessage(&msg); 142 143 //分发消息 144 DispatchMessage(&msg); 145 146 } 147 148 149 return 0; 150 } 151 152 153 //函数入口
消息处理机制
① 操作系统接收到应用程序的窗口消息,将消息投递到该应用程序的消息队列中。
② 应用程序在消息循环中调用GetMessage函数从消息队列中取出一条一条的消息。取出消息后,应用程序可以对消息进行一些预处理,例如,放弃对某些消息的响应,或者调用TranslateMessage产生新的消息。
③ 应用程序调用DispatchMessage,将消息回传给操作系统。消息是由 MSG结构体对象来表示的,其中就包含了接收消息的窗口的句柄。因此, DispatchMessage函数总能进行正确的传递。
④ 系统利用WNDCLASS结构体的lpfnWndProc成员保存的窗口过程函数的指针调用窗口过程,对消息进行处理。
3、利用MFC创建窗口
MFC是什么?
微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是一个微软公司提供的类库(class libraries),以C++类的形式封装了Windows API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。
MFC把Windows SDK API函数包装成了几百个类,MFC给Windows操作系统提供了面向对象的接口,支持可重用性、自包含性以及其他OPP原则。MFC通过编写类来封装窗口、对话框以及其他对象,引入某些关键的虚函数(覆盖这些虚函数可以改变派生类的功能)来完成,并且MFC设计者使类库带来的总开销降到了最低。
项目的创建和之前一样,只是此次的源文件后缀为.cpp,因为MFC是由C++编写的,编写MFC程序需要包含#include <afxwin.h>头文件。
注意:要配置环境(项目鼠标右键,在项目属性页,选择“常规”——》“MFC的使用”后选择“在共享DLL中使用MFC”)
程序执行流程
① 程序开始时,先实例化应用程序对象(有且只有一个)
② 执行程序的入口函数InitInstance()
③ 给框架类MyFrame对象动态分配空间(自动调用它的构造函数),在其构造函数内部,通过CWnd::Create创建窗口
④ 框架类对象显示窗口CWnd::ShowWindow
⑤ 框架类对象更新窗口CWnd::UpdateWindow
⑥ 保存框架类对象指针CWinThread::m_pMainWnd
4、MFC消息映射机制
消息映射是一个将消息和成员函数相互关联的表。比如,框架窗口接收到一个鼠标左击消息,MFC将搜索该窗口的消息映射,如果存在一个处理WM_LBUTTONDOWN消息的处理程序,然后就调用OnLButtonDown。
下面是是将消息映射添加到一个类中所做的全部工作:
1)所操作类中,声明消息映射宏。
2)通过放置标识消息的宏来执行消息映射,相应的类将在对BEGIN_MESSAGE_MAP和END_MESSAGE_MAP的调用之间处理消息。
3)对应消息处理函数分别在类中声明,类外定义:
帮助文档的使用
1) MSDN的使用
2) VC++之MFC类库中文手册
通过此手册查找,必须加上成员所属的类作用域(类名::),否则,无法查找到匹配的关键字。
5、Windows字符集介绍
Widnows字符集
1) 多字节字符集(8位的ANSI字符集)
在Windows98以及以前的版本使用8位ANSI字符集,它类似于我们程序员熟悉的ASCII字符集。
char sz[] = "ABCDEFG";
char *psz = "ABCDEFG";
int len = strlen(sz);
2) 宽字符集(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); //测试宽字节字符串的长度
3) TEXT(_T)宏
MFC中的TEXT宏可以自动适应字符类型,如果定义了预处理器程序符号_UNICODE,那么编译器将使用Unicode字符,如果没用定义该预处理器程序符号,那么编译器将使用ANSI字符。
MessageBox(TEXT("鼠标左键"));
MessageBox(_T("鼠标左键"));
4) TCHAR类型
如果定义了_UNICODE符号TCHAR将变为wchar_t类型。如果没用定义_UNICODE符号,TCHAR将变为普通古老的char类型。
练习:
mfc.h
1 #include <afxwin.h> //MFC需要包含的头文件
2
3 class MyApp :public CWinApp //CWinApp 应用程序类
4 {
5 public:
6
7 //MFC 程序入口
8 virtual BOOL InitInstance();
9
10 };
11
12 //窗口框架类
13 class MyFrame :public CFrameWnd
14 {
15 public:
16 MyFrame(); //窗口构造函数
17
18 //使用消息映射机制 必须引用声明宏
19
20 DECLARE_MESSAGE_MAP()
21
22 afx_msg void OnLButtonDown(UINT, CPoint); //鼠标左键按下声明
23
24 afx_msg void OnChar(UINT, UINT, UINT); // 键盘函数声明
25
26 afx_msg void OnPaint(); //绘图声明
27
28 };
mfc.cpp
1 #include "mfc.h"
2
3 MyApp app; //应用程序对象 ,有且仅有一个
4
5 BOOL MyApp::InitInstance()
6 {
7 //创建窗口
8 m_pMainWnd = new MyFrame;
9
10
11 //显示 和 更新
12 m_pMainWnd->ShowWindow(SW_SHOWNORMAL);
13 m_pMainWnd->UpdateWindow();
14
15 //m_pMainWnd = frame;//保存指向应用程序的主窗口的指针
16
17 return TRUE; //返回正常初始化
18 }
19
20
21 //消息映射的 分界宏
22 BEGIN_MESSAGE_MAP(MyFrame,CFrameWnd)
23
24 ON_WM_LBUTTONDOWN() //鼠标左键按下 宏
25
26 ON_WM_CHAR() //键盘宏
27
28 ON_WM_PAINT() //绘图宏
29
30 END_MESSAGE_MAP()
31
32
33
34 //窗口框架的默认构造函数
35 MyFrame::MyFrame()
36 {
37 Create(NULL, TEXT("MFC WINDOW"));
38 }
39
40 //鼠标左键按下 实现
41 void MyFrame::OnLButtonDown(UINT, CPoint point)
42 {
43
44 //TCHAR buf[1024];
45 //wsprintf(buf, TEXT("x = %d, y = %d"), point.x, point.y);
46 //MessageBox(buf);
47
48 CString str; //MFC使用的字符串
49 //格式化字符串
50 str.Format(TEXT(" :::::x = %d, y = %d"), point.x, point.y);
51
52 MessageBox(str);
53
54 }
55
56 //键盘实现
57 void MyFrame::OnChar(UINT key, UINT, UINT)
58 {
59 //TCHAR buf[1024];
60 //wsprintf(buf, TEXT("按下了%c"), key);
61 //MessageBox(buf);
62
63
64 CString str;
65 str.Format(TEXT("按下了%c 键"),key);
66 MessageBox(str);
67
68 }
69
70 void MyFrame::OnPaint()
71 {
72 CPaintDC dc(this); //画家 画到当前的窗口中
73
74 //画文字
75 dc.TextOutW(100, 100, TEXT("为了部落"));
76
77 dc.Ellipse(10, 10, 100, 100);
78
79 // 多字节 转 宽字节
80 //MessageBox(L"aaa");
81 MessageBox(TEXT("aaa"));
82
83 //TEXT TCHAR 自动编码转换
84
85 //统计宽字节字符串长度
86 char * p = "aaaa";
87 int n = 0;
88 n = strlen(p);
89
90 wchar_t * p2 = L"bbbb";
91 n = wcslen(p2);
92
93
94 //string 互相转换 char * -> .c_str();<- 构造
95 //CString 和char * 互相转换
96 //char * -> CString
97 char * p3 = "aa";
98 CString str = CString(p3);//构造
99
100 //CString -> char*
101 CString str2 = TEXT("abc");
102 CStringA tmp;
103 tmp =