zoukankan      html  css  js  c++  java
  • CButton 实现重绘时需要注意(转)

    最近在做一个CheckBox的透明时,遇到了CButton的重绘,网上关于此类问题的帖子比较多,实现方法也比较多。

    这里只说一下我在实际操作中遇见的一些问题和解决方法。

    1、在窗体中重载WM_CTLCOLOR实现透明时,在某些使用了XP样式风格的系统中,CheckBox出现了黑乎乎的底色,没有真正达到透明效果,具体原因还不清楚,希望高手指点。代码如下:

    HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
    {
      HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
      // TODO:  Change any attributes of the DC here
      switch(pWnd->GetDlgCtrlID()){
      case IDC_CHECK1:
        pDC->SetBkMode(TRANSPARENT);
        pDC->SetTextColor(RGB(0,0,0));
        hbr=(HBRUSH)GetStockObject(NULL_BRUSH);
      default:
        break;
      }
      // TODO:  Return a different brush if the default is not desired
      return hbr;
    }

    2、使用子类化方法,自定义一个类CCheckBoxTrans并继承自CButton,直接重载WM_PAINT消息处理函数,并在Dialog使用处定义MFC成员量CButton m_oCheck并替换为CCheckBoxTrans m_oCheck,具体代码如下:

    class CTestDlg : public CDialog
    {
    public:
      CTestDlg(CWnd* pParent = NULL);

      // Dialog Data
      //{{AFX_DATA(CTestDlg)
      enum { IDD = IDD_TEST_DIALOG };
      CCheckBoxTrans m_oCheck;
      //}}AFX_DATA

      .....

      DECLARE_MESSAGE_MAP()
    };

    void CCheckBoxTrans::OnPaint()
    {
      CPaintDC dc(this); // device context for painting
     
      // TODO: Add your message handler code here
     
      CRect rect;
      GetClientRect(&rect);
     
      CRect BoxRect;
      BoxRect=rect;
      BoxRect.right=BoxRect.left+13;
      dc.DrawFrameControl(BoxRect, DFC_BUTTON, DFCS_BUTTONCHECK|(GetCheck()? DFCS_CHECKED: 0)); 
      CFont oFont;
      oFont.CreateFontIndirect(&m_sFont);
      CBrush* pOldBrush=(CBrush*)dc.SelectObject((HBRUSH)GetStockObject(NULL_BRUSH));
      CFont* pOldFont=(CFont*)dc.SelectObject(&oFont); 
      dc.SetBkMode(TRANSPARENT);
     
      CString StrWndText;
      GetWindowText(StrWndText);
     
      rect.OffsetRect(17, 0);
      dc.DrawText(StrWndText, &rect, DT_LEFT|DT_VCENTER|DT_SINGLELINE);

      //rect.OffsetRect(-3, 0);
      //rect.right=3+StrWndText.GetLength()*(GetDeviceCaps(dc.GetSafeHdc(), LOGPIXELSY)*abs(m_sFont.lfHeight)/72);
      //if(GetFocus())
        //dc.DrawFocusRect(&rect);

      dc.SelectObject(pOldFont); 
      //dc.SelectObject(pOldBrush);
      oFont.DeleteObject(); 
      // Do not call CButton::OnPaint() for painting messages
    }

    这种方法基本达到要求,不过我还是发现有过两个问题:A.当CheckBox被非聚焦时,有时会出现聚焦的虚线框;B.有时候受XP样式风格影响,字体会变大很多,和其他控件的不一样,同时会有文字重叠显示的现象,具体原因还不清楚,希望高手指点。

    3、采用OWNERDRAW的Button,同样继承CButton类,不过这次不重载OnPaint函数,而是像网上说的继承WM_DRAWITEM消息的处理函数virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );//注意不是OnDrawItem,千万不要直接用类向导重载WM_DRAWITEM,这两个可不是一个函数。另外需要重载virtual void PreSubclassWindow();具体代码如下:

    class CCheckBoxTrans : public CButton
    {
    // Construction
    public:
     CCheckBoxTrans();

    // Attributes
    public:

    // Operations
    public:

    // Overrides
     // ClassWizard generated virtual function overrides
     //{{AFX_VIRTUAL(CCheckBoxTrans)
    public:
      virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    protected:
      virtual void PreSubclassWindow();
     //}}AFX_VIRTUAL
      ......
      DECLARE_MESSAGE_MAP()
    };
    void CCheckBoxTrans::PreSubclassWindow()
    {
      // TODO: Add your specialized code here and/or call the base class
      SetButtonStyle(GetButtonStyle()|BS_OWNERDRAW);
      CButton::PreSubclassWindow();
    }
    void CXPButton::DrawItem(LPDRAWITEMSTRUCT 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 + 1];
     ::GetWindowText(m_hWnd, strText, MAX_PATH);
     
     //获取按钮的状态
     if (state & ODS_FOCUS){
     }else{
     }
     if (state & ODS_SELECTED || state & ODS_DEFAULT){
     }

     
     ......//绘制控件其他部件(略)

     //显示按钮的文本

      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);
        if (state & ODS_SELECTED)
          pt.Offset(1, 1);
        int nMode = pDC->SetBkMode(TRANSPARENT);
        if (state & ODS_DISABLED)
          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);
    }

    此外还需要重载鼠标和键盘的一些相关消息,不然控件画出来了,结果不能用:(,千万要注意哦。

    所以子类化自绘的方法应该是可以解决这个问题,但是不如直接CMFCButton的设置图片的方法来的省时省力

  • 相关阅读:
    Linux服务器在SSH客户端如何实现免密登录
    在linux服务器下JMeter如何执行jmx性能脚本
    单元测试
    JsonPath如何获取JSON数据中的值
    TestNG Suite 运行出现中文乱码如何解决
    Java如何获取JSON数据中的值
    数组的冒泡排序
    java数组扩容
    null类型不能转换成double基本类
    Java 将目录下的文件移动到指定的目录文件下
  • 原文地址:https://www.cnblogs.com/rainbowzc/p/1749867.html
Copyright © 2011-2022 走看看