青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

旅途

如果想飛得高,就該把地平線忘掉

走出MFC子類化的迷宮

走出MFC子類化的迷宮

KEY WORDS:子類化 SUBCLASSWINDOW  MFC消息機(jī)制

 

許多Windows程序員都是跳過SDK直接進(jìn)行RAD開發(fā)工具[VC,我想VC應(yīng)不屬于RAD]的學(xué)習(xí),有些人可能對子類化機(jī)制比較陌生。

我們先看看什么是Windows的子類化。Windows給我們或是說給它自己定義了許多豐富的通用控件,如:EditComboBox ListBox……等,這些控件功能豐富,能為我們開發(fā)工作帶來極大方面,試想:我們單單是自己實(shí)現(xiàn)一個(gè)EDIT控件是多么的艱難!但是,在實(shí)際開發(fā)中還是有些情況這些標(biāo)準(zhǔn)控件也無能為力,比如:在我們的應(yīng)用中要求一個(gè)EDIT得到老師對學(xué)生的評(píng)價(jià)ABC[不要對我說你想用ComboBox實(shí)現(xiàn)J],這時(shí),要求在Edit中禁止對其它字母、數(shù)字的輸入操作,怎么辦?EDIT控件本身沒有提供這種機(jī)制,我們就可以采用子類化很好的解決這類問題。

我們知道,每一個(gè)Windows窗口[這里是EDIT]都有一個(gè)窗口處理函數(shù)負(fù)責(zé)對消息處理,子類化的辦法就是用我們自己的消息處理函數(shù)來替代窗口原有的、標(biāo)準(zhǔn)的處理函數(shù)。當(dāng)然我們自己的窗口處理函數(shù)只是關(guān)心那些特定的消息[在這里當(dāng)然是WM_CHAR],而其它消息,再發(fā)給原來的窗口函數(shù)處理。在SDK中的實(shí)現(xiàn)方法是調(diào)用函數(shù)SetWindowLong

WNDPROC * oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC,(DWORD)AfxGetAfxWndProc());

其中AfxGetAfxWndProc()是我們自己的窗口處理函數(shù),在其中處理過我們感興趣的消息后就可能通過返回的原窗口處理函數(shù)指針oldWndProc來把其它消息按標(biāo)準(zhǔn)方法處理掉,具體做法請查閱相關(guān)資料。

但到了MFC“時(shí)代”,一切都被包裝起來了,原來的窗口類注冊、窗口函數(shù)都不見了[或是說隱身了],我想對于那些“刨根問底”的程序員有興趣了解在MFC中的子類化機(jī)制,本人就自己做的一點(diǎn)“探索”作出總結(jié),希望能給大家點(diǎn)啟示。

我們先用MFC實(shí)現(xiàn)我上面提到的要求:一個(gè)只能輸入ABCEDIT控件。

啟動(dòng)時(shí)界面如下:

輸入時(shí)就只能輸入ABC,并且只允許輸入一個(gè)字母。

實(shí)現(xiàn)方法:

先派生一個(gè)自己的類CsuperEditCtrl + W后,在其中處理WM_CHAR,然后再編輯這個(gè)消息處理函數(shù):

 

void CSuperEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

     // TODO: Add your message handler code here and/or call default

     TCHAR ch[20];

     GetWindowText(ch,20);

     if (strlen(ch) == 1 && (nChar <= 'C' && nChar >= 'A'))

            return;

     if (nChar != 'A'

            && nChar != 'B'

            && nChar != 'C'

            )

            return;

    

     CEdit::OnChar(nChar, nRepCnt, nFlags);

}

 

然后再給我們Cprog1Dlg類中加入一個(gè)數(shù)據(jù)成員CsuperEdit m_edit,在CProg1Dlg::OnInitDialog()中加入:

m_edit.SubclassDlgItem(IDC_EDIT1,this);

     m_edit.SetWindowText("<請輸入ABC>");

