深入浅出MFC:动态创建控件

来源:互联网 发布:linux安卓 编辑:程序博客网 时间:2024/05/15 09:00

——-先以CButton为例讲解MFC中动态创建控件———
在对话框类中增加了以下3个成员变量:
CButton m_btn1;
CButton m_btn2;
CButton m_btn3;

在对话框的OnInitDialog函数中写入了如下代码动态创建控件

BOOL OnInitDialog{    m_btn1.CreateEx(0, TEXT("BUTTON"), TEXT("Btn_1"), WS_CHILD | WS_VISIBLE, 10, 10, 100, 20,                    this->GetSafeHwnd(), (HMENU)IDC_BTN_DYN_BEG, 0);    m_btn2.CreateEx(0, TEXT("BUTTON"), NULL, WS_CHILD | WS_VISIBLE, 10, 40, 100, 20,                    this->GetSafeHwnd(), (HMENU)IDC_BTN_DYN_BEG+1, 0);    m_btn2.SetWindowText(TEXT("Btn_2"));    m_btn3.Create(TEXT("Btn_3"), WS_CHILD | WS_VISIBLE, CRect(10, 70, 110, 90), this, IDC_BTN_DYN_BEG+4);}

我们现在来研究一下代码的本质:
m_btn1.CreateEx与m_btn2.CreateEx实际上调用的CWnd::CreateEx
m_btn3.Create调用了CButton::Create
先来瞧瞧CButton::Create,其中调用了CWnd::Create

BOOL CButton::Create(LPCTSTR lpszCaption, DWORD dwStyle,                     const RECT& rect, CWnd* pParentWnd, UINT nID){    CWnd* pWnd = this;    return pWnd->Create(_T("BUTTON"), lpszCaption, dwStyle, rect, pParentWnd, nID);}

CWnd::Create调用了CWnd::CreateEx

BOOL CWnd::Create(LPCTSTR lpszClassName,                  LPCTSTR lpszWindowName, DWORD dwStyle,                  const RECT& rect,                  CWnd* pParentWnd, UINT nID,                  CCreateContext* pContext){    return CreateEx(0, lpszClassName, lpszWindowName,                    dwStyle | WS_CHILD,                    rect.left, rect.top,                    rect.right - rect.left, rect.bottom - rect.top,                    pParentWnd->GetSafeHwnd(), (HMENU)(UINT_PTR)nID, (LPVOID)pContext);}

研究CWnd::CreateEx才能看出本质

[wincore.cpp]

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,                    LPCTSTR lpszWindowName, DWORD dwStyle,                    int x, int y, int nWidth, int nHeight,                    HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam){    CREATESTRUCT cs;    cs.dwExStyle = dwExStyle;    cs.lpszClass = lpszClassName;    cs.lpszName = lpszWindowName;    cs.style = dwStyle;    cs.x = x;    cs.y = y;    cs.cx = nWidth;    cs.cy = nHeight;    cs.hwndParent = hWndParent;    cs.hMenu = nIDorHMenu;    cs.hInstance = AfxGetInstanceHandle();    cs.lpCreateParams = lpParam;    if (!PreCreateWindow(cs))    {        PostNcDestroy();        return FALSE;    }    AfxHookWindowCreate(this);   //利用Hook进行了子类化    HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,                    cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,                    cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);    return TRUE;}

[wincore.cpp]

void AFXAPI AfxHookWindowCreate(CWnd* pWnd){    pThreadState->m_pWndInit == pWnd;    if (pThreadState->m_hHookOldCbtFilter == NULL)    {        pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,            _AfxCbtFilterHook, NULL, ::GetCurrentThreadId());    }    pThreadState->m_pWndInit = pWnd;}

[wincore.cpp]

LRESULT CALLBACK _AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam){    pWndInit->Attach(hWnd);    pWndInit->PreSubclassWindow();    WNDPROC *pOldWndProc = pWndInit->GetSuperWndProcAddr();    WNDPROC afxWndProc = AfxGetAfxWndProc();    //改写了窗口过程函数为MFC通用的窗口过程函数也即子类化    oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,                                           (DWORD_PTR)afxWndProc);       if (oldWndProc != afxWndProc)        *pOldWndProc = oldWndProc;    pThreadState->m_pWndInit = NULL;}

所以动态创建控件全部都进行了子类化
以下列出了MFC中具体控件对应的窗口类名称
(由于BUTTON按钮对应了PUSHBUTTON&CHECKBOX&RADIOBOX等,按钮样式区分了创建按钮的类型)
显然:
Button———- CButton—— “BUTTON” — BS_PUSHBUTTON
Check Box——- CButton—— “BUTTON” — BS_AUTOCHECKBOX
Radio Button—- CButton—— “BUTTON” — BS_AUTORADIOBUTTON
Edit Control—- CEdit——– “EDIT”
Combo Box——- CComboBox—- “COMBOBOX”
List Box——– CListBox—– “SysListView32”

如果要动态创建Check Box,代码如下

CButton m_btnChk;m_btnChk.CreateEx(0, TEXT("BUTTON"), NULL, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 10, 160, 100, 20,                  this->GetSafeHwnd(), (HMENU)1250, 0);

在CButton实例对象调用CreateEx时指定窗口类名为”EDIT”都可以,只不过创建的控件就是Edit Box了

m_btn1.CreateEx(0, TEXT("EDIT"), TEXT("Btn_1"), WS_CHILD | WS_VISIBLE, 10, 10, 100, 20,this->GetSafeHwnd(), (HMENU)IDC_BTN_DYN_BEG, 0);
0 0