0


MFC基础入门

1 MFC入门

1.1 为什么学习MFC

Windows

平台上做

GUI

开发,

MFC

是一个不错的选择。

学习

MFC

不仅可以学习到

MFC

本身,而且可以学习

MFC

框架的设计思想。

1.2 Windows消息机制

基本概念解释

SDK:软件开发工具包(

Software Development Kit

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

API函数:Windows操作系统提供给应用程序编程的接口。Windows应用程序API是通过C语言实现的,所有主要的Windows函数都在

Windows.h

头文件中进行了声明。Windows操作系统提供了1000多种API函数。

窗口:一个Windows应用程序至少有一个窗口,称为主窗口。窗口是屏幕上的一块矩形区域,是Windows应用程序与用户进行交互的接口。一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、可调边框,有的还有滚动条。窗口可分为客户区和非客户区。窗口可以有一个父窗口,有父窗口的称为子窗口。

在Windows应用程序中,窗口是通过窗口句柄来标识的。要对某个窗口进行操作,首先就要得到这个窗口的句柄。

句柄:在Windows程序中,有各种各样的资源(窗口、图标、光标、画刷等),系统在创建这些资源时会为它们分配内存,并返回这些资源的标识号,即句柄。例如,有图标句柄、光标句柄、画刷句柄。

消息与消息队列:Windows程序设计是一种完全不同于传统DOS方式的程序设计方法。它是一种事件驱动方式的程序设计模式,主要基于消息。

每一个Windows应用程序开始执行后,系统会为该程序创建一个消息队列,这个消息队列用来存放该程序创建的窗口的消息。

例如,用户在窗口中画图时,按下鼠标左键。此时,操作系统会感知到这一事件,于是将该事件包装成一个消息,投递到应用程序的消息队列中,等待应用程序的处理。

然后,应用程序通过一个消息循环不断从消息队列中取出消息,并进行响应。在这个处理过程中,操作系统也会给应用程序“发送消息”。所谓“发送消息”,实际上是操作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程。

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

Windows编程模型

一个简单但完整

Win32

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

  • WinMain函数的定义
int WINAPI WinMain(
    HINSTANCE hInstance,// 应用程序实例句柄
    HINSTANCE hPrevInstace,// 上一个应用程序实例,在win32环境中,默认为NULL
    LPSTR lpCmdLine,// 命令行参数 char * argv[]int nShowCmd            // 窗口显示样式)
  • 创建一个窗口
// 1.设计窗口
WNDCLASS wc;// 窗口类变量
wc.cbClsExtra =0;// 类的额外内存
wc.cbWndExtra =0;// 窗口的额外内存
wc.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);// 设置背景
wc.hCursor =LoadCursor(NULL, IDC_HAND);// 设置光标,若第一个参数为NULL,代表使用系统提供的光标
wc.hIcon =LoadIcon(NULL, IDI_ERROR);// 设置图标,若第一个参数为NULL,代表使用系统提供的光标
wc.hInstance = hInstance;// 应用程序实例句柄,为WinMain第1个形参
wc.lpfnWndProc = WinProc;// 回调函数 窗口过程函数名字
wc.lpszClassName =TEXT("MyWin");// 类的名字
wc.lpszMenuName =NULL;// 没有菜单
wc.style =0;// 显示风格,填0,使用默认风格// 2.注册窗口类RegisterClass(&wc);// 3.创建窗口
HWND  hWnd =CreateWindow(TEXT("MyWin"),TEXT("测试"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,NULL,NULL, hInstance,NULL);// 4.显示及更新ShowWindow(hWnd, SW_SHOWNORMAL);UpdateWindow(hWnd);
HWND CreateWindow(
    LPCTSTR lpClassName,//类名
    LPCTSTR lpWindowName,//标题名
    DWORD dwStyle,//指定创建的窗口的样式 WS_OVERLAPPEDWINDOWint x,//默认值 CW_USEDEFAULTint y,//指定窗口左上角的x,y坐标int nWidth,//默认值 CW_USEDEFAULTint nHeight,//指定窗口的宽度,高度
    HWND hWndParent,//指定被创建窗口的父窗口句柄
    HMENU hMenu,//指定窗口菜单的句柄
    HINSTANCE hInstance,//窗口所属的应用程序实例的句柄
    LPVOID lpParam);//通常设置为NULL
  • 建立消息循环
// 5.通过循环取消息
MSG msg;while(1){if(GetMessage(&msg,NULL,0,0)== FALSE){break;}else{TranslateMessage(&msg);//翻译DispatchMessage(&msg);//把收到的消息传到窗口回调函数进行分析和处理}}
/*
 * Message structure
 */typedefstructtagMSG{
    HWND        hwnd;//消息所属窗口
    UINT        message;//消息标识符
    WPARAM      wParam;//指定消息的附加信息
    LPARAM      lParam;//指定消息的附加信息
    DWORD       time;//标识一个消息产生时的时间
    POINT       pt;//表示产生这个消息时光标或鼠标的坐标#ifdef_MAC
    DWORD       lPrivate;#endif} MSG,*PMSG, NEAR *NPMSG, FAR *LPMSG;
BOOL GetMessage(
    LPMSG lpMsg,//指向一个消息结构体
    HWND hWnd,//指定接收哪一个窗口的消息。设置为NULL,用于接收属于调用线程的所有窗口的窗口消息
    UINT wMsgFilterMin,//指定消息的最小值
    UINT wMsgFilterMax);//指定消息的最大值//如果wMsgFilterMin和wMsgFilterMax都设置为0, 则接收所有消息。
  • 编写窗口过程函数
LRESULT CALLBACK WinProc(// CALLBACK和WINAPI 作用一样
    HWND hWnd,// 信息所属的窗口句柄
    UINT uMsg,// 消息类型
    WPARAM wParam,// 附加信息(如键盘哪个键按下)
    LPARAM lParam          // 附加信息(如鼠标点击坐标));

完整示例代码

要创建一个

win32

项目,在

VS2019

中点击Windows桌面向导

在这里插入图片描述
在这里插入图片描述
选择应用程序类型为桌面应用程序,并勾选空项目

在这里插入图片描述
注意,添加新建项是

.c

文件

在这里插入图片描述

#include<windows.h>

LRESULT CALLBACK WinProc(// CALLBACK和WINAPI 作用一样
    HWND hWnd,// 消息所属的窗口句柄
    UINT uMsg,// 具体消息名称
    WPARAM wParam,// 附加信息(如键盘哪个键按下)
    LPARAM lParam          // 附加信息(如鼠标点击坐标)){switch(uMsg){case WM_KEYDOWN://键盘按下MessageBox(hWnd,TEXT("键盘按下"),TEXT("键盘"), MB_OK);break;case WM_CLOSE://所有以Window结尾的方法不会进入到消息队列去,而是直接执行DestroyWindow(hWnd);// DestroyWindow 发送另一个消息 WM_DESTROYbreak;case WM_DESTROY:PostQuitMessage(0);break;case WM_LBUTTONDOWN://鼠标左键按下{int xPos =LOWORD(lParam);int yPos =HIWORD(lParam);char buf[1024];wsprintf(buf,TEXT("x = %d, y = %d"), xPos, yPos);MessageBox(hWnd, buf,TEXT("鼠标左键按下"), MB_OK);break;}case WM_PAINT://绘图事件{
            PAINTSTRUCT ps;//绘图结构体
            HDC hdc =BeginPaint(hWnd,&ps);TextOut(hdc,100,100,TEXT("HELLO!"),strlen("HELLO"));EndPaint(hWnd,&ps);break;}default://以windows默认方式处理returnDefWindowProc(hWnd, uMsg, wParam, lParam);}return0;}// 程序入口函数// #define WINAPI  __stdcall 参数的传递顺序:从右到左依次入栈,并在函数返回前清空堆栈int WINAPI WinMain(
    HINSTANCE hInstance,// 应用程序实例句柄
    HINSTANCE hPrevInstace,// 上一个应用程序实例,在win32环境中,默认为NULL
    LPSTR lpCmdLine,// 命令行参数 char * argv[]int nShowCmd            // 窗口显示样式){// 1.设计窗口
    WNDCLASS wc;// 窗口类变量
    wc.cbClsExtra =0;// 类的额外内存
    wc.cbWndExtra =0;// 窗口的额外内存
    wc.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);// 设置背景
    wc.hCursor =LoadCursor(NULL, IDC_HAND);// 设置光标,若第一个参数为NULL,代表使用系统提供的光标
    wc.hIcon =LoadIcon(NULL, IDI_ERROR);// 设置图标,若第一个参数为NULL,代表使用系统提供的光标
    wc.hInstance = hInstance;// 应用程序实例句柄,为WinMain第1个形参
    wc.lpfnWndProc = WinProc;// 回调函数 窗口过程函数名字
    wc.lpszClassName =TEXT("MyWin");// 类的名字
    wc.lpszMenuName =NULL;// 没有菜单
    wc.style =0;// 显示风格,填0,使用默认风格// 2.注册窗口类RegisterClass(&wc);// 3.创建窗口
    HWND  hWnd =CreateWindow(TEXT("MyWin"),TEXT("测试"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,NULL,NULL, hInstance,NULL);// 4.显示及更新ShowWindow(hWnd, SW_SHOWNORMAL);UpdateWindow(hWnd);// 5.通过循环取消息
    MSG msg;while(1){if(GetMessage(&msg,NULL,0,0)== FALSE){break;}else{TranslateMessage(&msg);//翻译DispatchMessage(&msg);//把收到的消息传到窗口回调函数进行分析和处理}}return0;}

执行结果

在这里插入图片描述

1.3 MFC入门

微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是一个微软公司提供的类库(class libraries),以C++类的形式封装了Windows API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。
MFC把Windows SDK API函数包装成了几百个类,MFC给Windows操作系统提供了面向对象的接口,支持可重用性、自包含性以及其他OPP原则。MFC通过编写类来封装窗口、对话框以及其他对象,引入某些关键的虚函数(覆盖这些虚函数可以改变派生类的功能)来完成,并且MFC设计者使类库带来的总开销降到了最低。

编写第一个MFC应用

mfc.h
#include<afxwin.h>//mfc头文件classMyApp:publicCWinApp// CWinApp应用程序类{public:virtual BOOL InitInstance();};classMyFrame:publicCFrameWnd{public:MyFrame();};
mfc.cpp
#include"mfc.h"

MyApp app;// 有且只有一个全局的应用程序类对象

BOOL MyApp::InitInstance()// 程序入口地址{
    MyFrame* frame =new MyFrame;// 1.创建框架类对象

    frame->ShowWindow(SW_SHOWNORMAL);// 2.显示窗口
    frame->UpdateWindow();// 3.更新窗口

    m_pMainWnd = frame;// 4.保存框架类对象指针(保存指向应用程序的主窗口的指针)return TRUE;// 初始化正常返回TRUE}MyFrame::MyFrame(){Create(NULL,TEXT("mfc"));}

编译项目,报错

C:\Program Files(x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\atlmfc\include\afx.h(24,1): fatal error C1189: #error:  Building MFC application with /MD[d](CRT dll version)requires MFC shared dll version. Please #define _AFXDLL ordonot use /MD[d]

解决方法:打开项目属性页,在MFC的使用中选择在共享DLL中使用MFC

在这里插入图片描述
成功运行

在这里插入图片描述

程序执行流程:

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

BOOL Create(
     LPCTSTR lpszClassName,// 如果为NULL,使用预定义的缺省CFrameWnd属性
     LPCTSTR lpszWindowName,// 指向代表窗口名的以空终止的字符串,用作标题条的文本。
     DWORD dwStyle = WS_OVERLAPPEDWINDOW,// 指定窗口风格属性const RECT &rect = rectDefault,// 定义窗口大小和位置
     CWnd* pParentWnd =NULL,// 指定框架窗口的父窗口,对最高层框架窗口来说应为NULL
     LPCTSTR lpszMenuName =NULL,// 指定与窗口一起使用的菜单资源名
     DWORD dwExStyle =0,// 指定窗口扩展的风格属性
     CCreateContext* pContext =NULL// 指向CCreateContext结构的指针);
CWnd::ShowWindow

BOOL ShowWindow(int nCmdShow );//SW_SHOWNORMAL 激活并显示窗口。如果窗口是最小化或最大化的,则Windows恢复它原来的大小和位置。 //返回值:如果窗口原来可见,则返回非零值;如果CWnd原来是隐藏的,则返回0。

消息映射机制

消息映射是一个将消息和成员函数相互关联的表。比如,框架窗口接收到一个鼠标左击消息,

MFC

将搜索该窗口的消息映射,如果存在一个处理

WM_LBUTTONDOWN

消息的处理程序,然后就调用

OnLButtonDown

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

  1. 所操作类中,声明消息映射宏
  2. 通过放置标识消息的宏来执行消息映射,相应的类将在对BEGIN_MESSAGE_MAPEND_MESSAGE_MAP的调用之间处理消息
  3. 对应消息处理函数分别在类中声明,类外定义
mfc.h
#include<afxwin.h>//mfc头文件classMyApp:publicCWinApp// CWinApp应用程序类{public:virtual BOOL InitInstance();};classMyFrame:publicCFrameWnd{public:MyFrame();

    afx_msg voidOnLButtonDown(UINT nFlags, CPoint point);
    afx_msg voidOnChar(UINT, UINT, UINT);
    afx_msg voidOnPaint();// 声明宏 提供消息映射机制DECLARE_MESSAGE_MAP()};
mfc.cpp
#include"mfc.h"

MyApp app;// 有且只有一个全局的应用程序类对象

BOOL MyApp::InitInstance()// 程序入口地址{
    MyFrame* frame =new MyFrame;// 1.创建框架类对象

    frame->ShowWindow(SW_SHOWNORMAL);// 2.显示窗口
    frame->UpdateWindow();// 3.更新窗口

    m_pMainWnd = frame;// 4.保存框架类对象指针(保存指向应用程序的主窗口的指针)return TRUE;// 初始化正常返回TRUE}BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)// 开始ON_WM_LBUTTONDOWN()ON_WM_CHAR()ON_WM_PAINT()END_MESSAGE_MAP()// 结束MyFrame::MyFrame(){Create(NULL,TEXT("mfc"));}voidMyFrame::OnLButtonDown(UINT, CPoint point){//TCHAR buf[1024];//wsprintf(buf, TEXT("x = %d, y = %d"), point.x, point.y);//MessageBox(buf);// MFC中使用字符串 CStirng
    CString str;
    str.Format(TEXT("x = %d, y = %d"), point.x, point.y);MessageBox(str);}voidMyFrame::OnChar(UINT key, UINT, UINT){

    CString str;
    str.Format(TEXT("按下了%c键"), key);MessageBox(str);}voidMyFrame::OnPaint(){

    CPaintDC dc(this);

    dc.TextOutW(100,100,CString("NJ"));// 画椭圆
    dc.Ellipse(100,100,150,150);}

运行结果

在这里插入图片描述

Windows字符集

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

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

char sz[]="ABCDEFG";char*psz ="ABCDEFG";int len =strlen(sz);
  • 宽字符集(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类型。

char * 与 CString之间的转换

// char * -> CStringchar* p ="ccc";
CString str =CString(p);// CString -> char *
CStringA tmp;
tmp = str;char* pp = tep.GetBuffer();

1.4 用向导生成一个MFC应用

用VS2019创建新项目时,选择MFC应用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
项目创建好后,点击视图

    →
   
  
  
   \to
  
 
→类视图

在这里插入图片描述
直接运行,显示窗口

在这里插入图片描述
打开任务管理器,可以看见进程

在这里插入图片描述
双击类名,即可打开

.h

文件

在这里插入图片描述
双击类中成员函数,即可打开对应

.cpp

文件

在这里插入图片描述

文档/视图结构体系

MFC

应用程序框架结构的基石是文档/视图体系结构,它定义了一种程序结构,这种结构依靠文档对象保存应用程序的数据,并依靠视图对象控制视图中显示的数据,把数据本身与它的显示分离开。

数据的存储和加载由文档类来完成,数据的显示和修改则由视类来完成

MFC

在类

CDocument

CView

中为稳定视图提供了基础结构。

CWinApp

CFrameWnd

和其他类与

CDocument

CView

合作,把所有的片段连在了一起。

CView

类也派生于

CWnd

类,框架窗口是视图窗口的一个父窗口。主框架窗口(

CFrameWnd

)是整个应用程序外框所包括的部分,即粗框以内的内容,而视类窗口只是主框架中空白的地方。

在这里插入图片描述

因此,框架窗口是视窗口的父窗口,那么视类窗口就应该始终覆盖在框架类窗口之上。就好比框架窗口是一面墙,视类窗口就是墙纸,它始终挡在这面墙前边。也就是说,所有操作,包括鼠标单击、鼠标移动等操作都只能由视类窗口捕获。

添加消息处理

在消息列表中找到

WM_LBUTTONDOWN

消息

在这里插入图片描述
那么文件中会自动发生三处改动

  • 头文件中声明消息处理函数

在这里插入图片描述

  • 对应cpp文件中添加消息宏

在这里插入图片描述

  • 添加消息处理函数实现

在这里插入图片描述

在函数定义中添加如下代码

voidCmfcGuideView::OnLButtonDown(UINT nFlags, CPoint point){// TODO: 在此添加消息处理程序代码和/或调用默认值CView::OnLButtonDown(nFlags, point);

    CString str;
    str.Format(TEXT("x = %d, y = %d"), point.x, point.y);MessageBox(str);}

可以达到和之前一样的效果

在这里插入图片描述

MFC框架中一些重要的函数

  • CmfcGuideApp::InitInstance函数:应用程序类的一个虚函数,MFC应用程序的入口
  • CMainFrame::PreCreateWindow函数

当框架调用

CreateEx

函数创建窗口时,会首先调用

PreCreateWindow

函数。

通过修改传递给

PreCreateWindow

的结构体类型参数

CREATESTRUCT

,应用程序可以更改用于创建窗口的属性。在产生窗口之前让程序员有机会修改窗口的外观

最后再调用

CreateWindowEx

函数完成窗口的创建。

  • CMainFrame::OnCreate函数
OnCreate

是一个消息响应函数,是响应

WM_CREATE

消息的一个函数,而

WM_CREATE

消息是由

Create

函数调用的。一个窗口创建(Create)之后,会向操作系统发送

WM_CREATE

消息,

OnCreate()

函数主要是用来响应此消息的。

  • CmfcGuideView::OnDraw函数

通常我们不必编写

OnPaint

处理函数。当在

View

类里添加了消息处理

OnPaint()

时,

OnPaint()

就会覆盖掉

OnDraw()

拓展知识点

  • MFC中后缀名为Ex的函数都是扩展函数
  • MFC中,以Afx为前缀的函数都是全局函数,可以在程序的任何地方调用它们

2 基于对话框编程

2.1 创建基于对话框的MFC应用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
点击完成,却报错!

在这里插入图片描述
依照博客:VS 2019 解决对COM组件的调用返回了错误HRESULT E_FAIL

以管理员身份打开

Developer Command Prompt for VS 2019

在这里插入图片描述
找到

VS2019

安装目录

在这里插入图片描述
cd 到文件位置后,输入:

gacutil -i Microsoft.VisualStudio.Shell.Interop.11.0.dll

在这里插入图片描述
显示:程序集已成功添加到缓存中,表示已成功!

再依照上述步骤新建基于对话框的MFC应用程序即可。奈何还是无用依旧报错。在网上偶然看见说,项目名称使用全英文,试了下,不报错了。

在这里插入图片描述
双击

.rc

文件打开资源视图( 菜单栏

    →
   
  
  
   \to
  
 
→视图

 
  
   
    →
   
  
  
   \to
  
 
→其他窗口

 
  
   
    →
   
  
  
   \to
  
 
→资源视图,同样可以打开)

在这里插入图片描述
双击第二个选项

IDD_CDIALOGTEST_DIALOG

在这里插入图片描述
即可看见对话框,也一般称为设计界面,打开菜单栏

    →
   
  
  
   \to
  
 
→视图

 
  
   
    →
   
  
  
   \to
  
 
→工具箱,可以进行选择控件拖拽至对话框中

在这里插入图片描述

点击运行便弹出程序窗口

在这里插入图片描述

另外,打开类视图,可以看见一共有三个类
类名作用CAboutDlg版本信息对话框,从CDialogEx继承过来CCDialogTestApp应用程序类,从CWinApp继承过来CCDialogTestDlg对话框类,从CDialogEx继承过来
在这里插入图片描述
其中对话框类中有两个重要的方法函数

  • DoDataExchange:该函数主要完成对话框数据的交换和校验
  • OnInitDialog:相当于对对话框进行初始化处理

2.3 模态对话框

选中对话框,右击属性,可以修改对话框的标题栏等。

ctrl a + delete

可选中对话框中所有控件并删除

菜单栏

    →
   
  
  
   \to
  
 
→视图

 
  
   
    →
   
  
  
   \to
  
 
→工具箱,拖拽1个按钮进对话框

在这里插入图片描述

如何修改按钮的文字?方法一:属性中修改;方法二:直接选中但不双击,直接打字进行修改。(下图为方法一)

在这里插入图片描述

接下来,实现点击按钮,弹出一个对话框

但此时没有多余对话框,咋办?当然先创建出一个对话框:右击

Dialog

,点击插入Dialog

在这里插入图片描述
修改其

ID

IDD_EXEC

,注意一般为大写

在这里插入图片描述
此时,模态对话框是有了。可以在模态对话框中删除默认控件,并添加一个按钮以显示模态对话框弹出。

但是在主对话框中点击按钮是没有反应的。点击模态对话框

    →
   
  
  
   \to
  
 
→右击

 
  
   
    →
   
  
  
   \to
  
 
→添加类

在这里插入图片描述

在这里插入图片描述
如此,类视图中多了一个自定义类

CDlgExec

在这里插入图片描述
方式一:在主对话框中添加按钮处理函数:创建对话框,并以模态方式运行

在这里插入图片描述
方式二:选中模态对话框按钮控件,右击选择添加事件处理程序

在这里插入图片描述
方式三:直接双击模态对话框按钮控件(因此,和Qt中双击是修改控件文字的操作是不一样的)

添加头文件

#include"CDlgExec.h"
// 模态对话框按钮点击事件voidCCDialogTestDlg::OnBnClickedButton1(){// TODO: 在此添加控件通知处理程序代码

    CDlgExec dlg;
    dlg.DoModal();//以模态方式运行}

在这里插入图片描述

2.4 非模态对话框

与上文类似,先在主对话框中拖入一个按钮,并修改其文字为:非模态对话框

再插入一个对话框,并更改其

ID

IDD_SHOW

,并拖入一个按钮,修改文字:非模态对话框弹出

只有对话框可不行,还得为对话框添加类,

CDlgShow

在这里插入图片描述
当然,你也就会发现,类试图中多了一个类(其实每个窗口都会对应一个类)

在这里插入图片描述
在主对话框中,双击非模态对话框控件,进入该按钮的点击事件处理函数,编写程序

#include"CDlgShow.h"
// 非模态对话框点击事件voidCCDialogTestDlg::OnBnClickedButton2(){// TODO: 在此添加控件通知处理程序代码

    CDlgShow dlg;
    dlg.Create(IDD_SHOW);
    dlg.ShowWindow(SW_SHOWNORMAL);}

运行程序,会发现对话框一闪而过。原因:

dlg

是局部变量,函数运行完就会消失。

解决办法:将

dlg

变量放在类

CCDialogTestDlg

的私有变量中,成为成员变量即可。(记得,添加头文件)

在这里插入图片描述

// 非模态对话框点击事件voidCCDialogTestDlg::OnBnClickedButton2(){// TODO: 在此添加控件通知处理程序代码//CDlgShow dlg;
    dlg.Create(IDD_SHOW);
    dlg.ShowWindow(SW_SHOWNORMAL);}

在这里插入图片描述
关闭非模态对话框后,当在主对话框中再次点击非模态对话框按钮时,会报错

在这里插入图片描述
原因:

Create

函数只能创建一次,再次创建就会出错。

解决办法:将创建窗口的语句放在

OnInitDialog

下,可以保证只创建一次非模态对话框的窗口

在这里插入图片描述
如此一来,在主窗口初始化时便创建了非模态对话框,点击按钮只是显示出来

3 常用控件

3.1 静态文本框 CStaticText

在同一解决方案下继续新建MFC项目,创建好后设定启动项

在这里插入图片描述
在这里插入图片描述
静态文本框是最简单的控件,它主要用来显示文本信息,不能接受用户输入,一般不需要连接变量,也不需要处理消息。

MFC中的静态文本框等同于Qt中的

QLabel

。它与上述按钮控件一样,同样有两种方式修改文本,不再赘述。

在这里插入图片描述
再拖两个按钮控件上去

  • 点击按钮1,可将静态文本框设置为:呵呵
  • 点击按钮2,可弹出显示窗口,显示静态文本框中内容

在这里插入图片描述

Qt

中任何控件都有

ObjectName

,但

MFC

中不存在,但是

MFC

可以关联变量。选中控件,右击

    →
   
  
  
   \to
  
 
→添加变量

由于

XXX_STATIC

静态

ID

是不能关联变量,故需把

ID

修改后,再关联变量

在这里插入图片描述
修改

ID

后就可以添加为控件添加变量了

在这里插入图片描述
修改访问类变量访问权限为

private

,添加类变量名称为

m_text

,点击完成

在这里插入图片描述
创建好控件对应的类变量后,自然可以在按钮1的点击处理函数中编程

// 点击按钮,使得哈哈哈哈变为呵呵voidCCStaticTextTestDlg::OnBnClickedButton1(){// TODO: 在此添加控件通知处理程序代码// 设置文本
    m_text.SetWindowTextW(TEXT("呵呵"));}

运行程序

在这里插入图片描述
在按钮2的点击处理函数中编程

// 点击按钮,获取文本中内容,并且弹出voidCCStaticTextTestDlg::OnBnClickedButton2(){// TODO: 在此添加控件通知处理程序代码

    CString str;
    m_text.GetWindowTextW(str);MessageBox(str);}

在这里插入图片描述
再拖入一个静态文本框控件。右击

    →
   
  
  
   \to
  
 
→添加变量,别忘了改一下控件
ID

在主对话框类

CCStaticTextTestDlg

OnInitDialog

初始化函数中添加代码

//设置静态控件窗口风格为位图居中显示
m_pic.ModifyStyle(0xf, SS_BITMAP | SS_CENTERIMAGE);//通过路径获取bitmap句柄#defineHBMP(filepath,width,height)(HBITMAP)LoadImage(AfxGetInstanceHandle(),filepath,IMAGE_BITMAP,width,height,LR_LOADFROMFILE|LR_CREATEDIBSECTION)//宽高设置 按照控件大小设置
CRect rect;
m_pic.GetWindowRect(rect);//静态控件设置bitmap
m_pic.SetBitmap(HBMP(TEXT("./1.bmp"), rect.Width(), rect.Height()));

在这里插入图片描述

另外,按钮控件不但可以处理点击事件,也可以像静态文本框控件这样去关联变量,并且可以不用修改其

ID

。关联之后在窗口类中就存在一个私有变量,从而可以借助该变量去设置按钮的文本、属性等。常用接口如下:
接口功能CWnd::SetWindowTextW设置控件内容CWnd::GetWindowTextW获取控件内容CWnd::EnableWindow设置控件是否变灰

voidCCStaticTextTestDlg::OnBnClickedButton3(){// TODO: 在此添加控件通知处理程序代码

    m_btn.SetWindowTextW(TEXT("o_o"));

    CString str;
    m_btn.GetWindowTextW(str);MessageBox(str);

    m_btn.EnableWindow(FALSE);}

在这里插入图片描述

3.2 编辑框 CEdit

继续新建项目,

CEditCtrlTest

,在对话框中拖入控件

Edit Control

在这里插入图片描述
运行程序后,在编辑框中输入按回车,会自动退出对话框。若是想设置为多行编辑框,右击

    →
   
  
  
   \to
  
 
→属性

在这里插入图片描述
在这里插入图片描述
另外,该控件可以设置属性中

Auto VScroll

垂直滚动

达到类似

txt

上下滚动的效果

在这里插入图片描述
若是想再实现一个一模一样的编辑框,按住

ctrl

拖动一下即可。在工具箱中拖入两个按钮以实现功能。

在这里插入图片描述
为两个编辑框分别添加变量:

m_edit1

m_edit2

在这里插入图片描述

当对话框中控件较多时,同时添加变量较多时,该如何方便得查看类中的所有变量呢?右击对话框

    →
   
  
  
   \to
  
 
→类向导

 
  
   
    →
   
  
  
   \to
  
 
→成员变量

在这里插入图片描述

先在编辑框中添加一下默认文本内容,在

OnInitDialog

函数中编写初始化程序

// TODO: 在此添加额外的初始化代码
m_edit1.SetWindowTextW(TEXT("MFC"));

copy

按钮添加处理事件程序

voidCCEditCtrlTestDlg::OnBnClickedButton1(){// TODO: 在此添加控件通知处理程序代码
    CString str;
    m_edit1.GetWindowText(str);
    m_edit2.SetWindowTextW(str);}

在这里插入图片描述

close

按钮添加事件处理程序

voidCCEditCtrlTestDlg::OnBnClickedButton2(){// TODO: 在此添加控件通知处理程序代码// 退出程序exit(0);}

但是一般而言,我们只希望关闭当前对话框,不希望关闭整个程序

voidCCEditCtrlTestDlg::OnBnClickedButton2(){// TODO: 在此添加控件通知处理程序代码// 退出当前对话框CDialog::OnOK();}

再回过头解决一下小

bug

:单行编辑框点击回车就退出的问题。

解决办法:重写

OnOk

,注释掉其中代码

在这里插入图片描述
为了介绍编辑框另一个使用方法——关联基本类型变量,再拖入一个编辑框和两个按钮。并为编辑框添加变量,但此时注意,类别选择

Value

在这里插入图片描述
添加设置内容控件的点击处理函数

voidCCEditCtrlTestDlg::OnBnClickedButton3(){// TODO: 在此添加控件通知处理程序代码

    m_text = L"hhh";UpdateData(FALSE);}

在这里插入图片描述

添加获取内容控件的点击处理函数

voidCCEditCtrlTestDlg::OnBnClickedButton4(){// TODO: 在此添加控件通知处理程序代码UpdateData(TRUE);MessageBox(m_text);}

在这里插入图片描述

3.4 组合框 CComboBox

继续在同一解决方案下创建新项目,

ComboBoxCtrl

。在对话框中拖入

Combo Box

控件,经如下设置后运行程序,可显示下拉框的效果

在这里插入图片描述

在这里插入图片描述
但是一般在开发中,不会通过属性去设置。组合框常用接口如下:
接口功能CComboBox::AddString组合框添加一个字符串CComboBox::SetCurSel设置当前选择项(当前显示第几项),下标从0开始CComboBox::GetCurSel获取组合框中当前选中项的下标CComboBox::GetLBText获取指定位置的内容CComboBox::DeleteString删除指定位置的字符串CComboBox::InsertString在指定位置插入字符串
使用接口自然需要关联变量,为下拉框控件关联变量

在这里插入图片描述
在主对话框类的

OnInitdialog

函数中添加下拉框初始化代码

// TODO: 在此添加额外的初始化代码
m_cbx.AddString(TEXT("韩立"));
m_cbx.AddString(TEXT("墨居仁"));
m_cbx.AddString(TEXT("银月"));
m_cbx.AddString(TEXT("紫灵"));

m_cbx.SetCurSel(2);

m_cbx.InsertString(3,TEXT("小瓶"));

m_cbx.DeleteString(1);

在这里插入图片描述
组合框常用的事件为:

CBN_SELCHANGE

,当选择组合框某一项时,自动触发此事件。

在控件属性中选择该事件,或者双击控件进入事件处理函数

voidCComboBoxCtrlDlg::OnCbnSelchangeCombo1(){// TODO: 在此添加控件通知处理程序代码int index = m_cbx.GetCurSel();

    CString str;
    m_cbx.GetLBText(index, str);MessageBox(str);}

在这里插入图片描述

3.5 列表控件 CListCtrl

继续新建项目,

ListCtrl

。在工具箱中拖入一个列表控件,并设置属性:

view
    →
   
  
  
   \to
  
 
→
Report

在这里插入图片描述
添加变量

在这里插入图片描述
列表控件常用接口如下
接口功能CListCtrl::SetExtendedStyle设置列表风格CListCtrl::GetExtendedStyle获取列表风格CListCtrl::InsertColumn插入某列内容,主要用于设置标题CListCtrl::InsertItem在某行插入新项内容CListCtrl::SetItemText设置某行某列的子项内容CListCtrl::GetItemText获取某行某列的内容
去窗口初始化函数中添加初始化代码

// TODO: 在此添加额外的初始化代码

CString str[]={TEXT("姓名"),TEXT("性别"),TEXT("年龄")};for(int i =0; i <3; i++){// 设置表头 参数1->索引  2->内容  3->对齐方式 4->列宽  
    m_list.InsertColumn(i, str[i], LVCFMT_LEFT,150);}

CString name[]={ L"韩立", L"紫灵", L"元瑶", L"冰风", L"巧倩"};
CString gender[]={ L"男", L"女", L"女", L"女", L"女"};
CString age[]={ L"24", L"22", L"23", L"24", L"25"};// 设置正文 表头不算正文for(int i =0; i <5; i++){int j =0;
    m_list.InsertItem(i, name[i]);// 设置这个item其他列的数据
    m_list.SetItemText(i,++j, gender[i]);
    m_list.SetItemText(i,++j, age[i]);}

在这里插入图片描述
可以通过代码继续设置列表属性

m_list.SetExtendedStyle(m_list.GetExtendedStyle()| LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

在这里插入图片描述

3.6 树控件 CTreeCtrl

继续新建

MFC

应用,

CTreeCtrl

。在主对话框中拖入控件

CTreeCtrl

,先设置一下属性

在这里插入图片描述
接着给树控件关联变量

在这里插入图片描述
该控件常用接口如下
接口功能AfxGetApp()获取应用程序对象指针CWinApp::LoadIcon加载自定义图标CImageList::Create创建图像列表CImageList::Add图像列表追加图标CTreeCtrl::SetImageList设置图形状态列表CTreeCtrl::InsertItem插入节点CTreeCtrl::SelectItem设置默认选中项CTreeCtrl::GetSelectedItem获取选中项CTreeCtrl::GetItemText获取某项内容
编程前的准备工作:把ico资源文件放在项目res文件夹中

在这里插入图片描述

ico

资源文件放好位置后,在资源视图

    →
   
  
  
   \to
  
 
→
Icon
    →
   
  
  
   \to
  
 
→添加资源。注意,
VS2019

需要将资源文件改成

.bmp

后缀的才可以进行添加

在这里插入图片描述

OnInitDialog

函数中添加控件初始化代码

// TODO: 在此添加额外的初始化代码// 树控件使用// 1.设置图标// 准备HICON图标
HICON icons[4];
icons[0]=AfxGetApp()->LoadIconW(IDI_ICON1);
icons[1]=AfxGetApp()->LoadIconW(IDI_ICON2);
icons[2]=AfxGetApp()->LoadIconW(IDI_ICON3);
icons[3]=AfxGetApp()->LoadIconW(IDI_ICON4);// CImageList list; // 这个需要写到类成员变量中,否则出函数变量会被释放//30, 30: 图片的宽度和高度    ILC_COLOR32:样式    3, 3:有多少图片写多少
list.Create(30,30, ILC_COLOR32,4,4);// 添加具体图片for(int i =0; i <4; i++){

    list.Add(icons[i]);}

m_tree.SetImageList(&list, TVSIL_NORMAL);// 2.设置节点
HTREEITEM root = m_tree.InsertItem(TEXT("根节点"),0,0,NULL);
HTREEITEM parent = m_tree.InsertItem(TEXT("父节点"),1,1, root);
HTREEITEM sub1 = m_tree.InsertItem(TEXT("子节点1"),2,2, parent);
HTREEITEM sub2 = m_tree.InsertItem(TEXT("子节点2"),3,3, parent);

在这里插入图片描述
树控件常用事件为:

TVN_SELCHANGED

,当选择某个节点时,自动触发此事件

在这里插入图片描述

voidCCTreeCtrlDlg::OnTvnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult){
    LPNMTREEVIEW pNMTreeView =reinterpret_cast<LPNMTREEVIEW>(pNMHDR);// TODO: 在此添加控件通知处理程序代码*pResult =0;

    HTREEITEM selItem;//获得选择项
    selItem = m_tree.GetSelectedItem();//获取选中的内容
    CString cs = m_tree.GetItemText(selItem);MessageBox(cs);}

在这里插入图片描述

3.7 标签页的使用

新建

MFC

项目,

CtabCtrl

。将默认控件删除,并拖入

CTabCtrl

控件。

TabSheet.h

TabSheet.cpp

放在项目文件同级目录,并且添加到工程目录中。

在这里插入图片描述

ui

Tab Control

关联

Control

类型(

CTabSheet

在这里插入图片描述

两个标签页都需要各自添加对话框,并设置相应属性

在这里插入图片描述
在这里插入图片描述
自定义类:点击对话框模板

    →
   
  
  
   \to
  
 
→ 右击 

 
  
   
    →
   
  
  
   \to
  
 
→ 添加类(
MyDlg1

MyDlg2

)

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

在这里插入图片描述
主对话框类中

OnInitDialog()

做初始化工作

// TODO: 在此添加额外的初始化代码

m_tab.AddPage(TEXT("系统管理"),&dlg1, IDD_DIALOG1);
m_tab.AddPage(TEXT("系统设置"),&dlg2, IDD_DIALOG2);

m_tab.Show();

在这里插入图片描述

标签: mfc windows c++

本文转载自: https://blog.csdn.net/Star_ID/article/details/125238025
版权归原作者 Star_ID 所有, 如有侵权,请联系我们删除。

“MFC基础入门”的评论:

还没有评论