并處理EDITDIALOG發(fā)送的通知消息:EN_SETFOCUS

void CProg1Dlg::OnSetfocusEdit1()

{

     // TODO: Add your control notification handler code here

     m_edit.SetWindowText("");

     m_edit.SetFocus();

}

 

OK,一切搞定!和SDK的子類化方法比起來,這是多么的容易!

我們看看MFC背著我們到底做了什么!這里主要解決兩個(gè)容易讓初學(xué)者比較疑惑的問題:

1、    m_edit只是我們定義的一個(gè)C++類對象,為什么通過它調(diào)用其成員函數(shù)SetWindowText便可以控制我們程序中資源編號(hào)為:IDC_EDIT1的控件?

2、    CSuperEdit類為什么可以處理WM_CHAR消息?

 

大家都知道,控制Windows窗口、控件、資源……都是通過它們的句柄來實(shí)現(xiàn),如
HHANDLE
HWNDHDC都是句柄,它表現(xiàn)為一個(gè)32位長整形數(shù)據(jù),存放于Windows中的特定區(qū)域,我們可以把它理解為指向我們想控制的窗口、控件、資源的索引,有了它,我們就可以控制我們想要控制的對象

這里你可以想到為什么多數(shù)API函數(shù)都有一個(gè)參數(shù)HWND hwnd了吧!

BOOL SetWindowText(
  HWND hWnd,         // handle to window or control
  LPCTSTR lpString   // title or text
);

我們的C++變量m_edit要想控制IDC_EDIT1,也要通過它的句柄,但這又是如何實(shí)現(xiàn)的呢?您可能注意到了m_edit.SubclassDlgItem(IDC_EDIT1,this);一句,對了,這就是關(guān)鍵所在!

在此處F9設(shè)置斷點(diǎn),F5之后,程序到達(dá)此處,F11跟入SubclassDlgItem函數(shù):

BOOL CWnd::SubclassDlgItem(UINT nID, CWnd* pParent)

{

     ASSERT(pParent != NULL);

     ASSERT(::IsWindow(pParent->m_hWnd));

 

     // check for normal dialog control first

     HWND hWndControl = ::GetDlgItem(pParent->m_hWnd, nID);

     if (hWndControl != NULL)

            return SubclassWindow(hWndControl);

 

#ifndef _AFX_NO_OCC_SUPPORT

     if (pParent->m_pCtrlCont != NULL)

     {

            // normal dialog control not found

            COleControlSite* pSite = pParent->m_pCtrlCont->FindItem(nID);

            if (pSite != NULL)

            {

                   ASSERT(pSite->m_hWnd != NULL);

                   VERIFY(SubclassWindow(pSite->m_hWnd));

 

#ifndef _AFX_NO_OCC_SUPPORT

                   // If the control has reparented itself (e.g., invisible control),

                   // make sure that the CWnd gets properly wired to its control site.

                   if (pParent->m_hWnd != ::GetParent(pSite->m_hWnd))

                          AttachControlSite(pParent);

#endif //!_AFX_NO_OCC_SUPPORT

 

                   return TRUE;

            }

     }

#endif

 

     return FALSE;   // control not found

}

代碼開始時(shí)對傳入的父窗口做些檢查,然后就是

HWND hWndControl = ::GetDlgItem(pParent->m_hWnd, nID);

     if (hWndControl != NULL)

            return SubclassWindow(hWndControl);

這是關(guān)鍵的代碼,先用hWndControl得到我們IDC_EDIT1控件的句柄,然后調(diào)用

SubclassWindow函數(shù),這個(gè)函數(shù)是實(shí)現(xiàn)的關(guān)鍵,我們來看一下它做了什么:

 

 

 

BOOL CWnd::SubclassWindow(HWND hWnd)

