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

微塵--KeepMoving

為了忘卻的記憶
posts - 3, comments - 2, trackbacks - 0, articles - 13
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

摘要

作為一個程序員,我們經常會在程序中用到Windows通用控件。比如按鈕控件,進度條控件等等。但是有時我們需要給控件更多的特色,這就需要做控件的子類化(subclassing).

子類化一個Windows控件與子類化一個C++類不同,子類化一個控件要求你把一個窗口的一些或所有的消息映射都替換成自己的函數來響應,這樣你就有效的阻止了控件去做系統默認的行為,而按自己的想法去做。子類化有兩種類型:實例子類化(instance subclassing)和全局子類化(global subclassing)。實例子類化是子類化一個窗口中的單一實例,全局子類化是把整個窗口子類化為一個特殊的類型。這里我們僅討論單一實例子類化。

記住CWnd派生類對象與窗口本身(一個HWND)的差別是很重要的。你的C++CWnd-派生類對象包含了一個指向HWND的成員函數,并且包含了當處理消息時HWND消息泵的響應函數(比如WM_PAINT,WM_MOUSEMOVE)。但你用一個C++對象子類化一個窗口時,你就把HWND與C++對象關聯起來,并且設置了處理消息時把自定義的回調函數提供給HWND消息使用。

子類化過程很簡單,首先創建一個類映射窗口的所有消息,然后把控件用作為這個類的實例。例如,下面的例子中我們做一個按鈕的子類化。

新類

為了子類化一個控件,我們需要創建一個新類,并映射所有我們感興趣的消息。為了簡便,我們一般都從控件標準類中派生自己的新類,這里與按鈕控件對應的標準類為CButton。

下面假定我們要實現的效果是,當鼠標懸停在按鈕上方時,按鈕顯示為黃色。首先我們使用ClassWizard創建一個CButton的派生類,叫做CMyButton。

 

在MFC框架中從CButton派生自己的類有許多好處,最大的好處是我們不用手工添加任何一行代碼就可以創建了一個擁有全部默認功能的Windows控件。因為MFC實現了所有的默認的消息映射,因此我們可以挑選我們感興趣的消息自己處理,而不用去管其他消息。

這里我們要為按鈕設計的功能是,鼠標懸停時變為黃色。

為了檢查鼠標是否懸停于按鈕上,我們設置一個成員變量m_bOverControl ,TRUE表示鼠標懸停,然后設置一個周期(使用定時器)跟蹤鼠標是否已離開控件,這是因為,系統并沒有OnMouseEnterOnMouseLeave函數供我們調用,因此我們必須使用OnMouseMove。如果,在一個時間點上,發現鼠標已離開按鈕,我們關閉定時器并重畫控件。

使用ClassWizard加入WM_MOUSEMOVE和WM_TIMER的消息映射,響應函數分別是OnMouseMoveOnTimer。

 

ClassWizard將在你的按鈕類文件中加入下面的代碼:

BEGIN_MESSAGE_MAP(CMyButton, CButton)//{{AFX_MSG_MAP(CMyButton)
ON_WM_MOUSEMOVE()
ON_WM_TIMER()//}}AFX_MSG_MAP
END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CMyButton message handlersvoid CMyButton::OnMouseMove(UINT nFlags, CPoint point)
{// TODO: Add your message handler code here and/or call default
CButton::OnMouseMove(nFlags, point);
}void CMyButton::OnTimer(UINT nIDEvent)
{// TODO: Add your message handler code here and/or call default
CButton::OnTimer(nIDEvent);
}

消息映射的入口(即BEGIN_MESSAGE_MAP) 建立了窗口消息與響應函數的對應關系。ON_WM_MOUSEMOVE把WM_MOUSEMOVE消息與OnMouseMove函數建立響應的關系,ON_WM_TIMER m把WM_TIMER消息與OnTimer函數建立了響應的關系。這些宏定義在MFC的源文件中,我們不需要去看,只要按照約定來做就可以了。

假設我們已經聲明了兩個變量m_bOverControlm_nTimerID,類型分別是BOOL和UINT, 并且在類的構造函數中把它們初始化,我們的消息處理應使用下面的代碼:

