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

——-先以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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值