{

     if (!Attach(hWnd))

            return FALSE;

 

     // allow any other subclassing to occur

     PreSubclassWindow();

 

     // now hook into the AFX WndProc

     WNDPROC* lplpfn = GetSuperWndProcAddr();

     WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC,     (DWORD)AfxGetAfxWndProc());

     ASSERT(oldWndProc != (WNDPROC)AfxGetAfxWndProc());

 

     if (*lplpfn == NULL)

            *lplpfn = oldWndProc;   // the first control of that type created

#ifdef _DEBUG

     else if (*lplpfn != oldWndProc)

     {

            TRACE0("Error: Trying to use SubclassWindow with incorrect CWnd\n");

            TRACE0("\tderived class.\n");

            TRACE3("\thWnd = $%04X (nIDC=$%04X) is not a %hs.\n", (UINT)hWnd,

                   _AfxGetDlgCtrlID(hWnd), GetRuntimeClass()->m_lpszClassName);

            ASSERT(FALSE);

            // undo the subclassing if continuing after assert

            ::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)oldWndProc);

     }

#endif

 

     return TRUE;

}

 

函數(shù)Attach內(nèi)部如下:

BOOL CWnd::Attach(HWND hWndNew)

{

       ASSERT(m_hWnd == NULL);     // only attach once, detach on destroy

       ASSERT(FromHandlePermanent(hWndNew) == NULL);

              // must not already be in permanent map

 

       if (hWndNew == NULL)

              return FALSE;

 

       CHandleMap* pMap = afxMapHWND(TRUE); // create map if not exist

       ASSERT(pMap != NULL);

 

       pMap->SetPermanent(m_hWnd = hWndNew, this);

 

#ifndef _AFX_NO_OCC_SUPPORT

       AttachControlSite(pMap);

#endif

 

       return TRUE;

}

 

這里要說明的是pMap->SetPermanent(m_hWnd = hWndNew, this);一句,它把我們IDC_EDIT1的句柄賦值給類CsuperEdit的數(shù)據(jù)成員m_hWnd [別忘了我們的CsuperEdit類是派生于Cedit],大家可能現(xiàn)在已經(jīng)隱約的明白了些什么,不錯(cuò),在m_edit.SetWindowText("<請輸入ABC>");中正是通過這個(gè)數(shù)據(jù)成員m_hWnd實(shí)現(xiàn)對IDC_EDIT1控制的:

void CWnd::SetWindowText(LPCTSTR lpszString)

{

       ASSERT(::IsWindow(m_hWnd));

 

       if (m_pCtrlSite == NULL)

              ::SetWindowText(m_hWnd, lpszString);

       else

              m_pCtrlSite->SetWindowText(lpszString);

}

其它CEdit類的函數(shù)也都是圍繞 m_hWnd + API函數(shù)” 進(jìn)行包裝的。

而我們常用的DDX_Control方法說到底也是調(diào)用SubclassWindow

 

怎么樣?第一個(gè)問題的來龍去脈搞明白了吧?

 

現(xiàn)在看看第二個(gè)問題:CSuperEdit類為什么可以處理WM_CHAR消息?

可能有的朋友現(xiàn)在疑惑,雖然通過句柄實(shí)現(xiàn)了m_editIDC_EDIT的控制,但發(fā)送給它的消息照樣跑到EDIT的標(biāo)準(zhǔn)處理函數(shù)中,對WM_CHAR的處理是如何實(shí)現(xiàn)的呢?

如果消息照樣跑到EDIT的標(biāo)準(zhǔn)處理函數(shù)中,那當(dāng)然是不能處理了!不知您有沒有看到在上面的SubclassWindow函數(shù)中有這么一小段我加了重點(diǎn)標(biāo)示:

// now hook into the AFX WndProc

     WNDPROC* lplpfn = GetSuperWndProcAddr();

     WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC,     (DWORD)AfxGetAfxWndProc());

     ASSERT(oldWndProc != (WNDPROC)AfxGetAfxWndProc());

 

     if (*lplpfn == NULL)

            *lplpfn = oldWndProc;   // the first control of that type created

