设为首页 加入收藏

TOP

VC按钮自绘的简单实现(一)
2015-11-21 03:28:02 】 浏览:2685
Tags:按钮 简单 实现

之前一直使用公司开发的界面库来进行VC界面设计,今天偶然发现其中一个按钮类不能实现特定需求,例如文字的位置不能随意显示在按钮上。于是唯有重新定义了该按钮类的自绘功能,添加新的属性和操作。
通过这次修改,感觉控件自绘也还是蛮有意思的,本来不能实现的功能,通过类的派生和自绘就能实现,感觉真爽,符合人性欲望无限扩展的本性。
说起VC的界面设计,大家都应该很清楚,MFC提供了很多标准的控件,例如按钮,下拉框等等,但是这些控件本身并不美观。要想改变它们的形状和外观,就必须要进行控件的自绘。我们常常看到QQ,360的界面设计,之所以那么狂吊炸天,就是因为他们有自己的界面库,能实现控件的自绘。现以一个简单的例子来介绍按钮自绘的方法实现。(部分函数代码和实现原理还是要列出的,因为代码才是王道啊,步骤就略过哈。)

1. 功能需求

1) 实现按钮文字任意位置的偏移。效果图如下:

这里写图片描述

这里写图片描述

2) 实现按钮的几种状态
Normal:
Normal
Over:
这里写图片描述
Down:
这里写图片描述
Disable:
这里写图片描述

2. 方法实现

首先定义一个CSkinButton类,它继承于CButton类。
1) 自绘属性
要想实现按钮自绘,需要把按钮风格修改为自绘属性BS_OWNERDRAW,从而系统会发送WM_DRAWITEM消息给CButton类,才会调用重载函数DrawItem实现自绘。可选择在对话框属性中或者在重载函数PreSubclassWindow中添加ModifyStyle(0,BS_OWNERDRAW);。

void CSkinButton::PreSubclassWindow() 
{
    // TODO: Add your specialized code here and/or call the base class
    ModifyStyle(0,BS_OWNERDRAW);
    CButton::PreSubclassWindow();
}

2) 重载DrawItem()函数
DrawItem()函数主要是根据按钮的状态来绘制自身的形状和外观,按钮控件自绘的功能就是在这里实现的。它主要包含了一个LPDRAWITEMSTRUCT的指针。声明如下:

typedef struct tagDRAWITEMSTRUCT {
UINT CtlType;         //控件的类型
UINT CtlID;           //自绘控件ID
UINT itemID;          //菜单项ID
UINT itemAction;      //绘制行为
UINT itemState;       //当前绘制操作完成后,所绘项的可见状态
HWND hwndItem;        //指定了组合框、列表框和按钮等自绘控件的窗口句柄
HDC hDC;              //绘制操作所使用的设备环境
RECT rcItem;          //绘制的矩形区域。这个区域就是上面hDC的作用范围。
ULONG_PTR itemData;   //菜单项数据
} DRAWITEMSTRUCT, NEAR *PDRAWITEMSTRUCT, FAR *LPDRAWITEMSTRUCT

具体实现如下:

void CSkinButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
    // TODO: Add your code to draw the specified item
    CRect rcItem(lpDrawItemStruct->rcItem);
    CString strText,strPath;
    CString strWorkPath;

    //按钮状态
    int nStatus = CONTROL_STATUS_NORMAL;
    if ( !IsWindowEnabled() )
    {
        nStatus = CONTROL_STATUS_DISABLE;
    }
    else
    {
        if ( m_bTrackMouseEvent )
        {
            if ( m_bLButtonDown )
            {
                nStatus = CONTROL_STATUS_DOWN;
            }
            else
            {
                nStatus = CONTROL_STATUS_OVER;
            }
        }
        else
        {
//          if ( ::GetFocus()==m_hWnd )
//          {
//              nStatus = CONTROL_STATUS_FOCUS;
//          }
//          else
            {
                nStatus = CONTROL_STATUS_DISABLE/*CONTROL_STATUS_NORMAL*/;
            }
        }
    }

    if ( m_hBitmap[nStatus] )
    {
        //绘图
        Draw9gridTransparent(lpDrawItemStruct->hDC, lpDrawItemStruct->rcItem, m_rcBorder9grid, m_hBitmap[nStatus]);
    }
    //使用透明的输出,也就是文字的背景是不改变的
    ::SetBkMode(lpDrawItemStruct->hDC, TRANSPARENT);

    GetWindowText(strText);
    if (m_unDrawTextStyle==BTN_DRAW_TEXT_CENTER)
    {
        ::DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), rcItem, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
    }
    else if (m_unDrawTextStyle==BTN_DRAW_TEXT_LEFT)
    {
        //根据偏移值来绘制
        rcItem.left = rcItem.left+m_unDrawTextSize;
        ::DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), rcItem, DT_LEFT|DT_VCENTER|DT_SINGLELINE);
    }
    else if (m_unDrawTextStyle==BTN_DRAW_TEXT_RIGHT)
    {
        rcItem.right = rcItem.right-m_unDrawTextSize;
        ::DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), rcItem, DT_RIGHT|DT_VCENTER|DT_SINGLELINE);
    }
}

3) 文字绘制
文字的绘制使用DrawText函数,偏移值只要根据矩形区域的left和right来设置就行了,具体可参看DrawItem函数:

        //根据偏移值来绘制
        rcItem.right = rcItem.right-m_unDrawTextSize;  
        ::DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), rcItem, DT_RIGHT|DT_VCENTER|DT_SINGLELINE);

4) Mouse相关响应
想要按钮随着鼠标移动来动态显示状态,需要触发WM_MOUSEMOVE,WM_MOUSELE

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇经验之谈―项目如何分模块(MVC) 下一篇vc获得窗口并枚举其子窗口

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目