程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> ASP編程 >> ASP技巧 >> MFC中自定義窗口類名

MFC中自定義窗口類名

編輯:ASP技巧

MFC中封裝很多常用的控件,把類名也給封裝了,沒有提供明顯的接口出來,用win api寫窗口程序,第一步就是注冊窗口類

此時類名和標題名是一起注冊的,所以能把標題很好地讓用戶來設定,類名也應該是很簡單的,可惜的是MFC沒有這樣做,原因也許是window name可以不停的改,而類名不能。窗口的類名是有Create來確定的,要在Create前,給窗口選擇一個已經注冊的窗口類名,作為參數窗口Create就ok了,CWnd的Create最終還是到了CreateEx中來,看看CreateEx就會清楚許多

 

BOOL CWnd::CreateEx(DWord dwExStyle, LPCTSTR lpszClassName,        LPCTSTR lpszWindowName, DWORD dwStyle,        const RECT& rect, CWnd* pParentWnd, UINT nID,        LPVOID lpParam /* = NULL */){    return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,        rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,        pParentWnd->GetSafeHwnd(), (HMENU)(UINT_PTR)nID, lpParam);}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){    ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) ||         AfxIsValidAtom(lpszClassName));    ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));        // allow modification of several common create parameters    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);    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);#ifdef _DEBUG    if (hWnd == NULL)    {        TRACE(traceAppMsg, 0, "Warning: Window creation failed: GetLastError returns 0x%8.8X\n",            GetLastError());    }#endif    if (!AfxUnhookWindowCreate())        PostNcDestroy();        // cleanup if CreateWindowEx fails too soon    if (hWnd == NULL)        return FALSE;    ASSERT(hWnd == m_hWnd); // should have been set in send msg hook    return TRUE;}
可以看到最後到了::AfxCtxCreateWindowEx,可以很容易地知道這裡調用了CreateWindowEx來創建一個窗口

 

在前面有一個PreCreateWindow(cs),而cs經過PreCreateWindow處理後,交給::AfxCtxCreateWindowEx處理

::AfxCtxCreateWindowEx在中轉給CreateWindowEx,cs.lpszClass就是類名,可以清楚了AfxCtxCreateWindowEx的用心良苦

 


我們可以重載的PreCreateWindow,來修改類名,如下的代碼:

 

// TODO: 在此添加專用代碼和/或調用基類    //VERIFY(AfxDeferRegisterClass(AFX_WND_REG));    //AfxEndDeferRegisterClass(AFX_WND_REG);    //cs.lpszClass = AfxRegisterWndClass(NULL);    WNDCLASS wndcls;    memset(&wndcls, 0, sizeof(WNDCLASS));   // start with NULL    // defaults    wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;    //you can specify your own window procedure    wndcls.lpfnWndProc = ::DefWindowProc;     wndcls.hInstance = AfxGetInstanceHandle();    wndcls.hIcon =  NULL; // or load a different icon    wndcls.hCursor =NULL;    wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);    wndcls.lpszMenuName = NULL;    // Specify your own class name for using FindWindow later    wndcls.lpszClassName = _T("MyNewClass");    // Register the new class and exit if it fails    if(!AfxRegisterClass(&wndcls))    {        TRACE("Class Registration Failed\n");        return FALSE;    }    cs.lpszClass = wndcls.lpszClassName;    return TRUE;    //return CWnd::PreCreateWindow(cs);


其實就是為了把一個已經注冊的類名字符串傳給CreateWindowEx,從上面代碼中的注釋中來看,我還用了一種讓系統來生成className的方法AfxRegisterWndClass。CWnd::PreCreateWindow不符合我的心意,注釋掉了,其實裡面也沒什麼就是判斷而已。而在MFC中CWnd其他派生類就不這麼簡單了,不過單純的修改類名,就重載這個方法大多就ok了。

是的,只是大多數可以的,可惜的是這個方法,對於Dialog來說並不行,因為它不用CWnd::Create,也就繞不到

PreCreateWindow上來了,你可以重載對話框的這個方法,斷點,是斷不下來的。因為CDialog的創建可以直接用系統的api來搞,不用再勞駕CWnd來中轉到CReateWindowEx了,所以就不能夠用上述方法來改對話框的類名了。

看下它的創建代碼了:


BOOL CDialog::Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd){    ASSERT(IS_INTRESOURCE(lpszTemplateName) ||        AfxIsValidString(lpszTemplateName));    m_lpszTemplateName = lpszTemplateName;  // used for help    if (IS_INTRESOURCE(m_lpszTemplateName) && m_nIDHelp == 0)        m_nIDHelp = LOWORD((DWord_PTR)m_lpszTemplateName);#ifdef _DEBUG    if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE))    {        ASSERT(FALSE);          // invalid dialog template name        PostNcDestroy();        // cleanup if Create fails too soon        return FALSE;    }#endif //_DEBUG    HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG);    HRSRC hResource = ::FindResource(hInst, lpszTemplateName, RT_DIALOG);    HGLOBAL hTemplate = LoadResource(hInst, hResource);    BOOL bResult = CreateIndirect(hTemplate, pParentWnd, hInst);    FreeResource(hTemplate);    return bResult;}

 

可以看出來CDialog是靠資源來創建的,可以這樣來來搞的,在資源腳本中定義Class “對話框類名”在對話框domodal或者Create前注冊這個類名,然後等著modal和Create後就可以了。

 

 

這段時間,一直忙一些其他方面了,對MFC封裝機制淡忘了不少,跟蹤下代碼,算是溫習一下了。

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved