MFC简介
是微软提供的一个类库 以C++形式封装了windows API 并且包含了一个应用程序框架 减少工作人员的开发工作量
而且MFC不止可以封装了界面库 还要很多其他的类 可以说是很方便了 我们用MFC开发界面 不再需要我们自己处理消息 只需要根据控件就可以自动生成不同的消息处理等等
当然一个东西肯定不可能都是优点 缺点也是显而易见的 MFC经过这么多年的发展 封装过程过于复杂 如果出现问题 调试东西不容易定位问题的位置 当然有一本书叫<<深入浅出MFC>>它很详细地介绍了MFC的内部机制 对于新手并不是很友好 如果我们只是使用MFC使用方法 这本书可以先不用看
MFC的入口程序
我们知道在WIN32 API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序的窗口函数。而在MFC程序中,我们能不能找到类似于WinMain这样的程序入口?
因为程序是从Main(WinMain)开始。 但是在Main(WinMain)开始之前会对全局的变量或者对象进行初始化。 故在MFC中,通过通过全局类(theApp) 的初始化, 进入theApp的构造函数,根据类的规则,初始子类的构造函数,必须先要运行父类的构造函数。 在这过程把包含WinMain的文件连接了进来。 这样就隐藏了WinMain函数。 在WinMain函数中调用了AfxWinMain函数,在AfxWinMain函数中通过调用InitInstance函数完成了窗口的设计 窗口的注册 窗口的创建 窗口的显示和更新。然后在AfxWinMain中调用了Run方法,完成消息循环。
我们可以在appmodul.h找到winmain的定义
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
C++其实就是WinMain
MFC中的常用窗口类及关系
1. CWnd:窗口类祖宗 所有的窗口类都是从CWnd这个类派生出来的 包括对话框 各种控件等内部封装了很多对于窗口的操作常用的操作包括 创建窗口 关闭窗口 遍历窗口 禁用窗口 获得窗口的大小 获得窗口的标题等等很多很多内部有一个关键的成员变量 窗口句柄HWND m_hWnd
2. CDialog对话框类 派生自CWnd 因为对话框也是窗口该类主要是针对对话框的 可以从资源加载对话框模板 以及创建模态和非模态的对话框的操作
3. 各种控件类 CButton CEdit CList CListctrl CTreeCtrl CStatic 等等他们也是派生自基类CWnd每个控件类都有自己的操作方法所以内部的成员函数和成员变量都是针对控件自身的
4. 绑定关系 MFC中的对话框模板 如果不添加自定义的操作 则不必绑定自定义的对话框类 直接使用CDialog/CDialogEX来操作就可以 如果要定义添加一些类似OnInitDialog的初始化函数以及其他的一些事件以及其他一些事件和操作 那么就必须绑定一个自定义的派生自CDialog/CDialogex的对话框类 同理也是一样的道理
## CDialog与CDialogEx的区别联系
CDialogEx是VS2003之后出现的,VC++6.0没有。
CDialogEx = CDialog Extend
Extend的意思是扩展,即扩展的CDialog!
这个类是CDialog的扩展类,基类就是CDialog,具备基类全部功能,并根据新系统需要增加了一些界面美化的功能。
比如修改对话框的背景颜色,标题栏的颜色,标题栏的位图,标题栏字体的位置和颜色,包括激活和非激活状态,对话框边界的颜色,对话框字体等。
如果使用的是VS2005之后的版本,推荐使用CDialogEx,好看一些,VC++6就不要想了,老实用CDialog吧。
两个在基础功能上没什么区别,但因为版本不同,MFC向导生成的类模板差异较大。
CWnd和HWND的区别
CWnd第一个字母C指的是class的意思,即CWnd是一个类;HWND第一个字母H指的是handle的意思,即HWND是一个句柄。
CWnd:是MFC类库中所有窗口类的基类。MFC将所有窗口的通用操作都封装到CWnd类中,如MoveWindow、ShowWindow;同时,它也封装了窗口句柄,即m_hWnd成员。
HWND:即Windows窗口句柄,是Windows系统中对所有窗口的一种唯一标识。
聪明的读者可以发现,CWnd其实就是MFC中的一个类名;而HWND是Windows中窗体句柄的类型,一个类似于指针地址的数字型对象。
由CWnd获取HWnd:
方法一:从CWnd获取HWnd就容易多了,因为它的一个成员变量m_hWnd就是所对应窗口的句柄。
wnd->m_hWnd
方法二:也可以通过成员函数CWnd::GetSafeHwnd()来获得该窗口对象的HWND窗口句柄。
CWnd*和CButton*
GetDlgItem(IDC_BUTTON1) 这是获取按钮的窗口类 CWnd 指针
如果又定义了IDC_BUTTON1的成员变量为 m_button1,这个应该是 CButton 类,它的父父类应该是CWnd吧。 子类可以直接用继承自父类的函数 父类要用子类的要转化
(CButton*)GetDlgItem(IDC_BUTTON1)->EnableWindow
MFC对话框详解
对话框自带的两个类 新生成的对话框工程主要有两个类 主线程 主对话框类
主线程类的初始化函数中创建主对话框 主对话框负责界面显示
主对话框类
主对话框类的构造函数和析构函数 可以初始化内部的一些成员变量的值 此时对话框的界面窗口还没有被创建出来因此我们可以在这里初始化类的成员变量 但如果是界面的操作函数 在这里调用窗口是会崩溃的。
我们如果要添加 界面代码 则需要在BOOL C对话框详解Dlg::OnInitDialog()
这个函数进行界面的初始化 位置要在这个函数之后 这样界面就会被创建出来再操作void C对话框详解Dlg::DoDataExchange(CDataExchange* pDX)
此函数是进行数据校验的函数 一半不需要我们进行修改或者添加
BEGIN_MESSAGE_MAP(C对话框详解Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()
C++这里是程序对事件的映射 一般我们创建的消息事件都会在这里显示
主线程类
// 对话框详解.h: PROJECT_NAME 应用程序的主头文件
//
#pragma once
#ifndef __AFXWIN_H__
#error "在包含此文件之前包含 'pch.h' 以生成 PCH"
#endif
#include "resource.h" // 主符号
// C对话框详解App:
// 有关此类的实现,请参阅 对话框详解.cpp
//
class C对话框详解App : public CWinApp
{
public:
C对话框详解App();
// 重写
public:
virtual BOOL InitInstance();
// 实现
DECLARE_MESSAGE_MAP()
};
extern C对话框详解App theApp;
C++mfc线程类里面很简单 只有一个InitInstance 我们可以进内部看一下
其中进行了初始化一些创建对话框之前的准备工作 以及创建模态主对话框 domodal之后不会往下执行 只有当主对话框关闭之后 线程才会执行
类的属性
右键类对话框类 下面会有一些消息和事件 右键可以增加事件 那么需要删除的话
- 对话框类头文件里 删除
- 对话框类cpp文件 删除函数定义
- 对话框类cpp文件 删除绑定事件和消息
除了在属性里面添加 还可以直接操作控件 比如双击按钮来对应消息点击事件 我们对类添加事件 可以切换到资源视图 然后对应进行添加消息和事件
homework:
关闭对话框时候添加提示确认框 点击确定则关闭 点击取消不做任何操作
void C对话框详解Dlg::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (MessageBox(TEXT("您确认关闭吗"), 0, MB_ICONINFORMATION | MB_YESNO)== IDNO)
{
return;
}
CDialog::OnClose();
}
C++鼠标左键双击对话框空白位置 弹出messagebox提示框
void C对话框详解Dlg::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
MessageBox(TEXT("左键被单击"));
CDialogEx::OnLButtonUp(nFlags, point);
}
C++程序启动之后对话框位于屏幕的左上角
BOOL C对话框详解Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
CRect rc;
GetWindowRect(rc); //得到对话框的Rect 对话框的大小
ScreenToClient(rc); //把屏幕的值转成相应的实际的值
int cx, cy;
cx = GetSystemMetrics(SM_CXSCREEN);
cy = GetSystemMetrics(SM_CYSCREEN);
MoveWindow(1,1,rc.Width(),rc.Height(),true);
}
C++MFC控件指针及控件变量绑定
MFC控件指针
我们要操纵控件首先要获取一个窗口控件的句柄 有了句柄我们就可以对控件窗口进行操作 当然在win32中作为句柄 在mfc因为已经封装成类库 获取的叫控件指针GetDlgitem()
当然这个函数也分为全局函数和类函数
全局函数的参数包括一个句柄 和一个控件ID ->win32
类库函数的参数只需要传递控件 ID 默认的窗口就是当前的主窗口m_hwnd
- 随时用 随时取
我们添加一个复选框 然后获取它的当前选中状态 首先获取它的控件指针
可以看到指针所指向的控件句柄和我们用全局函数获取的句柄是一样的 因此我们使用全局或者mfc函数都是可以的 之前我们说过CWnd是父类 而复选框也属于按钮所以我们可以用按钮类转换一下
我们获取状态可以直接通过指针访问控件指针的成员方法 也可以使用sendmessage发送消息获取 这也是CWCheckbox->GetCheck();
调用的底层api (int)::SendMessage(m_hWnd, BM_GETCHECK, 0, 0) 获取单选按钮或检查框的检查状态。 可以显式发送此消息或使用 相信聪明的你一定理解了。
- 什么成类成员变量指针 初始化函数中获取这个指针
我们可以在对话框类的成员变量添加一个控件指针 并且在初始化函数中初始化指针为NULL 然后在界面构造函数BOOL C对话框详解Dlg::OnInitDialog()
调用获取对应控件指针的值
控件变量绑定
因为对指针的操作是很危险的 稍不注意就会造成程序的崩溃 所以我们还有第二种方法 绑定控件变量 在我们需要绑定的控件上右击添加变量 然后填写变量名称 之后会在对话框头文件的类成员变量增加一个控件对象变量CButton m_CheckButton;
并且会在void C对话框详解Dlg::DoDataExchange(CDataExchange* pDX)
函数中绑定控件ID和变量 然后就可以通过这个变量调用 每个变量只能绑定一次
还有一种绑定是值绑定 value
只是用来传递数据,不能对控件进行其它的操作。
UpdateData(FALSE); //可以向控件传递数据
UpdateData(TRUE); //可以从控件获得数据
我们继续给复选框绑定值
UpdateData(TRUE);
int icheck = i_CheckButton;
C++这样就可以获取到checkbox的状态
i_CheckButton = 1
UpdateData(FALSE);
C++这样就可以将我们的给value的值写到对话框的界面上
作业:1、在MFCDIgFirstDlg.cpp文件中添加一个全局函数int GetEditValue, 函数的参数可自定义,返
回值为控件ID为IDC_ EDIT的编辑框内的数字内容,若无内容返回0。界面上的某个按钮点击之后会
调用GetEditValue函数,同时将返回的编辑框的数字内容使用MessageBox提示出来!
- 可以将GetEditValue的参数设为我们类的指针 然后获取控件编辑框的整数内容
- 可以传入主窗口的句柄 用全局函数获取编辑框的内容
- AfxGetApp( )是全局的。
AfxGetApp( )这个函数可以得到当前应用进程的指针,是CWinApp*类型的,通过这个指针可以访问到这个进程中的对象。AfxGetApp()这个函数在VC当中很常见,主要是用来获得CWinAPP生成的全局对象的。一般情况下将其强制类型转换成你自己写的App类就可以调用里面的方法了。
代码如下
//方法1
int GetEditValue(C对话框详解Dlg* pMainDlg)
{
int inEdit = pMainDlg->GetDlgItemInt(IDC_EDIT1);
return inEdit;
}
//方法2
int GetEditValue(HWND hmainDlg)
{
int inEdit = ::GetDlgItemInt(hmainDlg, IDC_EDIT1, 0, 0);
return inEdit;
}
//方法3
int GetEditValue()
{
C对话框详解Dlg* pMainDlg = (C对话框详解Dlg*)AfxGetApp()->m_pMainWnd; //保留指向应用程序主窗口的指针。
int iEditValue = pMainDlg->GetDlgItemInt(IDC_EDIT1);
return iEditValue;
}
void C对话框详解Dlg::OnBnClickedCheck1()
{
//方法1
int iValue = GetEditValue(this);
CString strValue;
strValue.Format(_T("%d"), iValue);
MessageBox(strValue);
//方法2
int iValueAPI = GetEditValue(m_hWnd);
TCHAR szValue[32] = { 0 };
_stprintf(szValue, _T("%d"), iValueAPI);
MessageBox(szValue);
// TODO: 在此添加控件通知处理程序代码
/*HWND hCheckbox = ::GetDlgItem(m_hWnd, IDC_CHECK1);
CButton* CWCheckbox = (CButton*)GetDlgItem(IDC_CHECK1);
int isCheck = ::SendMessage(m_hWnd, BM_GETCHECK, 0, 0);
int iCheck = CWCheckbox->GetCheck();*/
}
C++