按钮控件自绘

1.自绘按钮时,首先需要按钮具有自绘能力,即要为按钮设置BS_OWNERDRAW风格。再次需要重载按钮的PreSubclassWindow虚函数,在该函数中修改按钮风格。代码如下:

void CMyButton::PreSubclassWindow()

{

    ModifyStyle(0, BS_OWNERDRAW); /*使控件具有自绘的能力*/

    /*设置按钮的有效区域*/

    CRect rc;

    CRgn rgn;

    GetClientRect(&rc);

    /*有效区域为一个圆角矩形*/

    rgn.CreateRoundRectRgn(rc.left, rc.top, rc.right, rc.bottom,5, 5);

    SetWindowRgn(rgn, TRUE);

    rgn.DeleteObject();

    CButton::PreSubclassWindow();

}

 

2.当按钮具有自绘功能时,每次控件改变状态时都会触发DrawItem函数。因此在该函数里实现按钮绘制。

void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

{

    CRect rect = lpDrawItemStruct->rcItem;

    CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

    int nSaveDC = pDC->SaveDC();

    UINT state = lpDrawItemStruct->itemState;

    POINT pt;

    TCHAR strText[MAX_PATH + 2];

    GetWindowTextW(strText, MAX_PATH);

    /*绘制按钮外边框*/

    pt.x = 5;

    pt.y = 5;

    CPen *hOldPen = pDC->SelectObject(&m_OutsideBorder);

    pDC->RoundRect(&rect, pt);

    pDC->SelectObject(hOldPen);



    //获取按钮的状态

    if(state & ODS_FOCUS)

    {

        m_bFocus = TRUE;

        m_bSelected = TRUE;

    }

    else

    {

        m_bFocus = FALSE;

        m_bSelected = FALSE;

    }

    if(state & ODS_SELECTED || state & ODS_DEFAULT)

    {

        m_bFocus = TRUE;

    }

    

    /*根据按钮的状态填充按钮的底色*/

    CBrush *pOldBrush;

    if(m_bOver)

    {

        pOldBrush = pDC->SelectObject(&m_FillActive);

        DoGradientFill(pDC, &rect);

    }

    else

    {

        pOldBrush = pDC->SelectObject(&m_FillInactive);

        DoGradientFill(pDC, &rect);

    }

    pDC->SelectObject(pOldBrush);

    /*根据按钮状态绘制内边框*/

    if(m_bOver || m_bSelected)

    {

        DrawInsideBorder(pDC, &rect);

    }

    /*绘制按钮的文本*/

    if(strText != NULL)

    {

        CFont *hFont = GetFont();

        CFont *hOldFont = pDC->SelectObject(hFont);

        CSize szExtent = pDC->GetTextExtent(strText, lstrlen(strText));

        CPoint pt(rect.CenterPoint().x - szExtent.cx / 2, rect.CenterPoint().y - szExtent.cy / 2);

        int nMode = pDC->SetBkMode(TRANSPARENT);

        if(state & ODS_SELECTED)

            pt.Offset(1, 1);

        if(state & ODS_SELECTED)

            pDC->DrawState(pt, szExtent, strText, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);

        else

            pDC->DrawState(pt, szExtent, strText, DSS_NORMAL, TRUE, 0, (HBRUSH)NULL);

        pDC->SelectObject(hOldFont);

        pDC->SetBkMode(nMode);

    }

    pDC->RestoreDC(nSaveDC);

}

3.一般都会为按钮定义几种不同状态时的外观,比如光标滑过时的状态,按钮按下时的状态,按钮禁用时的状态,以及按钮的正常状 态等等。这就要为新的按钮添加几种重要的消息响应。比如WM_MOUSELEAVE消息,WM_MOUSEHOVER消息和WM_MOUSEMOVE消息 等等,值得一提的是前两个消息的响应函数需要自己手动添加,微软提供了一个TrackMouseEvent函数在光标离开一个窗口时投递 WM_MOUSELEAVE消息,光标滑过窗口时投递WM_MOUSEHOVER消息。一般来说可以在WM_MOUSEMOVE消息响应函数中调用 TrackMouseEvent函数来投递WM_MOUSELEAVE消息和WM_MOUSEHOVER消息。然后在WM_MOUSELEAVE消息的响 应函数中标记“光标已经离开按钮”,然后调用InvalidateRect函数让按钮重绘。在WM_MOUSEHOVER消息的响应函数中标记“光标正在 按钮上方”,并调用InvalidateRect函数让按钮重绘。

按钮几种状态:

Normal状态,就是按钮一开始显示时的样子。

Over状态,鼠标指针移动到按钮上面时按钮显示的样子。

Down状态,按下按钮时显示的样子。

Focus状态,按钮按下后松开的样子,例如标准按钮按下松开之后会看到按钮内部有一个虚线框。

Disable状态,当然就是按钮被设置成无效的时候的样子啦。

定义按钮状态变量:

    /*按钮的状态*/

    BOOL m_bOver; //鼠标位于按钮之上时该值为true,反之为false

    BOOL m_bTracking; //鼠标按下没有释放是该值为true

    BOOL m_bSelected; //按钮被按下是该值为true

    BOOL m_bFocus; //按钮为当前焦点时该值为true

响应按钮消息:

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

{

    if(!m_bTracking)

    {

        TRACKMOUSEEVENT tme;

        tme.cbSize = sizeof(tme);

        tme.hwndTrack = m_hWnd;

        tme.dwFlags = TME_LEAVE | TME_HOVER;

        tme.dwHoverTime = 1;

        m_bTracking = _TrackMouseEvent(&tme);

    }

    CButton::OnMouseMove(nFlags, point);

}



void CMyButton::OnMouseHover(UINT nFlags, CPoint point)

{

    m_bOver = TRUE;

    InvalidateRect(NULL);

    CButton::OnMouseHover(nFlags, point);

}



void CMyButton::OnMouseLeave()

{

    m_bOver = FALSE;

    m_bTracking = FALSE;

    InvalidateRect(NULL, FALSE);

    CButton::OnMouseLeave();

}

 

4.为父窗口响应按钮通告消息在父窗口的消息映射里添加消息映射宏:

ON_BN_CLICKED(IDC_BUTTON1, OnBtnClick)

ON_BN_DOUBLECLICKED(IDC_BUTTON1, OnBtnDClick)

声明和定义消息映射函数

public:

    // 响应按钮单击事件

    afx_msg void OnBtnClick(void);

    // 响应按钮双击事件

    afx_msg void OnBtnDClick(void);
// 响应按钮单击事件

void CButtonOwnerDraw_0200Dlg::OnBtnClick(void)

{

    MessageBox(_T("按钮被单击!"));

}



// 响应按钮双击事件

void CButtonOwnerDraw_0200Dlg::OnBtnDClick(void)

{

    MessageBox(_T("按钮被双击!"));

}

 

 

参考:

http://c.chinaitlab.com/vc/828932.html

http://www.vckbase.com/index.php/wv/374.html

http://www.360doc.com/content/10/1128/14/2226925_73128026.shtml

代码:

http://pan.baidu.com/share/link?shareid=452609&uk=2600520119

 

你可能感兴趣的:(控件)