再和我們開始講到的SDK中子類化機(jī)制聯(lián)系起來,明白了吧?MFC在這里神不知鬼不覺的搞起偷天換日的勾當(dāng)!

這個(gè)AfxGetAfxWndProc()函數(shù)是這樣的:

 

 

WNDPROC AFXAPI AfxGetAfxWndProc()

{

#ifdef _AFXDLL

       return AfxGetModuleState()->m_pfnAfxWndProc;

#else

       return &AfxWndProc;

#endif

}

讀過侯捷先生《深入淺出MFC》的朋友不知還是否記得MFC的命令路由機(jī)制正是以這個(gè)函數(shù)為起點(diǎn)的!

這樣當(dāng)程序收到發(fā)給EditWM_CHAR時(shí),本應(yīng)調(diào)用EDIT標(biāo)準(zhǔn)窗口處理函數(shù),現(xiàn)在被改為調(diào)用LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)了,然后WM_CHAR消息進(jìn)行一系列的流竄,最終成功到達(dá)我們的處理函數(shù)CSuperEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags),至于是如何流竄的、怎么到達(dá)的請參考《深入淺出MFC[如果您的書是繁體電子版,請從566頁讀起]

 

終于,我們走出了FMC子類化的迷宮。

 

posted on 2007-07-17 23:42 旅途 閱讀(221) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 深入windows

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美色视频在线| 欧美视频中文一区二区三区在线观看| 国产日本欧美视频| 香蕉久久a毛片| 亚洲第一综合天堂另类专| 1024欧美极品| 欧美视频在线一区| 欧美激情久久久久久| 亚洲最新中文字幕| 欧美高清不卡| 国产一区二区三区四区五区美女 | 一区二区日韩| 亚洲免费在线观看| 亚洲日产国产精品| 国产亚洲精品高潮| 欧美三级资源在线| 亚洲第一页在线| 一本久久精品一区二区| 国产精品永久免费观看| 国产欧美日韩三级| 国产一区在线播放| 亚洲乱码久久| 欧美一级午夜免费电影| 开心色5月久久精品| 欧美激情第三页| 国产精品99久久久久久有的能看| 欧美一级视频精品观看| 欧美精品一区在线观看| 国产日韩精品入口| 夜夜嗨av一区二区三区四季av | 99成人在线| 久久福利视频导航| 亚洲国产精品高清久久久| 夜夜狂射影院欧美极品| 久久成人综合视频| 国产精品久久久久久超碰| 亚洲国产精品va在线观看黑人| 亚洲欧美国产精品va在线观看| 欧美成人三级在线| 欧美一区二区三区婷婷月色| 欧美日韩直播| 亚洲免费观看视频| 欧美国产日韩二区| 欧美在线观看一二区| 国产精品高潮在线| 99热免费精品| 亚洲国产岛国毛片在线| 欧美在线一二三区| 国产色综合久久| 性欧美1819性猛交| 亚洲夜晚福利在线观看| 欧美日韩一区在线视频| 亚洲精品麻豆| 欧美国产第一页| 久久先锋影音| 亚洲黄色免费| 欧美国产专区| 欧美福利视频在线| 日韩一级不卡| 亚洲精品在线一区二区| 欧美国产第一页| 99av国产精品欲麻豆| 亚洲区一区二区三区| 一本久久综合亚洲鲁鲁五月天| 亚洲黄色免费电影| 亚洲第一色中文字幕| 久久综合九色欧美综合狠狠| 黄色日韩在线| 欧美国产视频在线| 久久伊人免费视频| 亚洲人成网站999久久久综合| 欧美成熟视频| 欧美黄色一级视频| 亚洲视频精品| 性娇小13――14欧美| 好吊视频一区二区三区四区| 免费成人在线视频网站| 美女尤物久久精品| 99这里只有精品| 亚洲无人区一区| 国产一区二区三区黄视频| 久久偷窥视频| 欧美激情精品久久久久久变态| 99xxxx成人网| 午夜影院日韩| 亚洲国产成人tv| 亚洲毛片在线看| 国产视频精品网| 欧美成人午夜免费视在线看片| 欧美精品在线一区二区| 午夜精品久久久久久久99热浪潮| 欧美一级成年大片在线观看| 亚洲国产一区二区三区在线播| 日韩视频在线观看一区二区| 国产日韩久久| 亚洲黄色毛片| 国产视频不卡| 亚洲精品四区| 在线观看欧美日本| 日韩视频在线一区二区| 国产永久精品大片wwwapp| 亚洲国产精品va在线看黑人 | 亚洲国产精品嫩草影院| 国产精品成人观看视频免费 | 国产精品99久久99久久久二8 | 欧美精品激情| 久久精品首页| 欧美日韩的一区二区| 久久免费精品视频| 欧美日韩一区二区在线观看视频| 久久免费国产精品| 国产精品久久久久久影视| 美女视频黄a大片欧美| 国产精品高精视频免费| 亚洲人成在线影院| 伊人狠狠色j香婷婷综合| 亚洲无限乱码一二三四麻| 亚洲精品一区二| 久久影院午夜片一区| 欧美日韩国产美| 亚洲成色www久久网站| 中文欧美日韩| 亚洲人成在线观看| 欧美一区精品| 欧美在线视频播放| 国产精品久久久久久久久久久久久 | 日韩视频一区二区三区在线播放免费观看 | 一区二区三区四区五区视频| 在线日韩av| 欧美在线视频观看免费网站| 亚洲欧美一区二区在线观看| 欧美日韩另类字幕中文| 亚洲精华国产欧美| 亚洲国产精品va在看黑人| 久久高清国产| 久久久久在线观看| 韩国福利一区| 久久久久久久综合狠狠综合| 久久久精品免费视频| 国产性天天综合网| 性欧美激情精品| 久久久精品国产一区二区三区 | 国产欧美69| 亚洲欧美区自拍先锋| 亚洲欧美日韩精品久久亚洲区| 欧美三级视频在线观看| 一区二区不卡在线视频 午夜欧美不卡在 | 欧美搞黄网站| 日韩视频免费观看高清在线视频 | 国产精品久久久久久亚洲调教| 一二美女精品欧洲| 亚洲专区欧美专区| 国产精品久久久久久五月尺| 亚洲男女自偷自拍图片另类| 久久精品国产亚洲一区二区三区| 国产综合色一区二区三区| 久久久久九九视频| 欧美黄色免费| 一区二区欧美国产| 国产精品区一区二区三| 欧美一区二区三区电影在线观看| 久久久久久久999| 亚洲国产成人不卡| 欧美日韩国产在线看| 欧美日本韩国一区二区三区| 欧美99久久| 99re热精品| 国产人成精品一区二区三| 久久久久久成人| 日韩视频免费在线| 久久久91精品国产一区二区精品| 亚洲第一网站免费视频| 欧美日韩日韩| 久久国产综合精品| 亚洲精品美女在线观看播放| 亚洲欧美综合另类中字| 在线观看视频免费一区二区三区 | 久久影院午夜片一区| 亚洲精品日韩在线观看| 久久aⅴ乱码一区二区三区| 在线日韩一区二区| 国产精品xxxxx| 久久天天躁夜夜躁狠狠躁2022| 亚洲九九九在线观看| 美女网站久久| 小辣椒精品导航| 亚洲精品视频免费观看| 国产一区二区剧情av在线| 欧美极品在线观看| 欧美亚洲日本一区| 999亚洲国产精| 欧美成人中文字幕| 久久黄色影院| 亚洲一二三四久久| 亚洲欧洲综合| 在线观看不卡av| 国产视频一区在线观看一区免费| 欧美人与禽性xxxxx杂性| 久久综合九色综合网站| 香蕉视频成人在线观看|