MFC:三角形按钮(重绘CButton)

本文介绍了一个自定义的三角形按钮类CTriangleButton,该类继承自标准按钮类CButton,并实现了不同方向的三角形样式绘制。文章详细展示了如何设置三角形的方向、调整窗口大小以适应三角形形状,并在不同状态下绘制按钮。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

头文件 TriangleButton.h:

#ifndef __TRIANGLEBUTTON_H__INCLUDED
#define __TRIANGLEBUTTON_H__INCLUDED

enum POINTDIRECTION { POINT_UP, POINT_DOWN, POINT_LEFT, POINT_RIGHT };

class CTriangleButton : public CButton
{
public:
    CTriangleButton();
    virtual ~CTriangleButton();

protected:
    POINTDIRECTION PointDirection;
    CRgn CurrentRegion;

public:
    public:
    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    protected:
    virtual void PreSubclassWindow();

    BOOL SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags );

public:
    void SetDirection(POINTDIRECTION PointDirection);    //sets the direction of triangle
    POINTDIRECTION GetDirection();                        //gets the direction of triangle

protected:
    DECLARE_MESSAGE_MAP()
};

#endif

源文件 TriangleButton.cpp:

#include "stdafx.h"
#include "math.h"
#include "TriangleButton.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CTriangleButton::CTriangleButton()
{
    PointDirection = POINT_RIGHT;
}

CTriangleButton::~CTriangleButton()
{
}

BEGIN_MESSAGE_MAP(CTriangleButton, CButton)
    ON_WM_NCHITTEST()
END_MESSAGE_MAP()

void CTriangleButton::SetDirection(POINTDIRECTION Direction)
{
    PointDirection = Direction;
    PreSubclassWindow();
}

POINTDIRECTION CTriangleButton::GetDirection()
{
    return PointDirection;
}

BOOL CTriangleButton::SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags)
{
    //Size must be dividable by two (else triangle will look strange when drawn)
    cx -= cx % 2;
    cy -= cy % 2;
    return CButton::SetWindowPos(pWndInsertAfter, x, y, cx, cy, nFlags);
}

// CRoundButton message handlers
void CTriangleButton::PreSubclassWindow()
{
    CButton::PreSubclassWindow();

    CRect rect;
    GetClientRect(rect);
    rect.bottom = rect.right = min(rect.bottom, rect.right);    //make it square
    rect.bottom -= rect.bottom % 2;
    rect.right  -= rect.right % 2;

    SetWindowPos(NULL, 0, 0, rect.right, rect.bottom, SWP_NOMOVE | SWP_NOZORDER);

    CPoint Head, RightLeg, LeftLeg;

    switch (PointDirection)
    {
        case POINT_UP :
            {
                Head.x = rect.right / 2;
                Head.y = 0;
                RightLeg.x = rect.right;
                RightLeg.y = rect.bottom;
                LeftLeg.x = 0;
                LeftLeg.y = rect.bottom;
            }
            break;
        case POINT_DOWN :
            {
                Head.x = rect.right / 2;
                Head.y = rect.bottom;
                RightLeg.x = 0;
                RightLeg.y = 0;
                LeftLeg.x = rect.right;
                LeftLeg.y = 0;
            }
            break;
        case POINT_LEFT :
            {
                Head.x = 0;
                Head.y = rect.bottom / 2;
                RightLeg.x = rect.right;
                RightLeg.y = 0;
                LeftLeg.x = rect.right;
                LeftLeg.y = rect.bottom;
            }
            break;
        case POINT_RIGHT :
            {
                Head.x = rect.right;
                Head.y = rect.bottom / 2;
                RightLeg.x = 0;
                RightLeg.y = rect.bottom;
                LeftLeg.x = 0;
                LeftLeg.y = 0;
            }
            break;
        default :
            ASSERT(FALSE);
    }//switch
                            
    CPoint points[3];
    points[0] = Head;
    points[1] = RightLeg;
    points[2] = LeftLeg;
    
    SetWindowRgn(NULL, FALSE);

    CurrentRegion.DeleteObject();
    CurrentRegion.CreatePolygonRgn(points, 3, ALTERNATE);

    SetWindowRgn(CurrentRegion, TRUE);
        
    ModifyStyle(0, BS_OWNERDRAW);
}

void CTriangleButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    ASSERT(lpDrawItemStruct != NULL);
    CRect rect = lpDrawItemStruct->rcItem;
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    UINT state = lpDrawItemStruct->itemState;
    UINT nStyle = GetStyle();

    int nSavedDC = pDC->SaveDC();

    //make the rect a square
    rect.bottom = rect.right = min(rect.bottom, rect.right);
    pDC->FillSolidRect(rect, ::GetSysColor(COLOR_BTNFACE));
    
    rect.right -= 1; rect.bottom -= 1;    //avoid drawing outside area

    CPen HighlightPen(PS_SOLID, 1, ::GetSysColor(COLOR_3DHIGHLIGHT));
    CPen DarkShadowPen(PS_SOLID, 1, ::GetSysColor(COLOR_3DDKSHADOW));
    CPen ShadowPen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
    CPen BlackPen(PS_SOLID, 1, RGB(0,0,0));
    CPen FocusPen(PS_DOT, 0, RGB(0,0,0));

    //Draw button
    switch (PointDirection)
    {
        case POINT_UP :
        {
            if (nStyle & BS_FLAT)
            {
                pDC->SelectObject(BlackPen);
                pDC->MoveTo(rect.right / 2, 0);
                pDC->LineTo(0, rect.bottom);
                pDC->LineTo(rect.right, rect.bottom);
                pDC->LineTo(rect.right / 2, 0);
                pDC->SelectObject(HighlightPen);
                pDC->MoveTo(rect.right / 2, 2);
                pDC->LineTo(2, rect.bottom - 1);
                pDC->LineTo(rect.right - 2, rect.bottom - 1);
                pDC->LineTo(rect.right / 2, 2);
            }
            else
            {
                if ((state & ODS_SELECTED))    
                {
                    pDC->SelectObject(HighlightPen);
                    pDC->MoveTo(0, rect.bottom);
                    pDC->LineTo(rect.right - 1, rect.bottom);
                    pDC->LineTo(rect.right / 2, 0);

                    pDC->SelectObject(ShadowPen);
                    pDC->LineTo(0, rect.bottom);            
                    
                    pDC->SelectObject(DarkShadowPen);
                    pDC->MoveTo(rect.right / 2 - 1, 4);
                    pDC->LineTo(1, rect.bottom);
                }
                else
                {
                    pDC->SelectObject(HighlightPen);
                    pDC->MoveTo(rect.right /2, 0);
                    pDC->LineTo(0, rect.bottom - 1);
                    
                    pDC->SelectObject(ShadowPen);
                    pDC->LineTo(rect.right - 1, rect.bottom - 1);
                    pDC->LineTo(rect.right / 2, 0);

                    pDC->SelectObject(DarkShadowPen);
                    pDC->MoveTo(rect.right / 2 + 2, 3);
                    pDC->LineTo(rect.right + 1, rect.bottom + 1);
                    
                    pDC->MoveTo(rect.right - 1, rect.bottom);
                    pDC->LineTo(1, rect.bottom);
                }
            }
        }
        break;
        case POINT_DOWN :
        {
            if (nStyle & BS_FLAT)
            {
                pDC->SelectObject(BlackPen);
                pDC->MoveTo(rect.right / 2, rect.bottom);
                pDC->LineTo(0, 0);
                pDC->LineTo(rect.right, 0);
                pDC->LineTo(rect.right / 2, rect.bottom);
                
                pDC->SelectObject(HighlightPen);
                pDC->MoveTo(rect.right / 2, rect.bottom - 2);
                pDC->LineTo(2, 1);
                pDC->LineTo(rect.right - 2, 1);
                pDC->LineTo(rect.right / 2, rect.bottom - 2);
            }
            else
            {
                if ((state & ODS_SELECTED))
                {
                    pDC->SelectObject(ShadowPen);
                    pDC->MoveTo(rect.right, 1);
                    pDC->LineTo(1, 1);
                    pDC->LineTo(rect.right / 2, rect.bottom - 1);
                    
                    pDC->SelectObject(BlackPen);
                    pDC->MoveTo(rect.right - 2, 2);
                    pDC->LineTo(1, 2);
                    
                    pDC->SelectObject(HighlightPen);
                    pDC->MoveTo(rect.right + 1, 0);
                    pDC->LineTo(rect.right / 2 + 1, rect.bottom + 1);

                }
                else
                {
                    pDC->SelectObject(ShadowPen);
                    pDC->MoveTo(0, 0);
                    pDC->LineTo(rect.right / 2, rect.bottom);
                    pDC->LineTo(rect.right, 0);
                    pDC->MoveTo(1, 1);
                    pDC->LineTo(rect.right / 2 + 1, rect.bottom);
                    
                    pDC->SelectObject(DarkShadowPen);
                    pDC->MoveTo(rect.right, 2);
                    pDC->LineTo(rect.right / 2 + 1, rect.bottom + 1);
                    
                    pDC->SelectObject(HighlightPen);
                    pDC->MoveTo(0, 0);
                    pDC->LineTo(rect.right, 0);
                
                }
            }
        }
        break;
        case POINT_LEFT :
        {
            if (nStyle & BS_FLAT)
            {
                pDC->SelectObject(BlackPen);
                pDC->MoveTo(rect.right, 0);
                pDC->LineTo(0, rect.bottom / 2);
                pDC->LineTo(rect.right, rect.bottom);
                pDC->LineTo(rect.right, 0);
                
                pDC->SelectObject(HighlightPen);
                pDC->MoveTo(rect.right - 1, 2);
                pDC->LineTo(3, rect.bottom / 2);
                pDC->LineTo(rect.right - 1, rect.bottom - 2);
                pDC->LineTo(rect.right - 1, 2);
            }
            else
            {
                if ((state & ODS_SELECTED))
                {
                    pDC->SelectObject(ShadowPen);
                    pDC->MoveTo(rect.right, 0);
                    pDC->LineTo(0, rect.bottom / 2);

                    pDC->SelectObject(DarkShadowPen);
                    pDC->MoveTo(rect.right, 1);
                    pDC->LineTo(2, rect.bottom / 2);
                    
                    pDC->SelectObject(HighlightPen);
                    pDC->MoveTo(rect.right, 0);
                    pDC->LineTo(rect.right, rect.bottom);
                    pDC->LineTo(0, rect.bottom / 2);
                }
                else
                {
                    pDC->SelectObject(ShadowPen);
                    pDC->MoveTo(rect.right - 1, 0);
                    pDC->LineTo(rect.right - 1, rect.bottom - 1);
                    pDC->LineTo(0, rect.bottom / 2);
                    pDC->MoveTo(1, rect.bottom / 2 + 1);
                    pDC->LineTo(6, rect.bottom / 2 + 4);

                    pDC->SelectObject(DarkShadowPen);
                    pDC->MoveTo(rect.right, 1);
                    pDC->LineTo(rect.right, rect.bottom);
                    pDC->LineTo(2, rect.bottom / 2 + 2);
                    
                    pDC->SelectObject(HighlightPen);
                    pDC->MoveTo(0, rect.bottom / 2);
                    pDC->LineTo(rect.right, 0);
                }
            }
        }
        break;
        case POINT_RIGHT :
        {
            if (nStyle & BS_FLAT)
            {
                pDC->SelectObject(BlackPen);
                pDC->MoveTo(0, 0);
                pDC->LineTo(rect.right, rect.bottom / 2);
                pDC->LineTo(0, rect.bottom);
                pDC->LineTo(0, 0);
                
                pDC->SelectObject(HighlightPen);
                pDC->MoveTo(1, 2);
                pDC->LineTo(rect.right - 2, rect.bottom / 2);
                pDC->LineTo(1, rect.bottom - 2);
                pDC->LineTo(1, 2);
            }
            else
            {
                if ((state & ODS_SELECTED))
                {
                    pDC->SelectObject(ShadowPen);
                    pDC->MoveTo(0, rect.bottom);
                    pDC->LineTo(0, 0);
                    pDC->LineTo(rect.right, rect.bottom / 2);

                    pDC->SelectObject(DarkShadowPen);
                    pDC->MoveTo(1, rect.bottom - 2);
                    pDC->LineTo(1, 1);
                    pDC->MoveTo(rect.right - 3, rect.bottom / 2);
                    pDC->LineTo(0, 1);
                    
                    pDC->SelectObject(HighlightPen);
                    pDC->MoveTo(0, rect.bottom);
                    pDC->LineTo(rect.right, rect.bottom / 2);
                    
                }
                else
                {
                    pDC->SelectObject(ShadowPen);
                    pDC->MoveTo(0, rect.bottom);
                    pDC->LineTo(rect.right, rect.bottom / 2);

                    pDC->SelectObject(DarkShadowPen);
                    pDC->MoveTo(0, rect.bottom + 1);
                    pDC->LineTo(rect.right, rect.bottom / 2 + 1);
                    
                    pDC->SelectObject(HighlightPen);
                    pDC->MoveTo(0, rect.bottom);
                    pDC->LineTo(0, 0);
                    pDC->LineTo(rect.right, rect.bottom / 2);
                }
            }
        }
        break;
        default :
            ASSERT(FALSE);
    }//switch

    //Draw text
    CString strText;
    GetWindowText(strText);
    if (!strText.IsEmpty())
    {
        CSize TextExtent = pDC->GetTextExtent(strText);
        CPoint TextPos;
        pDC->SetBkMode(TRANSPARENT);

        switch (PointDirection)
        {
            case POINT_UP :
            {
                TextPos = CPoint((int)(rect.right / 2.0 - TextExtent.cx / 2.0), rect.bottom - (int)(rect.bottom / 5.0 + TextExtent.cy));
                int iXLimit = (int)((rect.bottom / 5.0 + TextExtent.cy) * 4.0 / 7.0);

                CRgn rgn;
                rgn.CreateRectRgn(iXLimit, TextPos.y, rect.right - iXLimit, rect.bottom - 2);
                pDC->SelectClipRgn(&rgn);            
            }
            break;
            case POINT_DOWN :
            {
                TextPos = CPoint((int)(rect.right / 2.0 - TextExtent.cx / 2.0), (int)(rect.bottom / 5.0));
                int iXLimit = (int)((rect.bottom / 5.0 + TextExtent.cy) * 4.0 / 7.0);

                CRgn rgn; rgn.CreateRectRgn(iXLimit, (int)(rect.bottom / 5.0), rect.right - iXLimit, (int)(rect.bottom / 5.0) + TextExtent.cy + 2);
                pDC->SelectClipRgn(&rgn);
            }
            break;
            case POINT_LEFT :
            {
                TextPos = CPoint((int)((rect.right / 2.0 - TextExtent.cx / 2.0) + (rect.right / 8.0)), (int)(rect.bottom / 2.0 - TextExtent.cy / 2.0) );
                int iXLimitLeft = (int)(TextExtent.cy / 2.0 * 7.0 / 4.0) + 4;
                int iXLimitRight = rect.right - 4;
            
                CRgn rgn; rgn.CreateRectRgn(iXLimitLeft, (int)(rect.bottom / 2.0 - TextExtent.cy / 2.0), iXLimitRight, (int)(rect.bottom / 2.0 + TextExtent.cy / 2.0) );
                pDC->SelectClipRgn(&rgn);
            }
            break;
            case POINT_RIGHT :
            {
                TextPos = CPoint((int)((rect.right / 2.0 - TextExtent.cx / 2.0) - (rect.right / 8.0)), (int)(rect.bottom / 2.0 - TextExtent.cy / 2.0) );
                int iXLimitLeft = 4;
                int iXLimitRight = rect.right - (int)(TextExtent.cy / 2.0 * 7.0 / 4.0) - 4;
                    
                CRgn rgn; rgn.CreateRectRgn(iXLimitLeft, (int)(rect.bottom / 2.0 - TextExtent.cy / 2.0), iXLimitRight, (int)(rect.bottom / 2.0 + TextExtent.cy / 2.0) );
                pDC->SelectClipRgn(&rgn);
            }
            break;
            default :
                ASSERT(FALSE);
        }//switch

        //common for all directions
        if (state & ODS_SELECTED)
        {
            TextPos.Offset(1,1);
        }

        if (state & ODS_DISABLED)
        {
            pDC->DrawState(TextPos, TextExtent, strText, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);
        }
        else
        {
            pDC->TextOut(TextPos.x, TextPos.y, strText);
        }

    }

    //Draw the focus triangle on the inside of the button if we have focus
    if ((state & ODS_FOCUS))
    {
        CRgn rgn;
        rgn.CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
        pDC->SelectClipRgn(&rgn);
        pDC->SelectObject(FocusPen);
        switch (PointDirection)
        {
            case POINT_UP:
            {
                pDC->MoveTo(rect.right / 2, 12);
                pDC->LineTo(9, rect.bottom - 6);
                pDC->LineTo(rect.right - 9, rect.bottom - 6);
                pDC->LineTo(rect.right / 2, 12);
            }
            break;
            case POINT_DOWN:
            {
                pDC->MoveTo(rect.right / 2 + 1, rect.bottom - 13);
                pDC->LineTo(10, 6);
                pDC->LineTo(rect.right - 9, 6);
                pDC->LineTo(rect.right / 2 + 1, rect.bottom - 13);
            }
            break;
            case POINT_LEFT:
            {
                pDC->MoveTo(12, rect.bottom / 2);
                pDC->LineTo(rect.right - 6, 9);
                pDC->LineTo(rect.right - 6, rect.bottom - 9);
                pDC->LineTo(12, rect.bottom / 2);
            }
            break;
            case POINT_RIGHT:
            {
                pDC->MoveTo(6, 9);
                pDC->LineTo(rect.right - 12, rect.bottom / 2);
                pDC->LineTo(6, rect.bottom - 9);
                pDC->LineTo(6, 9);
            }
            break;
            default:
                ASSERT(FALSE);
        }//switch
    }

    pDC->RestoreDC(nSavedDC);
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值