void CMyButton::OnMouseMove(UINT nFlags, CPoint point)
{if (!m_bOverControl)// Cursor has just moved over control
{
TRACE0("Entering controln");
m_bOverControl = TRUE;// Set flag telling us the mouse is in
Invalidate();// Force a redraw
SetTimer(m_nTimerID,100, NULL);// Keep checking back every 1/10 sec
}
CButton::OnMouseMove(nFlags, point);// drop through to default handler
}void CMyButton::OnTimer(UINT nIDEvent)
{// Where is the mouse?
CPoint p(GetMessagePos());
ScreenToClient(&p);// Get the bounds of the control (just the client area)
CRect rect;
GetClientRect(rect);// Check the mouse is inside the controlif (!rect.PtInRect(p))
{
TRACE0("Leaving controln");// if not then stop looking...
m_bOverControl = FALSE;
KillTimer(m_nTimerID);// ...and redraw the control
Invalidate();
}// drop through to default handler
CButton::OnTimer(nIDEvent);
}

最后我們來畫出我們需要的效果,我們不再進行消息映射,而是重載CWnd::DrawItem虛函數。只有當控件設置owner-drawn風格時這個函數才能被調用,并且這個函數沒有默認的實現代碼,虛函數的設計只為了在派生類中進行實現。

 

使用ClassWizard重載DrawItem函數,并加入下面的代碼

void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC* pDC   = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rect = lpDrawItemStruct->rcItem;
UINT state = lpDrawItemStruct->itemState;
CString strText;
GetWindowText(strText);// draw the control edges (DrawFrameControl is handy!)if (state & ODS_SELECTED)
pDC->DrawFrameControl(rect, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_PUSHED);else
pDC->DrawFrameControl(rect, DFC_BUTTON, DFCS_BUTTONPUSH);// Deflate the drawing rect by the size of the button’s edges
rect.DeflateRect( CSize(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)));// Fill the interior color if necessaryif (m_bOverControl)
pDC->FillSolidRect(rect, RGB(255,255,0));// yellow// Draw the textif (!strText.IsEmpty())
{
CSize Extent = pDC->GetTextExtent(strText);
CPoint pt( rect.CenterPoint().x - Extent.cx/2,
rect.CenterPoint().y - Extent.cy/2 );if (state & ODS_SELECTED)
pt.Offset(1,1);int nMode = pDC->SetBkMode(TRANSPARENT);if (state & ODS_DISABLED)
pDC->DrawState(pt, Extent, strText, DSS_DISABLED, TRUE,0, (HBRUSH)NULL);else
pDC->TextOut(pt.x, pt.y, strText);
pDC->SetBkMode(nMode);
}
}

接下來,我們剩下最后一步。為控件設置owner drawn風格。我們可以在對話框的資源編輯器中,右鍵單擊按鈕控件,選擇“屬性”,然后在Style中選中owner drawn風格。但是有一種更好的方法,使得使用新建類子類化的按鈕自動的設置owner drawn風格。為了完成這個功能,我們重載最后一個函數:PreSubclassWindow

這個函數將在子類化窗口時被調用,次序是在CWnd::CreateDDX_Control之后,這就是說,無論是動態的創建窗口實例還是使用對話框模板創建,這個函數都將被調用。PreSubclassWindow在窗口子類化創建后和窗口被顯示前被調用,換句話說,這是我們來做窗口初始化的一個最好時機。

一個重點要注意的地方是: 如果你是用對話框資源創建一個控件,那么你要子類化的控件將不會響應WM_CREATE消息,所以我們不能在OnCreate函數中做初始化的工作,因為它并不是在所有的情況下都被調用。

使用ClassWizard重載PreSubclassWindow函數并加入下面的代碼

void CMyButton::PreSubclassWindow()
{
CButton::PreSubclassWindow();
ModifyStyle(0, BS_OWNERDRAW);// make the button owner drawn
}

祝賀 - 你的Cbutton派生類已經完成。

子類化

在創建時使用DDX子類化

在這個例子中,我們使用對話框編輯器在對話框中加入了一個新的按鈕:

 

然后,使用ClassWizard為你的按鈕控件添加成員變量,變量類型選擇我們剛剛建立的類CMyButton

ClassWizard g會在對話框的DoDataExchange函數中創建一個DDX_Control調用。DDX_Control啟動了子類化過程,使得按鈕控件使用CMyButton類進行消息映射,而不是使用通常的CButton

使用沒有在ClassWizard中注冊的類子類化窗口

如果你在工程中加入了一個新的窗口類,并且希望使用這個新類類型子類化你的窗口,但是ClassWizard中并沒有提供新類的選項,那么你需要重新生成class wizard文件。

