效果演示
上位机MFC三角形按钮实例
例程通过自己编写代码实现按钮自绘,完成三角形按钮功能。
效果如上图,涉及的代码可以在下面复制使用。
或直接下载项目工程,内含编译好的可执行程序,可直接运行查看效果
实现过程
1.新建基于对话框应用程序, 如上图添加控件,并排版。
2.将工程根目录按钮文件TRIANGLEBUTTON.CPP,TRIANGLEBUTTON.h复制到工程根目录。
并导入到自己工程中,这样工程内就新添加一按钮类CTriangleButton
上位机MFC三角形按钮实例
3.在主对话框包含CTriangleButton的头文件,并关联按钮控件,注意控件ID与变量的对应。
然后编译工程,按钮就可以变成三角形状了。
#include "TriangleButton.h"
CTriangleButton trif7;
CTriangleButton trif6;
CTriangleButton tri3d7;
CTriangleButton tri3d6;
CTriangleButton trif5;
CTriangleButton trif4;
CTriangleButton trif3;
CTriangleButton trif2;
CTriangleButton trif1;
CTriangleButton tri3d5;
CTriangleButton tri3d4;
CTriangleButton tri3d3;
CTriangleButton tri3d2;
CTriangleButton tri3d1;
DDX_Control(pDX, IDTRI_F_7, trif7);
DDX_Control(pDX, IDTRI_F_6, trif6);
DDX_Control(pDX, IDTRI_3D_7, tri3d7);
DDX_Control(pDX, IDTRI_3D_6, tri3d6);
DDX_Control(pDX, IDTRI_F_5, trif5);
DDX_Control(pDX, IDTRI_F_4, trif4);
DDX_Control(pDX, IDTRI_F_3, trif3);
DDX_Control(pDX, IDTRI_F_2, trif2);
DDX_Control(pDX, IDTRI_F_1, trif1);
DDX_Control(pDX, IDTRI_3D_5, tri3d5);
DDX_Control(pDX, IDTRI_3D_4, tri3d4);
DDX_Control(pDX, IDTRI_3D_3, tri3d3);
DDX_Control(pDX, IDTRI_3D_2, tri3d2);
DDX_Control(pDX, IDTRI_3D_1, tri3d1);
4.然后是实现对按钮文本,三角形方向的控制
依次双击单选框,添加其点击函数
void CCBtnDlg::OnRaDown()
{
ChangeTriButtonDirection(CTriangleButton:OINT_DOWN);
}
void CCBtnDlg::OnRaRight()
{
ChangeTriButtonDirection(CTriangleButton:OINT_RIGHT);
}
void CCBtnDlg::OnRaUp()
{
ChangeTriButtonDirection(CTriangleButton:OINT_UP);
}
void CCBtnDlg::OnRaLeft()
{
ChangeTriButtonDirection(CTriangleButton:OINT_LEFT);
}
其中void ChangeTriButtonDirection(CTriangleButton:OINTDIRECTION d);为自己在主对话框添加的函数
void CCBtnDlg::ChangeTriButtonDirection(CTriangleButton:OINTDIRECTION d)
{
trif1.SetDirection(d);
trif2.SetDirection(d);
trif3.SetDirection(d);
trif4.SetDirection(d);
trif5.SetDirection(d);
trif6.SetDirection(d);
trif7.SetDirection(d);
tri3d1.SetDirection(d);
tri3d2.SetDirection(d);
tri3d3.SetDirection(d);
tri3d4.SetDirection(d);
tri3d5.SetDirection(d);
tri3d6.SetDirection(d);
tri3d7.SetDirection(d);
Invalidate();
}
这样就可以通过单选框,设置三角按钮的方向。
5.其他的功能就可以使用MFC按钮类自带的,如按钮 文本的修改
可以在界面编辑中完成,双击添加编辑框文本变化触发函数便可
CString text;
GetDlgItemText(IDC_BUTTONTEXT,text);
trif1.SetWindowText(text);
trif2.SetWindowText(text);
trif3.SetWindowText(text);
trif4.SetWindowText(text);
trif5.SetWindowText(text);
trif6.SetWindowText(text);
trif7.SetWindowText(text);
tri3d1.SetWindowText(text);
tri3d2.SetWindowText(text);
tri3d3.SetWindowText(text);
tri3d4.SetWindowText(text);
tri3d5.SetWindowText(text);
tri3d6.SetWindowText(text);
tri3d7.SetWindowText(text);
下面是两文件内代码,可复制使用:
- #ifndef __TRIANGLEBUTTON_H__INCLUDED
- #define __TRIANGLEBUTTON_H__INCLUDED
- class CTriangleButton : public CButton
- {
- public:
- enum POINTDIRECTION {POINT_UP, POINT_DOWN, POINT_LEFT, POINT_RIGHT};
-
- // Construction
- public:
- CTriangleButton();
- virtual ~CTriangleButton();
- // Attributes
- public:
- protected:
- POINTDIRECTION PointDirection;
- CRgn CurrentRegion;
- // Operations
- public:
- // Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(CTriangleButton)
- public:
- virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
- protected:
- virtual void PreSubclassWindow();
- //}}AFX_VIRTUAL
- public:
- //note: SetWindowPos decreases the cx, cy parameter to nearest number dividable by two
- BOOL SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags );
- // Implementation
- public:
- void SetDirection(POINTDIRECTION PointDirection); //sets the direction of triangle
- POINTDIRECTION GetDirection(); //gets the direction of triangle
- // Generated message map functions
- protected:
- //{{AFX_MSG(CTriangleButton)
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
- };
- #endif // __TRIANGLEBUTTON_H__INCLUDED
复制代码
- #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::CTriangleButton()
- {
- PointDirection = POINT_RIGHT;
- }
- CTriangleButton::~CTriangleButton()
- {
- }
- BEGIN_MESSAGE_MAP(CTriangleButton, CButton)
- //{{AFX_MSG_MAP(CRoundButton)
- ON_WM_NCHITTEST()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
- void CTriangleButton::SetDirection(POINTDIRECTION Direction)
- {
- PointDirection = Direction;
- PreSubclassWindow();
- }
- CTriangleButton::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;
- //TRACE("x=%i y=%i\n", cx, cy);
- return CButton::SetWindowPos(pWndInsertAfter, x, y, cx, cy, nFlags);
- }
- /////////////////////////////////////////////////////////////////////////////
- // CRoundButton message handlers
- void CTriangleButton::PreSubclassWindow()
- {
- CButton::PreSubclassWindow();
- //get client rectangle
- 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
- //make some pens
- 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));
- //NOTE: If U use this class for NT apps only, use the implementation of FocusPen below
- // instead, as WIN95 doesn't support this yet (though the doc says **dang ms-fools**)
- // (WIN98 might also support this)
- //LOGBRUSH logbrush; logbrush.lbStyle = BS_SOLID; logbrush.lbColor = RGB(0,0,0); logbrush.lbHatch = NULL;
- //CPen FocusPen(PS_COSMETIC | PS_ALTERNATE, 1, &logbrush);
- CPen FocusPen(PS_DOT, 0, RGB(0,0,0));
-
- //Draw button
- switch (PointDirection) {
- case POINT_UP : {
- //Draw the raised/sunken edges of the button (unless flat)
- if (nStyle & BS_FLAT) { //style is 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 { //style not flat
- if ((state & ODS_SELECTED)) { //Button is down
- 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 { //Button is not down
- 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);
- }//else|if
- }//else|if
- break;
- }//case
-
- case POINT_DOWN : {
- //Draw the raised/sunken edges of the button (unless flat)
- if (nStyle & BS_FLAT) { //style is 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 { //style not flat
- if ((state & ODS_SELECTED)) { //Button is down
- 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 { //Button is not down
- 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);
-
- }
- }//else|if
- break;
- }//case
- case POINT_LEFT : {
- if (nStyle & BS_FLAT) { //style is 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 { //style not flat
- if ((state & ODS_SELECTED)) { //Button is down
- 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 { //Button is not down
- 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);
- }
- }//else|if
- break;
- }//case
- case POINT_RIGHT : {
- if (nStyle & BS_FLAT) { //style is 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 { //style not flat
- if ((state & ODS_SELECTED)) { //Button is down
- 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 { //Button is not down
- 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);
- }
- }//else|if
- break;
- }//case
- default :
- ASSERT(FALSE);
- }//switch
- //Draw text if any
- 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
- 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
- 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;
- }//case
- 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);
- }
- }//if
- //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
- 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;
- }//case
- default :
- ASSERT(FALSE);
- }//switch
- }//if
- pDC->RestoreDC(nSavedDC);
- }
- /* I'm not sure what this function is supposed to do, but it was in the
- CRoundButton class i used to make this class, so I have implemented it, though
- I don't know what the function should do ! (if it is nescessary just remove comments)
- UINT CTriangleButton::OnNcHitTest(CPoint point)
- {
- ScreenToClient(&point);
- if (CurrentRegion.PtInRegion(point)) {
- //TRACE("HTCLIENT: %i, %i\n", point.x, point.y);
- return HTCLIENT;
- }
- else {
- //TRACE("HTNOWHERE: %i, %i\n", point.x, point.y);
- return HTNOWHERE;
- }
- }
- */
复制代码 如果您认可,可联系功能定制! 如果您着急,充值会员可直接联系发您资料!
|