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

創造你自己的控件

介紹

作為一個程序員有許多普通的windows控件可以用在應用程序的外觀上。許多的控件的從列表到按鈕再到進程條都是可以現成的用。盡管如此,在如此多的控件中我們還是會碰到那些標準的控件不夠用的時候。歡迎進入子分類控件的藝術。

 

子分類一個windows控件不像子分類一個C++類。子分類一個控件意味這你用你自己的消息處理函數取代了改控件的一些或者所有的消息處理函數。你可以有效的截獲改控件的消息并使它按照你的意愿行事,而非windows的默認方式。這可以讓改控件實現大多數而非全部的你想得到的行為,并且使它表現得很完美。有兩種類型的子分類,局部子分類和全局子分類。局部子分類就是子分類一個實體,全局子分類就是將一個特定類型的控件全部子分成你的類型。

 

記住一個從CWnd類派生的類對象和一個與它相聯的窗口(hwnd)的區別是很重要的。CWnd的派生類對象包含一個成員變量指向hwnd,而且包含那些通過hwnd作為參數的處理消息的函數(比如,WM_PAINT, WM_MOUSEMOVE)。當你子分類一個控件通過你的C++對象時,你就是將相應的hwnd連接到你的C++對象上并把改控件將激發的消息回調函數改成你的。

 

子分類是很容易的。首先,你創建一個處理了你感興趣的所以消息的類,然后將該類來子分一個已經存在的控件使它按照你的新類的行事。某中方面上改控件已經變成了你所擁有的了。在這個例子中我們將子分一個按鈕控件并且使它做一些它從來都沒能夠做的事。

 

一個新類

 

 

子分一個控件我們需要創建一個新類改類應該處理了所有我們感興趣的消息。由于我們很懶,最好是使我們處理的消息最少,而且最好的方式是從你將要子分的控件派生你的新類,我們這里選擇的是CButton

 

我們設想的是使按鈕在鼠標每次經過時顯示出高亮的黃色。奇怪的事已經產生了。首先我們通過向導創建一個從CButton派生的新類CMyButton

 

 

 

 

 

通過MFC框架派生CButton類有許多優點,最大的就是我們不需要實際的為我們的類添加一行控件的代碼。假如我們愿意我們可以通過我們的新類在下一步子分一個按鈕控件,盡管有些煩瑣。這是因為MFC實現了所有缺省的消息處理函數,所以我們可以簡單的選擇一個我們感興趣的消息忽略其他的。

However for this example we have loftier plans for our control - making it bright yellow.

無論怎樣在這個例子中我們將使我們的控件表面高亮黃色顯示。

 

為了檢查鼠標是否是經過了控件我們將設置一個布爾變量m_bOverControlTRUE當鼠標進入控件邊界時,并且通過定時器實時的檢查跟蹤鼠標什么時候離開了控件。不幸的是我們沒有平臺提供的OnMouseEnter OnMouseLeave函數可用,我們將通過OnMouseMove。加入我么在某個時候發現鼠標不再在控件上,我們將關閉定時器并重畫該控件。

通過類向導添加WM_MOUSEMOVEWM_TIMER消息處理函數OnMouseMoveOnTimer

類向導將會添加如下代碼到你的新button類:

BEGIN_MESSAGE_MAP(CMyButton, CButton)

    //{{AFX_MSG_MAP(CMyButton)

    ON_WM_MOUSEMOVE()

    ON_WM_TIMER()

    //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

/////////////////////////////////////////////////////////////////////////////

// CMyButton message handlers

 

void 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);

}

消息映像的入口將消息映射成函數。ON_WM_MOUSEMOVE映射成函數OnMouseMoveON_WM_TIMER映射成OnTimer。這些宏在MFC源代碼中定義,但是它們不需要閱讀。這個練習僅僅知道它們這樣處理就可以了。

我們定義了兩個布爾變量m_bOverControlm_nTimer,一個UNIT變量,在構造函數里面初始化它們,我們的消息處理函數如下:

IDvoid CMyButton::OnMouseMove(UINT nFlags, CPoint point)

