MFC包含的基本四个类
- 框架类
- 应用程序类
- 文档类
- 视图类
MFC程序运行启动
AFX_MODULE_STATE aaa;//当前程序模块状态信息aaa(臆造的名字)
AFX_MODULE_THREAD_STATE bbb;//当成程序线程状态信息
CWinAPP::CWinApp()//构造全局对象CMyWinApp theApp
{
AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
//获取全局变量&aaa,_AFX_CMDTARGET_GETSTATE()为AfxGetModuleState()的宏定义
AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread
//获取全局变量&bbb
pThreadState->m_pCurrentWinThread = this;
//谁调用构造函数,谁就是this,即theApp的地址保存在变量m_pCurrentWinThread,bbb的一个成员中
AfxGetThread(){
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();//获取全局变量&bbb
CWinThread* pThread = pState->m_pCurrentWinThread;
return pThread;//返回&theApp
}
//ASSERT断言判断
pModuleState->m_pCurrentWinApp = this;//将&theApp的赋给aaa的一个成员
AfxGetApp(){
return afxCurrentWinApp;
//afxCurrentWinApp是一个宏,AfxGetModuleState()->m_pCurrentWinApp,即return &theApp
}
}
- 程序的启动,构造theApp的对象,调用父类CWinApp的构造函数:
- 将theAPP对象的地址保存在线程状态信息中;
- 将theApp对象的地址保存在模块状态信息中;
- 进入WinMain函数,调用AfxWinMain函数。
程序的执行
//theApp是不是指导程序流程
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,_In_ LPTSTR lpCmdLine, int nCmdShow){
AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow){
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();//均为获取&theApp
pApp->InitApplication();//利用theApp对象调用应用程序类成员虚函数****初始化,多态性
pThread->InitInstance()//利用theApp对象调用应用程序类成员虚函数****创建并显示窗口
pThread->Run()//利用theApp对象调用应用程序类成员虚函数****消息循环
{
for(;;)
{
while(没有消息时)
OnIdle();//利用theApp对象调用应用程序类成员虚函数 空闲处理
do
{
if(getMessage捉到WM_QUIT)
return ExitInstance();
//程序结束前,利用theApp对象调用应用程序类成员虚函数****善后处理
}while(...)
}
};
}
}
-
进入入口函数WinMain
- 获取应用程序类对象theApp的地址;
- 利用theApp地址调用InitApplication,初始化当前应用程序的数据;
- 利用theApp地址调用InitInstance虚函数初始化程序,在函数中我们创建窗口并显示;
- 利用theApp地址调用CWinApp的Run虚函数进行消息循环;
- 如果没有消息,利用theApp地址调用OnIdle虚函数实现空闲处理;
- 程序退出利用theApp地址调用ExitInstance虚函数实现退出前的善后处理工作。
-
成员变量
m_pMainWnd——当前应用程序的主窗口
钩子函数
- Win32的技术,MFC借用了这个技术,大量用于木马病毒;
- 优先读取消息,把消息钩过来,所以称为钩子函数。
创建钩子
HHOOK SetWindowsHookEX(
int idHook,//钩子类型,在MFC里面一般为WH_CBT,即钩取WM_CREATE信息
HOOKPROC Lpfn,//钩子处理函数
HINSTANCE hMod,//应用程序实例句柄
DWORD dwThreadId//线程ID
);
钩子处理函数
LRESULT CALLBACK CBTProc(
int nCode,//钩子码,一般 为HCBT_CREATEWND
WPARAM wParam,//刚刚创建成功的窗口句柄
LPARAM lParam//...
)
更改窗口处理函数
LONG_PTR SetWindowLongPtr(
HWND hWnd,//窗口句柄
int nIndex,//GWLP_WNDPROC
LONG_PTR dwNewLong//新的窗口处理函数名(函数地址)
)
MFC的窗口如何创建
CMyFrameWnd *pFrame = new CMyFrameWnd;
pFrame->Create(NULL, "MFCBase");
//即Create的运行过程
- 加载菜单
- 调用CWnd::CreateEx函数创建窗口
{
调用PreCreateWindow函数设计和注册窗口类
{
调用AfxDeferRegisterClass函数
}
}
- 调用AfxHookWindowCreate函数,埋下钩子
- 调用CreateWindowEx函数创建窗口,马上调用钩子处理函数
- 钩子处理函数_AfxCbtFilterHook
- 将窗口句柄和框架类对象地址建立一对一的绑定关系
- 使用SetWindowLong函数,将窗口处理的函数设置为AfxWndProc
消息映射机制
-
在不重写WindowProc虚函数的大前提下,即可处理消息
-
类必须具备的条件
- 类内必须添加声明宏——DECLARE_MESSAGE_MAP()
- 类外必须添加实现宏
- BEGIN_MESSAGE_MAO(theClass, baseClass)
- END_MESSAGE_MAP()
-
总结:当一个类具备上述两个条件,这个类就可以按照消息映射进制来处理消息
-
example
class CMyFrameWnd :public CFrameWnd { DECLARE_MESSAGE_MAP() public: LRESULT OnCreate(WPARAM wParam, LPARAM lParam); }; BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd) ON_MESSAGE(WM_CREATE,OnCreate) END_MESSAGE_MAP() LRESULT CMyFrameWnd::OnCreate(WPARAM wParam, LPARAM lParam) { AfxMessageBox("WM_CREATE"); return 0; }
-
运行机制——遍历链表(本类的静态变量和静态数组,父类的静态变量和静态数组),当消息产生的时候,带着消息的ID遍历链表寻找对应的消息函数完成相应的处理。
消息的分类
-
标准windows消息
ON_WM_XXX
class CMyFrameWnd :public CFrameWnd { DECLARE_MESSAGE_MAP() public: int OnCreate(LPCREATESTRUCT pcs); }; BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP() int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) { AfxMessageBox("WM_CREATER IDLE"); return CFrameWnd::OnCreate(pcs);//防止父类的create函数被屏蔽 }
-
自定义消息
ON_MESSAGE
-
命令消息
ON_COMMAND
菜单
-
菜单相关问题
- Win32-HMENU
- MFC-CMenu类对象
-
CMenu封装了一个重要的成员变量m_hMenu(菜单句柄)
-
菜单的创建方法
-
添加菜单资源rc文件,同时注意#include “resource.h”,可视化操作新增菜单对象
-
将菜单设置到窗口
-
方法一:利用pFrame调用Create函数时,传参;
-
方法二:在处理框架窗口的WM_CREATE消息时,
CMenu menu; menu.LoadMenu(...);
-
-
-
example
#include<afxwin.h>
#include "resource.h"
class CMyFrameWnd :public CFrameWnd {
DECLARE_MESSAGE_MAP()
public:
int OnCreate(LPCREATESTRUCT pcs);
public:
CMenu menu;//保证生命周期
};
BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)
ON_WM_CREATE()
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) {
menu.LoadMenu(IDR_MENU1);//绑定菜单句柄和menu对象
this->SetMenu(&menu);
return CFrameWnd::OnCreate(pcs);
}
class CMyWinApp :public CWinApp {
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance() {
CMyFrameWnd *pFrame = new CMyFrameWnd;
//方法一,传参
//pFrame->Create(NULL, "MFCMenu",WS_OVERLAPPEDWINDOW,CFrameWnd::rectDefault,
// NULL,(CHAR*)IDR_MENU1);
pFrame->Create(NULL, "MFCMenu");
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;//爆破点
-
命令消息的处理顺序
对于ON_COMMMADE而言,框架类>应用程序类(对于同一个消息)
-
下拉菜单、菜单状态选项、右键菜单的例子
#include<afxwin.h>
#include "resource.h"
class CMyFrameWnd :public CFrameWnd {
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnNew();
afx_msg void OnInitMenuPopup(
CMenu* pPopupMenu,
UINT nIndex,
BOOL bSysMenu);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint pos);
public:
CMenu menu;//保证生命周期,代表整个大菜单
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_COMMAND(ID_new, OnNew)
ON_WM_CREATE()
ON_WM_INITMENUPOPUP()
ON_WM_CONTEXTMENU()
END_MESSAGE_MAP()
//右键菜单
void CMyFrameWnd::OnContextMenu(CWnd* pWnd, CPoint pos) {
方法一:调用win32api
//HMENU hPopup = ::GetSubMenu(menu.m_hMenu, 0);//获取顶层菜单某一菜单的下一菜单
//::TrackPopupMenu(hPopup, TPM_LEFTALIGN | TPM_TOPALIGN, pos.x, pos.y, 0,
// this->m_hWnd, NULL);
//方法二:采用MFC对象
CMenu *pPopup = menu.GetSubMenu(0);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, pos.x, pos.y,this);
}
//设置菜单项状态
void CMyFrameWnd::OnInitMenuPopup(
CMenu* pPopupMenu,
UINT nIndex,
BOOL bSysMenu) {
pPopupMenu->CheckMenuItem(ID_new, MF_CHECKED);
//::CheckMenuItem(pPopupMenu->m_hMenu, ID_new, MF_CHECKED);
}
//菜单选项消息响应
void CMyFrameWnd::OnNew() {
AfxMessageBox("新建");
}
//绑定UI菜单到程序
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) {
menu.LoadMenu(IDR_MENU1);//绑定菜单句柄和menu对象
this->SetMenu(&menu);
return CFrameWnd::OnCreate(pcs);
}
class CMyWinApp :public CWinApp {
public:
virtual BOOL InitInstance();
};
//基本应用框架
BOOL CMyWinApp::InitInstance() {
CMyFrameWnd *pFrame = new CMyFrameWnd;
//绑定菜单
//pFrame->Create(NULL, "MFCMenu",WS_OVERLAPPEDWINDOW,CFrameWnd::rectDefault,
// NULL,(CHAR*)IDR_MENU1);
pFrame->Create(NULL, "MFCMenu");
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
工具栏
- 相关的类
- CToolBarCtrl——父类为CWnd,封装了关于工具栏控件的各种操作。(不是工具栏,是工具栏里面的一个一个的按钮)
- CToolBar——父类CControlBar,封装了关于工具栏的操作,以及和框架窗口的关系。(这个才是工具栏)
- 工具栏的创建使用
- 添加工具栏资源(rc文件,可视化操作)
- 创建工具栏 CToolBar::CreateEx
- 加载工具栏CTool::LoadToolBar
- 设置工具栏的停靠(看看就好)
- CToolBar::EnableDocking
- CFrameWnd::EnableDocking
- CFrameWnd::DockControlBar
- example
#include<afxwin.h>
#include "resource.h"
#include<afxext.h>//CToolBar类为拓展类
class CMyFrameWnd :public CFrameWnd {
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnNew();
afx_msg void OnSet();
public:
CMenu menu;
CToolBar toolbar;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_COMMAND(ID_set,OnSet)
ON_COMMAND(ID_new,OnNew)
ON_WM_CREATE()
END_MESSAGE_MAP()
//绑定菜单、工具栏
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs){
//绑定菜单
menu.LoadMenu(IDR_MENU1);//绑定菜单句柄和menu对象
this->SetMenu(&menu);
//绑定工具栏
toolbar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP);
toolbar.LoadToolBar(IDR_TOOLBAR1);
return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnSet(){
AfxMessageBox("green");
}
void CMyFrameWnd::OnNew() {
AfxMessageBox("new");
}
class CMyWinApp :public CWinApp {
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance() {
CMyFrameWnd *pFrame = new CMyFrameWnd;
pFrame->Create(NULL, "MFCToolBar");
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
运行时类信息机制
-
MFC六大机制
- 程序启动机制
- 窗口创建机制
- 消息映射机制
- 运行时类信息机制
- 动态创建机制
- 序列化机制
-
含义:在程序运行过程中可以获知对象的类的相关信息(例如:对象是否属于某个类)
-
运行时类信息机制的使用(具备三个要件)
- 类必须派生自CObject
- 类内必须添加声明宏 DECLARE_DYNAMIC(theClass)
- 类外必须添加实现宏 IMPLEMENT_DYNAMIC(theClass,baseClass)
- 当一个类具备上述三个要件后,CObject::IsKindOf函数就可以正确判断对象是否属于某个类
-
example
#include<afxwin.h>
#include <iostream>
using namespace std;
class CAnimal :public CObject {
DECLARE_DYNAMIC(CAnimal)
};
IMPLEMENT_DYNAMIC(CAnimal,CObject)
class CDog :public CObject {
DECLARE_DYNAMIC(CDog)
};
IMPLEMENT_DYNAMIC(CDog,CAnimal)
int main()
{
CDog yellowdog;
if (yellowdog.IsKindOf(RUNTIME_CLASS(CDog))) {
cout << "yellowdog is dog";
}
else {
cout << "yelllowdog isnot dog";
}
return 0;
}
- 运行机制:还是宏展开链表追踪,重点的宏展开是RUNTIME_CLASS(class)
动态创建机制
-
作用:在不知道类名的情况下,将类的对象创建出来。
-
使用方法
-
类必须派生自CObject
-
类内必须添加声明宏 DECLARE_DYNCREATE(theClass)
-
类外必须添加实现宏 IMPLEMENT_DYNCREATE(theClass,baseClass)
-
当一个类具备上述三个要件后,CRuntimeClass::CreateObject(对象加工厂)
函数就可以将类的对象创建出来
-
-
example
#include<afxwin.h>
#include <iostream>
using namespace std;
class CAnimal :public CObject {
DECLARE_DYNAMIC(CAnimal)
};
IMPLEMENT_DYNAMIC(CAnimal,CObject)
class CDog :public CObject {
DECLARE_DYNCREATE(CDog)
};
IMPLEMENT_DYNCREATE(CDog,CAnimal)
int main()
{
CObject *pob= RUNTIME_CLASS(CDog)->CreateObject();//对象加工厂函数
if (pob) {
cout << pob<<endl;
}
else {
cout << "对象创建失败";
}
return 0;
}
- 抛弃单兵作战的思想,你设置对象,MFC帮你创建
视图窗口
-
提供一个用于显示数据的窗口
-
CView类,封装了关于视图窗口的各种操作,以及和文档类(后台处理数据)的数据交互,其父类为CWnd类。
-
命令消息的处理顺序(暂时)
对于ON_COMMMADE而言,视图类>框架类>应用程序类(对于同一个消息)
-
视图窗口的使用
- 定义一个自己的视图类(CMyView),派生自CView,并重写父类成员纯虚函数OnDraw(可用于绘图)
- 其余框架类和应用层程序类代码不变
- 在处理框架窗口的WM_CREATE消息时,定义CMyView类对象,并调用Create函数创建视图窗口,视图窗口的ID设置为AFX_IDW_PANE_FIRST(设置其大小同框架类画布)
-
example
#include<afxwin.h>
class CMyView : public CView {
public:
void OnDraw(CDC *pDC);
};
//重写纯虚函数
void CMyView::OnDraw(CDC *pDC) {
}
class CMyFrameWnd : public CFrameWnd {
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT pcs);
};
BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)
ON_WM_CREATE()
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) {
CMyView * pView = new CMyView;
pView->Create(NULL, "MFCVIEW", WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(0, 0, 200, 200),
this, AFX_IDW_PANE_FIRST);//视图ID设置为平铺在整个框架窗口上
this->m_pViewActive = pView;//视图类对象地址绑定
return CFrameWnd::OnCreate(pcs);
}
class CMyWinAPP : public CWinApp {
virtual BOOL InitInstance();
};
BOOL CMyWinAPP::InitInstance() {
CMyFrameWnd *pFrame = new CMyFrameWnd;
pFrame->Create(NULL, "MFCVIEW");
this->m_pMainWnd = pFrame;//框架类对象地址绑定
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinAPP theApp;//爆破点
- 对象关系
this->m_pMainWnd = pFrame;//框架类对象地址绑定
this->m_pViewActive = pView;//视图类对象地址绑定
——theApp
->m_pMainWnd(pFrame框架类对象)
->m_pViewActive(pView视图类对象地址)
一一绑定,获得theApp即可得到所有的类地址
文档类
-
CDocument:提供了一个用于管理数据的类,封装了关于数据的管理(数据管理,数据转换,数据存储等),并和视图类进行数据交互。
-
程序的创建过程
- 利用框架类对象地址pFrame调用LoadFrame函数,创建框架窗口;
- (父类)在处理框架窗口的WM_CREATE的消息时,动态创建视图类对象,并创建视图窗口;
- (父类)在处理视图窗口的WM_CREATE的消息时,将文档类对象和视图类对象建立关联关系。
-
对象关系图
- 文档类对象用一个链表成员变量,保存视图类对象地址;
- 视图类对象用一个普通成员变量,保存文档类对象地址;
——theApp
|->m_pMainWnd(pFrame框架类对象地址)
|->m_pViewActive(pView视图类对象地址,活动视图类对象地址,视图可以有多个,但活动视图只有一个)
|->m_pDocument(文档类对象地址pDoc)
|->m_viewList(所有视图类对象地址,一个链表,m_viewList.AddTail(pView))
//一一绑定,获得theApp即可得到所有的类地址;
//一个视图对应一个文档;一个文档可以对应多个视图;
- example
#include<afxwin.h>
#include<afxext.h>
#include "resource.h"
class CMyDoc :public CDocument {
};
class CMyView :public CView {
DECLARE_DYNCREATE(CMyView)//动态创建机制
DECLARE_MESSAGE_MAP()//消息映射机制
public:
virtual void OnDraw(CDC * pDC);//重写纯虚函数
afx_msg int OnCreate(LPCREATESTRUCT pcs);
};
IMPLEMENT_DYNCREATE(CMyView,CView)
BEGIN_MESSAGE_MAP(CMyView,CView)
ON_WM_CREATE()
END_MESSAGE_MAP()
int CMyView::OnCreate(LPCREATESTRUCT pcs) {
//return 0;//文档类和视图类没法关联
return CView::OnCreate(pcs);//将文档类对象和视图类对象建立关联关系
}
void CMyView::OnDraw(CDC * pDC) {
pDC->TextOut(100, 100, "this is view window");//父类处理视图动态创建的说明
}
class CMyFrameWnd :public CFrameWnd {
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT pcs);//pcs这个参数可以获取::CreateWindowEx的12个参数
};
BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)
ON_WM_CREATE()
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) {
//return 0;//MFC父类自动创建视图窗口的证明
return CFrameWnd::OnCreate(pcs);
}
class CMyWinApp :public CWinApp {
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance() {
CMyFrameWnd *pFrame = new CMyFrameWnd;
CMyDoc *pDoc = new CMyDoc;
CCreateContext cct;
cct.m_pCurrentDoc = pDoc;//文档类对象地址
cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);//&CMyView::classCMyView,即视图类的静态变量的地址
pFrame->LoadFrame(IDR_MENU1, WS_OVERLAPPEDWINDOW, NULL,&cct);//创建框架窗口
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
窗口切分
-
相关类
CSplitterWnd——不规则框架窗口类,封装了关于不规则框架窗口的操作;
-
窗口切分的使用
重写CFrameWnd类的成员虚函数OnCreateClient
- 在虚函数中调用CSplitterWnd::CreateStatic创建不规则框架窗口
- 在虚函数中调用CSplitterWnd::CreateView创建视图窗口
-
example
#include<afxwin.h>
#include<afxext.h>
#include "resource.h"
class CMyDoc :public CDocument {
};
class CMyView :public CView {
DECLARE_DYNCREATE(CMyView)//动态创建机制
DECLARE_MESSAGE_MAP()//消息映射机制
public:
virtual void OnDraw(CDC * pDC);//重写纯虚函数
afx_msg int OnCreate(LPCREATESTRUCT pcs);
};
IMPLEMENT_DYNCREATE(CMyView,CView)
BEGIN_MESSAGE_MAP(CMyView,CView)
ON_WM_CREATE()
END_MESSAGE_MAP()
int CMyView::OnCreate(LPCREATESTRUCT pcs) {
//return 0;//文档类和视图类没法关联
return CView::OnCreate(pcs);//将文档类对象和视图类对象建立关联关系
}
void CMyView::OnDraw(CDC * pDC) {
pDC->TextOut(100, 100, "this is view window");//父类处理视图动态创建的说明
}
class CMyFrameWnd :public CFrameWnd {
DECLARE_MESSAGE_MAP()
public:
CSplitterWnd split;//提高生命周期
public:
afx_msg int OnCreate(LPCREATESTRUCT pcs);//pcs这个参数可以获取::CreateWindowEx的12个参数
afx_msg BOOL OnCreateClient(LPCREATESTRUCT pcs, CCreateContext *pContext);
};
BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)
ON_WM_CREATE()
END_MESSAGE_MAP()
BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT pcs, CCreateContext *pContext) {
//创建两个视图窗口,父类处理OnCreate消息时自动把两个视图和唯一的文档类关联
split.CreateStatic(this, 1, 2);//父类,1行两列
split.CreateView(0, 0, pContext->m_pNewViewClass, CSize(100, 100), pContext);
split.CreateView(0, 1, pContext->m_pNewViewClass, CSize(100, 100), pContext);
return TRUE;
}
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) {
//return 0;//MFC父类自动创建视图窗口的证明
return CFrameWnd::OnCreate(pcs);
}
class CMyWinApp :public CWinApp {
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance() {
CMyFrameWnd *pFrame = new CMyFrameWnd;
CMyDoc *pDoc = new CMyDoc;
CCreateContext cct;
cct.m_pCurrentDoc = pDoc;//文档类对象地址
cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);//&CMyView::classCMyView,即视图类的静态变量的地址
pFrame->LoadFrame(IDR_MENU1, WS_OVERLAPPEDWINDOW, NULL,&cct);//创建框架窗口
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
-
命令消息的处理顺序
对于ON_COMMMADE而言,视图类>文档类>框架类>应用程序类(对于同一个消息)
-
文档类成员函数
当文档类数据发生变化是,调用UpDateAllViews函数刷新和文档类对象相关联的视图类对象(视图窗口)
void CMyDoc::OnNew() { this->str = "hello world!";//表示接收到的数据,比如网络的socket等 //this->UpdateAllViews(NULL);//刷新和这个文档类对象(this)关联的所有视图窗口 //刷新单独的窗口 POSITION pos = this->GetFirstViewPosition();//GetFirstXXXPosition,迭代器函数,获取链表头结点的上一个结点 CView *pView = this->GetNextView(pos);//GetNextXXXPosition,迭代器函数,获取链表的下一个结点 this->UpdateAllViews(pView);//刷新和这个文档类对象this关联的除了pView指向的视图窗口 } //--------------------------------------------------- void CMyView::OnDraw(CDC * pDC) { CMyDoc *pDoc = (CMyDoc*)this->m_pDocument; pDC->TextOut(100, 100, pDoc->str);//父类处理视图动态创建的说明 }
#include<afxwin.h> #include<afxext.h> #include "resource.h" class CMyDoc :public CDocument { DECLARE_MESSAGE_MAP() public: afx_msg void OnNew(); public: CString str;//数据 }; BEGIN_MESSAGE_MAP(CMyDoc, CDocument) ON_COMMAND(ID_NEW, OnNew) END_MESSAGE_MAP() void CMyDoc::OnNew() { this->str = "hello world!";//表示接收到的数据,比如网络的socket等 //this->UpdateAllViews(NULL);//刷新和这个文档类对象(this)关联的所有视图窗口 //刷新单独的窗口 POSITION pos = this->GetFirstViewPosition();//GetFirstXXXPosition,迭代器函数,获取链表头结点的上一个结点 CView *pView = this->GetNextView(pos);//GetNextXXXPosition,迭代器函数,获取链表的下一个结点 this->UpdateAllViews(pView);//刷新和这个文档类对象this关联的除了pView指向的视图窗口 } class CMyView :public CView { DECLARE_DYNCREATE(CMyView)//动态创建机制 DECLARE_MESSAGE_MAP()//消息映射机制 public: virtual void OnDraw(CDC * pDC);//重写纯虚函数 afx_msg int OnCreate(LPCREATESTRUCT pcs); afx_msg void OnNew(); }; IMPLEMENT_DYNCREATE(CMyView,CView) BEGIN_MESSAGE_MAP(CMyView,CView) ON_WM_CREATE() //ON_COMMAND(ID_NEW,OnNew) END_MESSAGE_MAP() void CMyView::OnNew() { AfxMessageBox("view class deal with WM_COMMAND message"); } int CMyView::OnCreate(LPCREATESTRUCT pcs) { //return 0;//文档类和视图类没法关联 return CView::OnCreate(pcs);//将文档类对象和视图类对象建立关联关系 } void CMyView::OnDraw(CDC * pDC) { CMyDoc *pDoc = (CMyDoc*)this->m_pDocument; pDC->TextOut(100, 100, pDoc->str);//父类处理视图动态创建的说明 } class CMyFrameWnd :public CFrameWnd { DECLARE_MESSAGE_MAP() public: CSplitterWnd split; public: afx_msg int OnCreate(LPCREATESTRUCT pcs);//pcs这个参数可以获取::CreateWindowEx的12个参数 afx_msg BOOL OnCreateClient(LPCREATESTRUCT pcs, CCreateContext *pContext); }; BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP() BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT pcs, CCreateContext *pContext) { //创建两个视图窗口,父类处理OnCreate消息时自动把两个视图和唯一的文档类关联 split.CreateStatic(this, 1, 2);//父类,1行两列 split.CreateView(0, 0, pContext->m_pNewViewClass, CSize(100, 100), pContext); split.CreateView(0, 1, pContext->m_pNewViewClass, CSize(100, 100), pContext); this->m_pViewActive = (CView*)split.GetPane(0, 0);//设置活动窗口0行0列 return TRUE; } int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) { //return 0;//MFC父类自动创建视图窗口的证明 return CFrameWnd::OnCreate(pcs); } class CMyWinApp :public CWinApp { public: virtual BOOL InitInstance(); }; BOOL CMyWinApp::InitInstance() { CMyFrameWnd *pFrame = new CMyFrameWnd; CMyDoc *pDoc = new CMyDoc; CCreateContext cct; cct.m_pCurrentDoc = pDoc;//文档类对象地址 cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);//&CMyView::classCMyView,即视图类的静态变量的地址 pFrame->LoadFrame(IDR_MENU1, WS_OVERLAPPEDWINDOW, NULL,&cct);//创建框架窗口 m_pMainWnd = pFrame; pFrame->ShowWindow(SW_SHOW); pFrame->UpdateWindow(); return TRUE; } CMyWinApp theApp;
-
视图类成员函数
获取和视图类对象关联的文档类对象,调用GetDocument(),这是公有函数,和m_pDocument的保护成员不一样,但返回的都是文档的地址。
代码基本同上
void CMyView::OnDraw(CDC * pDC) {
//CMyDoc *pDoc = (CMyDoc*)this->m_pDocument;
CMyDoc *pDoc = (CMyDoc*)this->GetDocument();
pDC->TextOut(100, 100, pDoc->str);//父类处理视图动态创建的说明
}
单文档视图架构
-
特点:只能有一个文档类对象,只能有一份数据
-
参与架构的类
CFrameWnd/ CWinApp/ CView /CDocument
-
需要用到的类
-
CDocTemplate(文档模板类)
|->CSingleDocTemplate(单文档模板类)
-
CDocManager(文档管理类)
-
-
win32程序书写:参与架构的四个类除了应用程序外,其余三个类均支持动态创建机制
-
执行过程
theApp
|->m_pDocManager//文档管理类对象地址
|->m_templateList//单文档模板类对象地址
|->CSingleDocTemplate *pTemplate
|->m_pOnlyDoc//唯一的文档类对象地址
|->m_pDocClass//RUNTIME_CLASS(CMyDoc),
|->m_pFrameClass//RUNTIME_CLASS(CMyFrameWnd),
|->m_ppViewClass//RUNTIME_CLASS(CMyView),
- example
#include <afxwin.h>
#include "resource.h"
class CMyDoc: public CDocument{
DECLARE_DYNCREATE(CMyDoc)
};
IMPLEMENT_DYNCREATE(CMyDoc,CDocument)
class CMyView :public CView {
DECLARE_DYNCREATE(CMyView)
public:
virtual void OnDraw(CDC *pDC);
};
IMPLEMENT_DYNCREATE(CMyView,CView)
void CMyView::OnDraw(CDC *pDC) {
pDC->TextOut(100, 100, "view window");
}
class CMyFrameWnd :public CFrameWnd {
DECLARE_DYNCREATE(CMyFrameWnd)
};
IMPLEMENT_DYNCREATE(CMyFrameWnd,CFrameWnd)
class CMyWinApp :public CWinApp {
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance(){
CSingleDocTemplate *pTemplate = new CSingleDocTemplate(IDR_MENU1,
RUNTIME_CLASS(CMyDoc), RUNTIME_CLASS(CMyFrameWnd), RUNTIME_CLASS(CMyView));
AddDocTemplate(pTemplate);
OnFileNew();
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
};
CMyWinApp theApp;
- MFC自动生成:善用类向导,创建消息、命令函数。(类视图和类向导,神器)
多文档视图架构
-
可以管理多份文档,可以有多份数据
-
参与架构的类(5个)
CMDIFrameWnd/ CMDIChildWnd/ CWinApp/ CView / CDocument
-
需要用到的类
-
CDocTemplate(文档模板类)
|->CMultiDocTemplate(单文档模板类)
-
CDocManager(文档管理类)
-
-
两个框架窗口,一个主框架,一个子框架
-
执行过程
theApp
|->m_pDocManager//文档管理类对象地址
|->m_templateList//多文档模板类对象地址
|->CMultiDocTemplate *pTemplate
|->m_docList//保存多个文档类对象地址
|->m_pDocClass//RUNTIME_CLASS(CMyDoc)
|->m_pFrameClass//RUNTIME_CLASS(CMyChild)
|->m_pViewClass//RUNTIME_CLASS(CMyView)
MFC绘图
-
WINDOWS下的绘图,需要 绘图设备
-
WIN32——绘图设备句柄(HDC)
-
MFC——类对象
-
所以类对象要和HDC绑定一对一的关系才行
-
-
绘图相关类
- CDC类(绘图设备类):封装了各种绘图相关的函数,以及两个非常重要的成员变量m_hDC和m_hAttribDC(这两个成员变量保存着绘图设备句柄)
- CPaintDC类,封装了在WM_PAINT消息中绘图的绘图设备
- CClientDC类,封装了在客户区绘图的绘图设备
- CGdiObject(绘图对象类):封装了各种绘图对象相关的操作,以及一个非常重要的成员变量m_hObject(绘图对象句柄)
- CPen类,封装了画笔的操作;
- CBrush类,封装了画刷的操作;
- CFont类,封装了字体的操作;
- CBitmap,封装了位图的操作;
- CDC类(绘图设备类):封装了各种绘图相关的函数,以及两个非常重要的成员变量m_hDC和m_hAttribDC(这两个成员变量保存着绘图设备句柄)
-
example:在view类下面创建消息(使用类向导)
//窗口一变即OnPaint,可以一直存在,即WM_PAINT消息
void CMFCDrawView::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CView::OnPaint()
//dc.Rectangle(100, 100, 300, 300);//画家在视图窗口上画矩形
}
//不能一直保持,窗体大小改变即消失,需要重现点击
void CMFCDrawView::OnClient()
{
// TODO: 在此添加命令处理程序代码
CClientDC dc(this);
dc.Ellipse(300, 300, 500, 500);
}
//画笔绘制矩形
void CMFCDrawView::OnPen()
{
// TODO: 在此添加命令处理程序代码
CClientDC dc(this);//创建设备
CPen pen(PS_SOLID, 2, RGB(255, 0, 0));//内部句柄已经绑定
CPen *oldpen= dc.SelectObject(&pen);//把笔给设备,并返回老的笔
dc.Rectangle(100, 100, 300, 300);//绘图设备绘图
dc.SelectObject(oldpen);//选择老的笔
pen.DeleteObject();//销毁创建的笔
}
//画刷填充矩形蓝色
void CMFCDrawView::OnBrush()
{
// TODO: 在此添加命令处理程序代码
CClientDC dc(this);
CBrush brush(RGB(0, 0, 255));
CBrush *oldbrush = dc.SelectObject(&brush);
dc.Rectangle(100, 100, 300, 300);
dc.SelectObject(oldbrush);
brush.DeleteObject();
}
//输出不同字体
void CMFCDrawView::OnFont()
{
// TODO: 在此添加命令处理程序代码
CClientDC dc(this);
CFont font;
VERIFY(font.CreatePointFont(120, _T("黑体"), &dc));//断言判断
CFont* def_font = dc.SelectObject(&font);
dc.TextOut(5, 5, _T("Hello"), 5);
dc.SelectObject(def_font);
font.DeleteObject();
}
void CMFCDrawView::OnBitmap()
{
/*
//添加位图资源,可视化,不需写代码
//创建一个和当前DC相匹配的内存DC
CClientDC dc(this);
CDC memdc;
memdc.CreateCompatibleDC(&dc);
//将位图数据送给内存DC
CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP1);
CBitmap *oldbmp = memdc.SelectObject(&bmp);
//成像
dc.BitBlt(100, 100, 100,100, &memdc, 0, 0, SRCCOPY);
//将位图数据要回来
memdc.SelectObject(oldbmp);
//销毁位图
bmp.DeleteObject();
//销毁内存DC
memdc.DeleteDC();
*/
//方式二:居中视图
CClientDC dc(this);
CBitmap bmp;
if (bmp.LoadBitmap(IDB_BITMAP1))
{
// 获取文件大小
BITMAP bmpInfo;
bmp.GetBitmap(&bmpInfo);
//创建一个和当前DC相匹配的内存DC
CDC dcMemory;
dcMemory.CreateCompatibleDC(&dc);
//将位图数据送给内存DC
CBitmap* pOldBitmap = dcMemory.SelectObject(&bmp);
// 找到居中区域
CRect rect;
GetClientRect(&rect);
int nX = rect.left + (rect.Width() - bmpInfo.bmWidth) / 2;
int nY = rect.top + (rect.Height() - bmpInfo.bmHeight) / 2;
//显示到居中区域
dc.BitBlt(nX, nY, bmpInfo.bmWidth, bmpInfo.bmHeight, &dcMemory,
0, 0, SRCCOPY);
dcMemory.SelectObject(pOldBitmap);
dcMemory.DeleteDC();
}
else
{
TRACE0("ERROR: Where's IDB_BITMAP1?\n");
AfxMessageBox(_T("error"));
}
bmp.DeleteObject();
}
序列化机制
-
MFC六大机制
- 程序启动机制
- 窗口创建机制
- 消息映射机制
- 运行时类信息机制
- 动态创建机制
- 序列化机制
-
文件操作相关类:
-
CFile——文件操作类,封装了关于文件读写等操作
- CFile::Open//创建和打开文件
- CFile::Write/Read
- CFile::Close
- CFile::SeekToBegin/SeekToEnd/Seek
- example
#include<afxwin.h> #include<iostream> using namespace std; void File() { CFile file; file.Open(_T("E:/pro_test/MFC/MFCFile/file.txt"), CFile::modeCreate | CFile::modeReadWrite);//没有就新建,有就读写 char str[] = "hello file"; file.Write(str, strlen(str)); file.SeekToBegin();//从头开始读写 char buf[256] = {0};//初始化 long nlen = file.Read(buf, 255);//返回字节数 cout << buf << " " << nlen << endl; file.Close(); } int main() { File(); return 0; }
-
-
序列化的基本类型
- 以二进制流的形式读写硬盘文件,但效果很高。
- 序列化机制的相关类
- CFile——文件操作类,完成硬盘文件的读写操作;
- CAchive——归档类,完成内存数据的读写操作;
-
序列化机制的使用:
- 创建或打开文件——CFile::Open
- 定义归档类对象——CArchive ar
- 数据序列化(存储/写) ar<<数据
- 关闭归档类对象 ar.Close()
- 关闭文件 CFile::Close()
-
example
void Store() {//序列化(创建/加载/写)
CFile file;
file.Open(_T("E:/pro_test/MFC/MFCFile/serial.txt"), CFile::modeCreate | CFile::modeWrite);
CArchive ar(&file, CArchive::store, 4096);//归档类对象,维护缓冲区,大小4096字节
long age = 18;
ar << age;
float score = 88.5;
ar << score;
CString name = "zhangsan";
cout << name << endl;
ar << name;
ar.Close();
file.Close();
}
void Load() {//反序列化(加载/读)
CFile file;
file.Open(_T("E:/pro_test/MFC/MFCFile/serial.txt"), CFile::modeRead);
CArchive ar(&file, CArchive::load, 4096);
long age;
ar >> age;
float score;
ar >> score;
CString name;
ar >> name;
ar.Close();
file.Close();
cout << age << " " << score << " " << name << endl;
}
int main() {
Store();
Load();
return 0;
}
序列化对象
-
序列化对象的使用方法
- 类必须派生自CObject
- 类内必须添加声明宏 DECLARE_SERIAL(theClass)
- 类外必须添加实现宏 IMPLEMENT_SERIAL(theClass, baseClass, 1)
- 类必须重写虚函数 Serialize
- 当类满足以上四个要件的时候,类对象就可以序列化到文件中保存了。
-
example
#include<afxwin.h>
#include<iostream>
using namespace std;
class CMyDoc :public CDocument {
DECLARE_SERIAL(CMyDoc)
public:
CMyDoc(int age = 0,float score= 0.0,CString name=""):m_age(age),m_score(score),m_name(name){}
int m_age;
float m_score;
CString m_name;
virtual void Serialize(CArchive &ar);
};
IMPLEMENT_SERIAL(CMyDoc,CDocument,1)
void CMyDoc::Serialize(CArchive &ar) {
if (ar.IsStoring()) {
ar << m_age << m_score << m_name;
}
else {
ar >> m_age >> m_score >> m_name;
}
}
void Store() {//序列化(创建/加载/写)
CFile file;
file.Open(_T("E:/pro_test/MFC/MFCFile/serial_class.txt"), CFile::modeCreate | CFile::modeWrite);
CArchive ar(&file, CArchive::store, 4096);//归档类对象,维护缓冲区
CMyDoc data(18, 88.5, "zhangsan");
ar << &data;
ar.Close();
file.Close();
}
void Load() {//反序列化(加载/读)
CFile file;
file.Open(_T("E:/pro_test/MFC/MFCFile/serial_class.txt"), CFile::modeRead);
CArchive ar(&file, CArchive::load, 4096);
CMyDoc *pdate = NULL;
ar >> pdate;
ar.Close();
file.Close();
cout << pdate->m_age << " " << pdate->m_score << " " << pdate->m_name << endl;
}
int main() {
Store();
Load();
return 0;
}
无模式对话框
-
创建方法
- 添加对话框资源
- 查找资源 FindResource
- 加载资源 LoadResource
- 锁定资源 LockResource
- 创建无模式对话框 CreateDialogIndirect
-
参与架构的类 CDialog/ CWinApp
-
代码书写
- 添加对话框资源
- 定义一个自己的对话框类(CMyDlg),管理对话框资源,派生自CDialog或CDialogEx均可
- 其余代码详见以下的
对象和控件绑定
-
一定是在对话框类里面进行成员变量的绑定,而不是应用程序类
-
将控件窗口和类对象绑定具有两大作用
- 如果和数据类对象绑定(CString等),对象和控件可以进行数据交换
- 如果和控件类对象绑定(CButton等),对象可以代表整个控件
-
和数据类对象绑定的使用
- 重写父类虚函数DoDateExchange,在函数内部通过一系列的DDX_xxx函数,实现控件和数据类型对象的数据交互
- 如果需要实现数据交互,调用UPdateData函数
- UpdataData(TRUE):控件->变量
- UpdataData(TRUE):变量->控件
滑块控件——Slide Control
- dialog资源文件设置,插入控件,更改ID
- 设置成员变量,使用类向导,绑定控件
- OnInit函数初始化
BOOL CMFCDialgDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
//滑块初始化
m_slider.SetRange(0, 100);
m_slider.SetPos(50);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
- 消息映射机制,拉动使用,发出WM_COMMAND消息(通知码NM_CUSTOMDRAW)
PS:可双击控件直接创建,也可使用类向导创建
void CMFCDialgDlg::OnNMCustomdrawSlider1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
int pos = m_slider.GetPos();//获取位置
CString strPos;
strPos.Format(_T("滑块位置%d"), pos);
this->SetWindowText(strPos);
*pResult = 0;
}
进度条控件——Progress Control
- CProgressCtrl类
- SetRange
- SetPos
- GetPos
- 操作同滑块控件
BOOL CMFCDialgDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
//初始化
m_slider.SetRange(0, 100);
m_slider.SetPos(50);
m_progress.SetRange(0, 100);
m_progress.SetPos(50);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
//联动滑块和进度条
void CMFCDialgDlg::OnNMCustomdrawSlider1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
int pos = m_slider.GetPos();
CString strPos;
strPos.Format(_T("滑块位置%d"), pos);
this->SetWindowText(strPos);
m_progress.SetPos(pos);
*pResult = 0;
}
下压式按钮——CButton类
-
消息WM_COMMAND,消息码(BN_CLICKED)
-
对话框类绑定成员变量——类向导
-
双击即可创建消息函数
-
一般没有数据交换
编辑框——Edit Control
-
应该先输入完然后和按钮联动,这样效果比较好
-
//只是例子,效果是每一个输入都会有弹框,即都有反应 void CMFCDialgDlg::OnEnChangeEdit1() { // TODO: 在此添加控件通知处理程序代码 TCHAR bud[256]; int length=m_edit.GetWindowText(bud,256); AfxMessageBox(bud); }
复选框按钮——Check Box
- 勾选和非勾选两种状态
- 仍然是CButton类
- m_check.GetCheck()——勾选即返回1
- m_check.SetCheck(!m_check.GetCheck())
- 属性的push_like是那个更改为TRUE,即变成多态按钮
单选框按钮——Radio Button
- 仍然是CButton类
- 一组单选框只能选一个
- 一般不出现在类向导里面,要在属性里面的group框选为TRUE才可以
- 互斥的关系要在点击单选框的消息函数里面自己写
分组框按钮——gruop box
- 提高界面友好性
- 仍然是CButton类
- 就是框选单选按钮,看的更清楚,就是示意
- ID: IDC_STATIC——不会出现在类向导里,更改之后可出现
文本静态框——Static Text
- SetWindowText可设置内容,这是父类CWin的函数,一般控件都可用;
- 但是文本静态一般只是展示,提高界面友好性的
- ID: IDC_STATIC——不会出现在类向导里,更改之后可出现
图像静态框——Picture Control
- 属性的杂项的type->Icon/Bitmap,一般是这两种类型
- 属性里面的image可以一开始设置图片
- ID: IDC_STATIC——不会出现在类向导里,更改之后可出现,如更改成IDC_PS
- 显示图像操作
- CStatic::SetIcon
- CStatic::SetBitmap
- example
m_ps.SetBitmap(::LoadBitmap(AfxGetInstanceHandle,MAKEINTRESOURCE()));//需要位图的句柄;如果是加载本程序的资源位图ID的话就需要获取当前程序的实例句柄和资源ID
组合框——Combo Box
- 一般是下拉式,支持组合框编辑
- 下拉链表时,不支持组合框编辑
- CComboBox::AddString()——添加组合框选项
- CComboBox::DeleteString——删除选项
- CComboBox::GetCurSel——获取选择性索引
- 获取选项文本内容——CComboBox::GetLBText
- 选择项发生变化的时候,会发送WM_COMMAND消息
列表框——List Box
- CListBox类
- 常见操作
- 添加选项CListBox::AddString
- 删除选项CListBox::DeleteString
- 获取选择项索引 CListBox::GetCurSel
- 获取选项文本内容 CListBox::GetItemText
列表控件——List Control
- CListCtrl类
- 风格
- 图标(LVS_ICON)
- 小图标(LVS_SMALLICON)
- 列表(LVS_LIST)
- 报表(详细信息)(LVS_REPORT)
- 修改风格 CWnd::ModifyStyle
- 常见操作
- 添加选项
- 删除选项
- 添加列
- 设置文本内容
- 设置图像
- 设置附加数据
- 获取附加数据
- 当列表被双击,发出WM_COMMAND消息,通知码(LBN_DBLCLK)
树控件——Tree Control
- CTreeCtrl
- 常见操作