• MFC自绘Button按钮分析和实现


    对于按压式的Button按钮,WM_CTLCOLOR无法完成按钮控件的背景颜色和字体颜色修改,若想要完成外观定制需要添加WM_DRAWITEM消息或者重写CButton类中的DrawItem函数完成按钮外观修改,下面逐一介绍。


    自绘制知识基础


    自绘制需要的两个基础步骤:

    1.控件类型设置为 BS_OWNERDRAW

    2.添加WM_DRAWITEM消息响应函数或者重写DrawItem函数。


    WM_DRAWITEM消息响应原型如下:

    afx_msg void OnDrawItem( int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct );
    
    参数: 
    nIDCtl 
        包含了发送WM_DRAWITEM消息的控件的标识符。如果菜单发送了此消息,则nIDCtl中包含0。  
    lpDrawItemStruct 
        指定了指向DRAWITEMSTRUCT数据结构的长指针,其中包含有关要画出的项和要求的绘图类型的信息。

    说明:
    当控件或菜单的可视状态发生变化时,框架为自画按钮控件、组合框控件、列表框控件或者菜单的拥有者调用这个成员函数。

    DRAWITEMSTRUCT结构体信息如下:

    typedef struct tagDRAWITEMSTRUCT 
    {
      UINT CtlType;   
      UINT CtlID;   
      UINT itemID; 
      UINT itemAction;   
      UINT itemState;   
      HWND hwndItem;   
      HDC hDC;   
      RECT rcItem; 
      ULONG_PTR itemData; 
    } DRAWITEMSTRUCT; 

    DrawItem函数原型如下,入参和OnDrawItem一样,不再重复介绍
    virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);

    需要说明的是,若某个控件拥有了BS_OWNERDRAW属性,则控件的绘制将由父窗口完成转移给了“程序员”,程序员需要完成所有的绘制工作,也就实现了控件自绘,若没有完成控件绘制功作,我们在界面上将看不到对应的控件,我们在重绘某个控件时,强烈推荐使用子类化方法,比如想自绘Button控件, 首先添加自己的类CMYButton 继承自 CButton,这样的设计符合程序设计思想,避免了父类功能的臃肿,也实现了程序的复用。



    自绘制原理分析


    自绘基本流程我已经绘制成流程图了,这样也清晰易懂,图中的数字标识也给出了简单介绍,自绘流程如图1所示:

                                                                         图1 自绘制原理


    1.子控件将要被绘制时,检测该控件有BS_OWNERDRAW属性,则向父窗口发送WM_DRAWITEM消息
    2.父窗口完成收集和准备控件绘制所必要的信息
    3.若ReflectLastMsg函数返回TRUE,表示消息反射成功,使用子控件中的绘制代码
    4.若ReflectLastMsg函数返回FALSE,表示消息反射失败,使用父窗口中的绘制代码
    5.消息反射成功了,我们就可以重写CButton中DrawItem虚函数完成控件自绘制


    下面将展示如何完成控件的绘制步骤:

    1.基于对话框建立DrawButton工程

    2.添三个按压式Button控件,其ID分别四IDC_YES,IDC_NO, IDC_HELP如图2所示:


                                      图2  控件布局


    3.分别在父窗口(对话框)和子类化中实现自绘,具体过程如下:


    父窗口中实现自绘制


    具体过程:类视图->属性->查找WM_WM_DRAWITEM->添加并编辑"OnDrawItem",其代码如下:

    void CDrawButtonDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
    {
       // TODO: 在此添加消息处理程序代码和/或调用默认值
       
       //获得button标题 
       CString btnCaption = _T("Dialog");
       CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    
       CRect drawRect;
       //获得绘图DC
       //得到原Button的矩形大小
       drawRect.CopyRect(&(lpDrawItemStruct->rcItem));    
       //绘制控件框架 
       pDC->DrawFrameControl(&drawRect,DFC_BUTTON,lpDrawItemStruct->CtlType);
    
    
       //创建画刷
       CBrush pBrush;
       pBrush.CreateSolidBrush(RGB(100,130,10));
       //画矩形 
       pDC->FillRect(drawRect,&pBrush);
    
    
       //定义一个CRect用于绘制文本 
       CRect textRect;
       //拷贝矩形区域 
       textRect.CopyRect(&drawRect);
       //获得字符串尺寸
       CSize sz = pDC->GetTextExtent(btnCaption);
       //调整文本位置 居中 
       textRect.top += (textRect.Height()- sz.cy)/2;
       //设置文本背景透明 
       pDC->SetBkMode(TRANSPARENT);
       //设置文本颜色
       pDC->SetTextColor(RGB(0,0,255)); 
       //绘制文本内容
       pDC->DrawText(btnCaption,&textRect,DT_RIGHT|DT_CENTER|DT_BOTTOM);
    
       CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);
    }


    子类化实现自绘制


    具体过程:

    1.类视图->点击工程名->点击添加->MFC类->基类:CButton,子类命名为CMyButton。

    2.资源视图->控件IDC_YES,IDC_HELP添加变量->类型选择为CMyButton。

    在自定义的CMyButton中我们添加DrawItem虚函数,其具体代码如下:

    void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
    {
        CString btnCaption = ""; 
        //设置标题
        switch (lpDrawItemStruct->CtlID)
        {
        case IDC_YES:
            btnCaption = "Yes";
        	break;
        case IDC_NO:
            btnCaption = "No";
            break;
        case IDC_HELP:
            btnCaption = "Help";
            break;
        default:
            ;
        } 
    
        CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    
        CRect drawRect;
        //获得绘图DC
        //得到原Button的矩形大小
        drawRect.CopyRect(&(lpDrawItemStruct->rcItem));    
        //绘制控件框架 
        pDC->DrawFrameControl(&drawRect,DFC_BUTTON,lpDrawItemStruct->CtlType);
    
        //使得初始的button颜色不一样
        static int nStepColor = 0; 
    
        //创建画刷
        CBrush pBrush;
        pBrush.CreateSolidBrush(RGB(100+nStepColor,130,nStepColor));
        //画矩形 
        pDC->FillRect(drawRect,&pBrush);
    
    
        //定义一个CRect用于绘制文本 
        CRect textRect;
        //拷贝矩形区域 
        textRect.CopyRect(&drawRect);
        //获得字符串尺寸
        CSize sz = pDC->GetTextExtent(btnCaption);
        //调整文本位置 居中 
        textRect.top += (textRect.Height()- sz.cy)/2;
        //设置文本背景透明 
        pDC->SetBkMode(TRANSPARENT);
        //设置文本颜色
        pDC->SetTextColor(RGB(0,0,255)); 
        //绘制文本内容
        pDC->DrawText(btnCaption,&textRect,DT_RIGHT|DT_CENTER|DT_BOTTOM);
        nStepColor += 120;
    
    }
    运行效果:


    说明中间一个Button按钮的自绘是由父窗口的OnDrawItem实现的。


  • 相关阅读:
    python(对象与实例属性)
    python(类和对象相关知识)
    python(面向对象设计)
    网络基础知识
    python(hashlib)
    子网掩码划分
    cmd命令
    Linux学习第一天:Linux常用快捷键
    python猜数字小游戏
    while语句
  • 原文地址:https://www.cnblogs.com/jinxiang1224/p/8468348.html
Copyright © 2020-2023  润新知