運行時類信息(RTTI)
C++:
##是拼接
#是替換成字符串
// RTTI.cpp : 此文件包含 "main" 函數(shù)。程序執(zhí)行將在此處開始并結(jié)束。
//
#include <iostream>
#include <afxwin.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CWinApp theApp;
int main()
{
//CListBox是MFC自帶的控件類
CListBox* pListBox = new CListBox;
//GetRuntimeClass方法返回運行時類信息
CRuntimeClass* pRuntimeClass = pListBox->GetRuntimeClass();
std::cout << pRuntimeClass->m_lpszClassName << std::endl;
//運行時類的IsDeriverFrome方法可以判斷該類是否繼承于某類
if (pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(CWnd))) {
std::cout<<"CListBox類繼承于CWnd類"<<std::endl;
}
if (pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(CView))) {
std::cout << "CListBox類繼承于視圖類" << std::endl;
}
//運行時類的m_pfnGetBaseClass方法可以獲取父類的信息
CRuntimeClass* pParentClass = pRuntimeClass->m_pfnGetBaseClass();
if (pParentClass->IsDerivedFrom(RUNTIME_CLASS(CWnd))) {
std::cout << "運行時類的父類繼承于CWnd類" << std::endl;
}
//動態(tài)創(chuàng)建一個對象:
CWnd* pWnd = (CWnd*)pParentClass->m_pfnCreateObject();
return 0;
}
這是MFC提供的運行時類信息的使用,如果我們自己創(chuàng)建一個類,如果想用這些方法,必須要滿足三個條件:
- 這個類必須繼承于CObject類
- 類內(nèi)必須聲明DECLARE_DYNAMIC
- 類外必須實現(xiàn)IMPLENENT_DYNAMIC
我們來看看是如何實現(xiàn)的:
拆分宏
DECLARE_DYNAMIC(SHape)
public:
//靜態(tài)的結(jié)構(gòu)體
//本來是static const CRuntimeClass class##class_name;,拼接之后:
static const CRuntimeClass classSHape;
//虛函數(shù)
virtual CRuntimeClass* GetRuntimeClass() const;
//IMPLEMENT_DYNAMIC(SHape,CObject)
IMPLEMENT_RUNTIMECLASS(SHape, CObject, 0xFFFF, NULL, NULL)
AFX_COMDAT const CRuntimeClass SHape::classSHape =
{
"SHape",
sizeof(class SHape),
0xFFFF,
NULL,
RUNTIME_CLASS(CObject),//返回父類靜態(tài)結(jié)構(gòu)體的地址
NULL,
NULL
};
CRuntimeClass* SHape::GetRuntimeClass() const
{
return RUNTIME_CLASS(SHape);
}
struct CRuntimeClass
{
LPCSTR m_lpszClassName; //類名稱
int m_nObjectSize; //類大小
UINT m_wSchema; //類版本
CObject* (PASCAL* m_pfnCreateObject)(); //動態(tài)創(chuàng)建才會使用 暫時NULL函數(shù)指針
CRuntimeClass* m_pBaseClass; //父類信息
CRuntimeClass* m_pNextClass; //NULL
const AFX_CLASSINIT* m_pClassInit; //NULL
}
#define RUNTIME_CLASS(class_name) _RUNTIME_CLASS(class_name)
((CRuntimeClass*)(&SHape::classSHape))
}
這里給出RTTI的圖,每一個類中都保存了這樣一個結(jié)構(gòu),相當于鏈表,我們有當前的類信息,就可以得到所有父類信息:
動態(tài)創(chuàng)建機制
如果想在MFC中實現(xiàn)動態(tài)創(chuàng)建:
- 也必須繼承與CObject類
- 類內(nèi)聲明DECLARE_DYNCREATE
- 類外實現(xiàn)IMPLEMENT_DYNCREATE
class SHape : public CObject
{
public:
DECLARE_DYNCREATE(SHape)
};
IMPLEMENT_DYNCREATE(SHape,CObject)
class CLine : public SHape
{
public:
DECLARE_DYNCREATE(CLine)
};
IMPLEMENT_DYNCREATE(CLine, SHape)
需要注意的是,動態(tài)創(chuàng)建宏中包含了動態(tài)信息的宏
使用:
int main()
{
HMODULE hModule = ::GetModuleHandle(nullptr);
AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0);
//定義直線類:
CLine line;
//方法內(nèi)部this指針指向line
//該方法用于判斷是否繼承與某個類
if (line.IsKindOf(RUNTIME_CLASS(SHape))) {
std::cout << "是圖形" << std::endl;
}
if (line.IsKindOf(RUNTIME_CLASS(CWnd))) {
std::cout << "是窗口" << std::endl;
}
else {
std::cout << "不是窗口" << std::endl;
}
CObject* pLine = RUNTIME_CLASS(CLine)->CreateObject();
if (pLine->IsKindOf(RUNTIME_CLASS(SHape))) {
std::cout << "創(chuàng)建成功" << std::endl;
}
return 0;
}
動態(tài)創(chuàng)建包括了類信息
//函數(shù)跟蹤
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
//拿到鏈表頭節(jié)點
CRuntimeClass* pClassThis = this->GetRuntimeClass();
pClassThis->IsDerivedFrom(參數(shù)是判斷的結(jié)構(gòu)體地址)
{
while (pClassThis != NULL)
{
if (pClassThis == 參數(shù))
return TRUE;
if (pClassThis->m_pfnGetBaseClass == NULL)
break;
//獲取父類靜態(tài)結(jié)構(gòu)體地址
pClassThis = pClassThis->m_pBaseClass;
}
}
}
#define DECLARE_DYNCREATE(class_name) \
DECLARE_DYNAMIC(class_name) \
static CObject* PASCAL CreateObject();
CObject* PASCAL CLine::CreateObject()
{
return new CLine;
} \
IMPLEMENT_RUNTIMECLASS(CLine, SHape, 0xFFFF, class_name::CreateObject, NULL)
AFX_COMDAT const CRuntimeClass class_name::class##class_name =
{
"CLine",
sizeof(class CLine),
0xFFFF,
pfnNew,
RUNTIME_CLASS(base_class_name),
NULL,
class_init
};
視圖分割
CSplitterWnd:專門負責窗口切分
創(chuàng)建對話框,視圖:Create函數(shù)
重載父類框架類的虛函數(shù)CFrandWnd::OnCreateClient,這個函數(shù)專門用于切分
動態(tài)創(chuàng)建:Create函數(shù)
靜態(tài)創(chuàng)建:CreateStatic函數(shù)
-
靜態(tài)分割(在窗口創(chuàng)建的時候就已經(jīng)分割好了)
在我們的框架類中:
class CMyFrameWnd:public CFrameWnd{ public: CSplitterWnd spWnd; CSplitterWnd spWnd1; virtual BOOL OnCreateClient(LPCREATESTRUCT* lpcs,CCreateContext* pContext){ spWnd.CreateStatic(this,2,1); spWnd1.CreateStatic(this,1,2,WS_CHILD|WS_CISIBLE,IdFromRowCol(0,0)); return true; } } }
我們這樣寫完了之后,發(fā)現(xiàn)運行不起來,這是因為我們只是創(chuàng)建了框架,但是沒有創(chuàng)建視圖
我們需要給視圖類添加動態(tài)創(chuàng)建機制,我們重新寫代碼:
//我們自己的視圖類: class MyView:public CView{ DECLARE_DYNREATE(MyView); virtual void OnDrow(DCD* pDC){ } } IMPLEMENT_DYNCREATE(MyView,CView) //我們自己的框架窗口類: class CMyFrameWnd:public CFrameWnd{ public: CSplitterWnd spWnd; CSplitterWnd spWnd1; virtual BOOL OnCreateClient(LPCREATESTRUCT* lpcs,CCreateContext* pContext){ spWnd.CreateStatic(this,2,1); spWnd1.CreateStatic(&spWnd,1,2,WS_CHILD|WS_CISIBLE,spWnd,IdFromRowCol(0,0)); //創(chuàng)建視圖: spWnd1.CreateView(0,0,RUNTIME_CLASS(MyVIew),CSize(50,50),pContext); spWnd1.CreateView(0,1,RUNTIME_CLASS(CTreeView),CSize(50,50),pContext); spWnd.CreateView(1,0,RUNTIME_CLASS(CHtmlView),CSize(50,50),pContext); //設(shè)置行信息: spWnd.SetRowInfo(0,200,100); //設(shè)置列信息 spWnd1.SetColumnInfo(0,200,100); spWnd1.SetColumnInfo(1,200,100); CHtmlView* html = (CHtmlView*)spWnd.GetPane(1,0); html->Navigate(L"e:/"); return true; } }
現(xiàn)在我們創(chuàng)建了三個窗口
這些控件都被MFC接管了,Win32 EDIT處理函數(shù),微軟定義的,
如果想要處理消息,就要使用Win32子類化(筆記在本篇最后面)
-
現(xiàn)在我們想處理樹視圖上的消息
-
Create方法:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs,CCreateContext* pContext){ swWnd.CreateStatic(CWnd* pParentEnd,//分隔器窗口的父框架窗口句柄 int nRows,//行數(shù),這個值必須不超過16 int nCols,//列數(shù),這個值必須不超過16 dwStyle,//指定窗口的風格 nID//此窗口的ID,如果這個分隔器窗口不是嵌套在另一個分隔器窗口中的,則這個ID可以是AFX_IDW_PANE_FIRSH )
-
獲取窗口ID:CSplitterWnd::IdFromRowCol方法:
int IdFromRowCol(int row,int col);//參數(shù):行數(shù),列數(shù) 返回值:返回此窗格的子窗口的ID
-
在分隔器中創(chuàng)建一個窗格:CreateVIew方法:
virtual BOOL CreateView(int row,int col,CRuntimeClass* pVIewClass,SIZE sizeInit,CCreateContext* pCOntext); 參數(shù):行數(shù),列數(shù),運行時類信息,初始尺寸,用來創(chuàng)建此試圖的創(chuàng)建環(huán)境的指針
-
-
動態(tài)分隔:
//我們自己的視圖類: class MyView:public CView{ DECLARE_DYNREATE(MyView); virtual void OnDrow(DCD* pDC){ } } IMPLEMENT_DYNCREATE(MyView,CView) //我們自己的框架窗口類: class CMyFrameWnd:public CFrameWnd{ public: CSplitterWnd spWnd; CSplitterWnd spWnd1; virtual BOOL OnCreateClient(LPCREATESTRUCT* lpcs,CCreateContext* pContext){ CCreateContext Context; Context.m_pNewViewClass = RUNTIME_CLASS(MyView); spWnd.Create(this,2,2,CSize(50,50),&Context); return true; } }
- 動態(tài)切分,Create方法:
BOOL CSplitterWnd::Create( CWnd* pParentWnd,//分隔器父窗口的句柄 int nMaxRows,//分隔器窗口的最大行數(shù),這個值不能超過2 int nMaxCols,//分隔器窗口的最大列數(shù),這個值不能超過2 SIZE sizeMin,//指出顯示一個窗格所需的最小尺寸 CCreateCOntext* pContext,//指向一個CCreateContext結(jié)構(gòu)的指針 DWORD dwStyle = WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|SPLS_DYNAMIC_SPLIT,//窗口風格 UINT nID = AFX_IDW_PANE_FIRST//此窗口的子窗口ID。如果這個分隔器窗口不是嵌套在另一個分隔器窗口中的,則這個ID可以是AFX_IDW_PANE_FIRST )
- 動態(tài)切分,Create方法:
Win32子類化
在win32編輯框,可以設(shè)置屬性,風格,字母不可見,****等
現(xiàn)在有一個需求:只允許輸入小寫字母和數(shù)字
C++中,只要繼承,重寫虛函數(shù),在交給父類處理
在Win32中,添加一個編輯框,和一個按鈕,
添加一個全局變量,保存原來的edit消息處理函數(shù)
WNDPROC OldProc;
然后添加按鈕回調(diào)函數(shù):
LRESULT CALLBACK MyProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam){
if(uMsg == WM_CHAR){
if(wParam>='a'&&wParam<='z'||wParam>='0'&&wParam<='9'){
//交給原來的處理函數(shù)處理
return OldProc(hDlg,uMsg,wParam,lParam);
}else{
return 0;
}
}
}
消息處理函數(shù)中:
if(LOWORD(wParam)==IDC_BUTTON1){
//要先找到窗口句柄:
HWND hEdit = GetDlgItem(hDlg,IDC_EDIT1);
//修改原來的過程函數(shù)(原來是操作系統(tǒng)默認的
//OldProc = (WNDPROC)SetWindowLogn(hEdit,GWL_WNDPROC,(LONG)MyProc);
//第二種方式,之前創(chuàng)建的編輯框不好使,但是之后創(chuàng)建的對話框,可以使用
//這個子類化方式實際上是改了類的回調(diào),就是EDIT類的回調(diào),之后創(chuàng)建的EDIt類就好使了
OldProc = (WNDPROC)SetWindowLogn(hEdit,GCL_WNDPROC,(LONG)MyProc);
}
第二種方式:
再添加一個按鈕
HISRANCE hInst;
消息回調(diào):
if(LPWORD(wParam)==IDC_BUTTON2){
CreateWindow(L"EDIT","ads",WS_CHILD|WS_VISIBLE,100,100,100,100,hDlg,NULL,hInst);
}
MFC子類化
這里我們把第一個視圖換成一個窗口(對話框)
- 創(chuàng)建一個對話框
- 為該對話框添加一個類:CMyFormView
- 主cpp中,包含剛才添加的類的頭文件
- 然后把第一個改為我們創(chuàng)建的類
//我們自己的視圖類: class MyView:public CView{ DECLARE_DYNREATE(MyView); virtual void OnDrow(DCD* pDC){ } } IMPLEMENT_DYNCREATE(MyView,CView) //我們自己的框架窗口類: class CMyFrameWnd:public CFrameWnd{ public: CSplitterWnd spWnd; CSplitterWnd spWnd1; virtual BOOL OnCreateClient(LPCREATESTRUCT* lpcs,CCreateContext* pContext){ spWnd.CreateStatic(this,2,1); spWnd1.CreateStatic(&spWnd,1,2,WS_CHILD|WS_CISIBLE,spWnd,IdFromRowCol(0,0)); //創(chuàng)建視圖: spWnd1.CreateView(0,0,RUNTIME_CLASS(MyFormView),CSize(50,50),pContext); spWnd1.CreateView(0,1,RUNTIME_CLASS(CTreeView),CSize(50,50),pContext); spWnd.CreateView(1,0,RUNTIME_CLASS(CHtmlView),CSize(50,50),pContext); //設(shè)置行信息: spWnd.SetRowInfo(0,200,100); //設(shè)置列信息 spWnd1.SetColumnInfo(0,200,100); spWnd1.SetColumnInfo(1,200,100); CHtmlView* html = (CHtmlView*)spWnd.GetPane(1,0); html->Navigate(L"e:/"); return true; } }
- 需要把我們創(chuàng)建的對話框修改為子窗口類,否則會報錯
-
DDX/DDV虛函數(shù):
就是空間綁定變量/數(shù)據(jù),調(diào)用UpdataTA(),交互數(shù)據(jù)用
控件綁定變量文章來源:http://www.zghlxwxcb.cn/news/detail-644777.html
值綁定變量文章來源地址http://www.zghlxwxcb.cn/news/detail-644777.html
到了這里,關(guān)于【MFC】10.MFC六大機制:RTTI(運行時類型識別),動態(tài)創(chuàng)建機制,窗口切分,子類化-筆記的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!