先備份以下工程中的.clw文件,然后刪除它。接下來在Visual Studio中按Ctrl+W。你將看到一個提示框,要求你加入ClassWizard中包含類的文件,確認選擇的文件中包含了新類的文件(soarlove注:一般情況下,選擇“add all”即可。

現在你的新類已經可以供選擇。如果不想這樣做,你還有一個通用的方法,就是在選擇類型的時候使用通用的類(比如CButton),然后在頭文件中手工把通用類(CButton)改為你的新類(CMyButton)。

子類化一個存在的窗口

使用DDX固然簡單,但是不能幫助我們實現一個已存在窗口的子類化。比如你想在combobox中子類化一個Edit控件,那么在你子類化Edit控件之前,你需要先創建combobox控件。

這種情況下,我們使用SubclassDlgItem或者SubclassWindow函數。這兩個函數允許你動態的子類化一個窗口,換句話說,把一個新的窗口實例與已經存在的窗口建立關聯。

比如,假設有一個對話框中包含了一個按鈕IDIDC_BUTTON1。這個按鈕已經被創建,我們想用一個CMyButton的實例來與之關聯,以使得按鈕符合我們需要的行為。

為了做到這些,我們需要有一個新類型的實例,最后的方法是在對話框或視的頭文件中加入成員函數。

CMyButton m_btnMyButton;

然后在對話框的OnInitDialog (或任何適當的地方) 中調用:

m_btnMyButton.SubclassDlgItem(IDC_BUTTON1,this);

假設你已經有了一個窗口的指針,或者你工作在一個CView或其他CWnd派生類中里面的控件被動態的創建,或者你不想使用SubclassDlgItem函數,那么你可以使用下面的方法:

CWnd* pWnd = GetDlgItem(IDC_BUTTON1);// or use some other method to get// a pointer to the window you wish// to subclass
ASSERT( pWnd && pWnd->GetSafeHwnd() );
m_btnMyButton.SubclassWindow(pWnd->GetSafeHwnd());

 

畫按鈕是非常簡單的,不需要考慮按鈕的風格(比如flat風格),也不需要考慮適應文字,僅僅需要考慮你畫的范圍。如果你編譯運行提供的演示代碼,那么你將看到,當鼠標懸停于按鈕上方時,按鈕變為黃色。

 

注意,實際上我們只重載了畫的函數,并截取了鼠標移動的函數。其余的功能都還是使默認響應的。

結論

子類化并不難 - 你只要認真的選擇你要子類化的類并且知道你要映射那些消息。要熟悉你要子類化的類,了解提供的消息和類中的虛函數。


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲狼人综合| 久久国产精品亚洲va麻豆| 欧美成人福利视频| 久久久久网站| 亚洲二区在线观看| 欧美大香线蕉线伊人久久国产精品| 欧美一进一出视频| 一区在线视频观看| 欧美黄色成人网| 欧美福利视频在线观看| 亚洲美洲欧洲综合国产一区| 亚洲精品日韩在线观看| 欧美激情综合在线| 亚洲一区二区三区视频播放| 亚洲一区二区三区三| 国产亚洲激情视频在线| 免费h精品视频在线播放| 免费观看在线综合| 一区二区三区鲁丝不卡| 亚洲欧美视频一区| 在线观看欧美日韩国产| 亚洲国产日日夜夜| 欧美人与禽性xxxxx杂性| 亚洲专区在线视频| 久久精品人人| 一区二区三区欧美成人| 这里只有精品视频| 国内伊人久久久久久网站视频| 欧美91精品| 国产精品国产三级国产aⅴ入口 | 欧美成人一区二区三区| 亚洲作爱视频| 香蕉乱码成人久久天堂爱免费| 亚洲欧洲另类国产综合| 亚洲综合视频一区| 亚洲精品护士| 欧美一区二粉嫩精品国产一线天| 亚洲国产精品久久人人爱蜜臀| 夜夜嗨av一区二区三区免费区| 国产日韩视频| 一区二区不卡在线视频 午夜欧美不卡在 | 一区二区三区 在线观看视频| 国产亚洲精品aa| 亚洲激情视频| 国产综合av| 一本一道久久综合狠狠老精东影业 | 亚洲精品免费一区二区三区| 国产欧美一区二区色老头| 亚洲大胆人体在线| 国产亚洲综合在线| 一本到12不卡视频在线dvd| 国内精品久久久久久久97牛牛| 亚洲美女视频网| 亚洲成色777777在线观看影院| 亚洲午夜免费视频| 夜夜嗨一区二区三区| 久久天天狠狠| 久久午夜电影网| 国产精品五区| 一区二区久久久久| 日韩午夜中文字幕| 久久影音先锋| 久久婷婷丁香| 国产精品影视天天线| 亚洲午夜av| 亚洲天堂久久| 欧美日韩少妇| 日韩亚洲欧美一区二区三区| 亚洲精品一区二区三区av| 久久久中精品2020中文| 久久婷婷国产综合国色天香| 国产视频一区在线观看一区免费 | 久久久国产一区二区| 国产精品伦子伦免费视频| 日韩亚洲欧美一区| 亚洲私人影院在线观看| 欧美午夜精品久久久久久久| 亚洲日本中文字幕| 一区二区高清视频| 欧美视频国产精品| 狠狠干综合网| 久久不见久久见免费视频1| 欧美在线观看一区二区| 国产欧美精品xxxx另类| 午夜精品亚洲| 麻豆精品传媒视频| 亚洲片国产一区一级在线观看| 开元免费观看欧美电视剧网站| 欧美高清视频一二三区| 亚洲精品欧美激情| 欧美视频一区二区在线观看| 国产精品99久久99久久久二8 | 国产亚洲欧美aaaa| 久久久久国产精品一区三寸| 欧美国产日韩精品| 一区二区三区高清在线| 国产精品久久久久久av下载红粉| 亚洲自拍偷拍麻豆| 久久综合久久综合这里只有精品| 亚洲国产日韩一区二区| 欧美日韩一级黄| 欧美在线一区二区| 亚洲国产欧美久久| 午夜一区在线| 亚洲国内自拍| 欧美午夜视频在线| 久久九九国产精品| 夜夜嗨av一区二区三区网页| 性欧美大战久久久久久久免费观看| 国内精品久久久久久久果冻传媒| 欧美成熟视频| 午夜一区在线| 亚洲激情在线观看| 久久精品噜噜噜成人av农村| 亚洲三级免费电影| 国产乱码精品一区二区三区不卡 | 亚洲欧洲日本一区二区三区| 亚洲欧美资源在线| 亚洲第一黄网| 国产日韩欧美黄色| 欧美人妖在线观看| 久久午夜国产精品| 午夜精品国产更新| 亚洲日本成人女熟在线观看| 久久精品亚洲国产奇米99| 亚洲美女电影在线| 韩日午夜在线资源一区二区| 国产精品theporn| 免费在线欧美黄色| 久久久亚洲精品一区二区三区| 日韩亚洲视频| 亚洲国产精品电影| 蜜桃精品久久久久久久免费影院| 亚洲欧美日韩精品久久久| 亚洲精品乱码久久久久久黑人| 国产一区999| 国产精品一区=区| 国产精品草莓在线免费观看| 欧美高清视频一区二区| 久久婷婷人人澡人人喊人人爽 | 美女露胸一区二区三区| 午夜精品福利在线| 亚洲一区激情| 一区二区三区国产在线观看| 亚洲精品社区| 最新日韩精品| 亚洲麻豆视频| 亚洲美女黄色片| 亚洲精品久久久蜜桃| 亚洲国产欧美一区| 亚洲国产精品美女| 亚洲国语精品自产拍在线观看| 韩国精品在线观看| 狠狠色伊人亚洲综合网站色| 国产婷婷色一区二区三区四区| 国产精品嫩草99a| 国产精品入口夜色视频大尺度 | 久久精品亚洲一区| 久久成人18免费网站| 欧美影视一区| 久久久久久免费| 久久久水蜜桃av免费网站| 久色婷婷小香蕉久久| 欧美高清视频一区| 欧美视频在线观看 亚洲欧| 欧美日韩三级| 国产精品每日更新| 国产日韩欧美在线观看| 黑人一区二区| 亚洲九九精品| 亚洲综合欧美日韩| 久久精品最新地址| 亚洲第一搞黄网站| 99精品热视频| 久久se精品一区精品二区| 久久婷婷麻豆| 欧美日韩视频在线| 国产小视频国产精品| 亚洲日本欧美日韩高观看| 亚洲一区国产一区| 久久午夜av| 夜色激情一区二区| 久久福利视频导航| 欧美日本在线观看| 国产日韩精品久久| 亚洲久久视频| 久久精品99国产精品酒店日本| 嫩草成人www欧美| 日韩香蕉视频| 久久亚洲图片| 国产精品成人aaaaa网站| 国产一区二区三区不卡在线观看| 亚洲电影免费观看高清完整版在线 | 欧美男人的天堂| 国产视频一区欧美| 亚洲午夜黄色| 免费精品视频| 亚洲一区亚洲| 欧美日韩精品欧美日韩精品| 国产在线一区二区三区四区|