{

    if (!m_bOverControl)                    // Cursor has just moved over control

    {

        TRACE0("Entering control\n");

 

        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 control

    if (!rect.PtInRect(p))

    {

        TRACE0("Leaving control\n");

 

        // 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。這個方法僅僅是在自繪控件時調用,而且沒有一個缺省的實現可以讓你調用。(可以通過ASSERT'試試)這個方法被設計成僅被重載以及被派生類使用。

通過向導添加一個DrawItem方法并且添加如下代碼:

Collapse

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 necessary
    if (m_bOverControl)
        pDC->FillSolidRect(rect, RGB(255, 255, 0)); // yellow
 
    // Draw the text
    if (!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);
    }
}

所有的都已經做好了-進缺最后一步。DrawItem方法需要被繪制控件可以自繪。這可以通過在對話框編輯器里選中相應的選項實現-但是更好的方式是通過類自己設置樣式使得該類成為真正替代CButton的“drop-in”。為了實現這點我們需要重寫最后一個方法:PreSubclassWindow.

 

這個方法被SubclassWindow調用,并依次被CWnd::Create 或者DDX_Control調用,這意味著加入你動態或者通過對話框模板創建一個新類的對象,PreSubclassWindow仍然會被調用。PreSubclassWindow將在你子分的控件已經產生但是還為顯示之前調用。換句話說這就是控件的一個完美的初始化時刻。

需要重點注意的一點是:假如你的控件是通過對話框編輯器創建,那么你子分的控件將不會有WM_CREATE消息,因此我們不能通過使用OnCreate來初始化,因為它根本不會被調用。

通過向導重載PreSubclassWindow并添加如下代碼:

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

祝賀你-你現在已經有一個CButton的派生類了!

子類

通過DDX在創建的時候子分一個窗口

在這個例子中我們要子分的控件是在對話框上放置的:

我們讓正常的對話框創建流程創建一個帶有控件的對話框,然后通過DDX和我們的新類子分改控件。為了做到這點,我們僅僅需要通過向導添加一個控件變量使其成為對話框類的成員(在這里它的IDIDC_BUTTON1),類名為CMyButton

向導在你的對話框成員方法DoDataExchange中產生了一個DDX_Control調用。DDX_Control會調用SubclassWindow使得該按鈕使用CMyButton代替常規的CButton的處理方法。此按鈕已經被劫持而且會按照你的設想形式了。

 

子分類一個窗口但是不被向導識別

加入你添加一個窗口類到你的工程并且希望通過這個類的一個對象子分一個窗口,但是向導并不允許你的新類作為一個類型選項,這時你也許需要重新構建類向導文件了。

先備份工程中的.clw文件,然后刪除之,接著在Visual Studio上按CTRL+W。你將會看到一個提示你哪些文件將被包含到類掃描過程中。確信你的新類文件在其中。

現在你的新類將可以作為一個類選項了,如果不是,你仍然可以通過類向導產生一個控件(比如說CButton),然后在頭文件中手動修改其類名(比如CMyButton)。

子分一個存在的窗口

使用DDX很簡單,但是它不能幫助我們子分一個已經存在的控件。比如說,你想子分一個組合框中的編輯框控件。你需要在你子分編輯框控件之前已經創建了組合框(因此它的子編輯框窗口也就創建了)。

在這種情況下你可以使用非常好用的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或者兩端對齊的文本外其他任何你想要的樣式都可以。當你編譯運行改程序時你會看見一個簡單的按鈕當你的鼠標經過它時會呈現出亮黃色。

注意到我們僅僅真正的重載了自繪的方法,以及鼠標移動消息的處理函數,這意味這該控件仍然是下按式的按鈕。給對話框類添加一個單擊的處理函數你會發現它仍然可以被調用。

結尾

子分類并不難-你僅僅需要仔細選擇你需要子分的類,而且要意識到你需要處理的消息函數。仔細研究你需要子分的控件學習相關消息的處理函數和該類實現的虛成員方法。一旦你深入一個控件并且掌握了它的內部工作機制,你會發現一切都是那么容易!

posted on 2008-03-17 21:33 弱水一瓢 閱讀(313) 評論(0)  編輯 收藏 引用 所屬分類: MFC

<2009年3月>
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

導航

統計

文章分類

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲制服少妇| 一区二区三区 在线观看视| 久久成人精品一区二区三区| 国产精品性做久久久久久| 亚洲欧美日韩国产一区| 亚洲一区二区高清| 国产亚洲精品一区二区| 久久久www成人免费无遮挡大片| 亚洲欧美日韩国产一区二区| 国产日韩在线一区| 美女主播视频一区| 欧美成人精品在线播放| 一区二区三区精品国产| 亚洲一区二区三区久久| 国产日韩精品一区观看 | 国产精品av久久久久久麻豆网| 亚洲午夜一区| 欧美一区日韩一区| 亚洲黄色在线| 亚洲综合成人在线| 伊人精品久久久久7777| 99国产精品久久久久老师| 国产日韩一级二级三级| 亚洲国产精品日韩| 欧美午夜片在线观看| 久久免费视频在线观看| 欧美精品三级在线观看| 欧美一区二区三区在线看| 免费日韩av片| 欧美一区二区三区精品| 欧美成人精品影院| 久久久精品日韩| 欧美另类69精品久久久久9999| 欧美一区二区三区免费视| 免费在线日韩av| 久久久99久久精品女同性| 欧美国产日韩一二三区| 久久琪琪电影院| 欧美午夜在线一二页| 欧美激情黄色片| 国产日韩欧美在线观看| 亚洲美女黄网| 亚洲国产小视频| 先锋亚洲精品| 亚洲在线成人| 欧美人与性动交cc0o| 免费亚洲一区二区| 国产日韩欧美精品在线| 99精品视频网| 亚洲看片网站| 六月婷婷久久| 欧美成人免费全部观看天天性色| 国产精品久久亚洲7777| 亚洲免费成人| 99精品视频一区| 免费观看一级特黄欧美大片| 久久婷婷国产综合精品青草| 国产精品人人爽人人做我的可爱| 最近看过的日韩成人| **网站欧美大片在线观看| 性欧美精品高清| 久久精品亚洲一区二区三区浴池| 国产精品极品美女粉嫩高清在线| 日韩视频免费| 亚洲视频在线免费观看| 欧美性生交xxxxx久久久| 亚洲免费av电影| 亚洲私拍自拍| 国产精品v欧美精品∨日韩| 亚洲人成在线观看网站高清| 亚洲日本视频| 欧美国内亚洲| 一本久久青青| 西西裸体人体做爰大胆久久久| 国产精品久久久久毛片大屁完整版| 99re6热在线精品视频播放速度| 一本色道**综合亚洲精品蜜桃冫| 欧美精品自拍偷拍动漫精品| 亚洲精品欧美极品| 在线视频一区二区| 国产精品乱码人人做人人爱| 亚洲一区免费视频| 久久精品午夜| 在线欧美电影| 欧美日韩亚洲综合| 亚洲在线播放电影| 久久永久免费| 日韩性生活视频| 国产精品久久看| 久久久之久亚州精品露出| 亚洲电影毛片| 亚洲午夜精品国产| 国产在线视频欧美一区二区三区| 久久国产精品久久久久久| 欧美夫妇交换俱乐部在线观看| 亚洲伦理自拍| 国产精品久久久亚洲一区| 久久久久久久999精品视频| 亚洲三级影片| 久久久国产91| 一区二区日韩欧美| 国产亚洲欧美另类一区二区三区| 老司机一区二区三区| 日韩午夜中文字幕| 久久三级视频| 国产精品99久久久久久久女警 | 国产欧美精品在线播放| 久久午夜视频| 亚洲视频第一页| 欧美a级片网| 午夜视频在线观看一区| 亚洲国产日韩一区二区| 国产美女精品视频| 欧美黑人国产人伦爽爽爽| 性欧美18~19sex高清播放| 亚洲国产另类精品专区| 久久国产主播精品| 亚洲视频精选| 1000部国产精品成人观看| 国产精品视频久久一区| 美女诱惑黄网站一区| 午夜精品久久久久久99热软件| 亚洲国产精品成人| 久久亚洲电影| 久久爱www久久做| 亚洲最新视频在线| 91久久精品美女高潮| 国产一区自拍视频| 国产精品海角社区在线观看| 欧美国产乱视频| 蜜桃av噜噜一区| 久久久久国产精品厨房| 亚洲欧美日韩精品久久| 99精品欧美一区二区三区综合在线| 欧美成熟视频| 欧美成人在线网站| 免费不卡在线视频| 久久综合色综合88| 久久亚洲高清| 久久综合成人精品亚洲另类欧美| 欧美在线观看网站| 久久福利精品| 久久精品论坛| 六十路精品视频| 久久亚洲风情| 欧美成人亚洲成人| 欧美a一区二区| 欧美激情日韩| 亚洲黄色小视频| 日韩视频在线一区| 中文有码久久| 午夜精品区一区二区三| 午夜精品久久久久久久99樱桃| 亚洲手机视频| 亚洲欧美日韩中文播放| 欧美在线观看一区二区| 久久国产欧美日韩精品| 久久综合九色综合欧美狠狠| 美国成人毛片| 欧美日韩国产一中文字不卡| 欧美视频免费看| 国产免费亚洲高清| 国语自产精品视频在线看一大j8 | 欧美激情一区二区三区在线视频观看| 免费观看在线综合| 欧美激情中文字幕一区二区 | 欧美在线亚洲在线| 久久综合伊人| 亚洲激情第一页| 亚洲色诱最新| 羞羞漫画18久久大片| 久久久久一区| 欧美精品在线一区二区三区| 国产精品久久久久久户外露出| 国产日韩一区二区三区| 亚洲激情视频| 亚洲一区精彩视频| 久久久久国产精品午夜一区| 欧美国产在线观看| 亚洲一品av免费观看| 久久精品视频网| 欧美男人的天堂| 韩国av一区二区三区在线观看| 最新亚洲视频| 久久精品卡一| 日韩亚洲综合在线| 久久精品91| 欧美视频中文字幕在线| 激情另类综合| 亚洲欧美变态国产另类| 老**午夜毛片一区二区三区| 99国产精品久久久久久久| 久久国产精品亚洲77777| 欧美日韩免费一区二区三区视频| 国产日韩欧美日韩大片| 99re6这里只有精品视频在线观看| 久久激情视频免费观看| 99在线热播精品免费99热| 久久米奇亚洲| 国产模特精品视频久久久久|