滑动控件是Windows中最常用的控件之一。一般而言它是由一个滑动条,一个滑块和可选的刻度组成,用户可以通过移动滑块在相应的控件中显示对应的值。通常,在滑动控件附近一定有标签控件或编辑框控件,用于显示相应的值。滑动控件在应用程序中用途级为广泛,如在桌面的属性中就可以看到。本实例借鉴透明位图的显示方法,实现了滑动控件的透明效果,程序编译运行后的界面效果如图一所示:
图一、透明滑动条效果图  图示链接如下:http://develop.csai.cn/c/images/200610108382.jpg一、实现方法  在介绍如何实现透明的滑动条之前,先介绍一下滑动条的基本操作。滑动条控制(Slider Control)也叫轨道条控制,其主要是用一个带有轨道和滑标的小窗口以及窗口上的刻度,来让用户选择一个离散数据或一个连续的数值区间。滑动条既可以是水平方式的也可以是垂直方式的。滑动条控制的风格如下:  ·TBS_HORZ 滑动条是水平方向的
  ·TBS_VERT 滑动条是垂直方向的
  ·TBS_LEFT 滑动条位于窗口左侧
  ·TBS_RIGHT 滑动条位于窗口右侧
  ·TBS_TOP 滑动条位于窗口顶部
  ·TBS_BOTTOM 滑动条位于窗口底部
  ·TBS_BOTH 滑动条位于窗口两侧
  ·TBS_AUTOTICKS滑动条具有刻度,默认
  ·TBS_NOTICKS 滑动条不具有刻度  滑动条的刻度条在每一个数值位置显示一个刻度标记,如果在滑动条上显示某一数值选择区间,则应使用风格TBS_ENABLESELRANGE,此时选择区间两个不再是刻度标记,而是一个小的三角形符号。另外,使用风格TBS_NOTHUMB会使滑标消隐起来。  滑动条控制在MFC类库中被封装为CSliderCtrl控制,其主要操作是设置刻度范围、绘制刻度标记、设置选择范围和当前滑标位置等。当用户进行交互操作时,滑动条控制将向其父窗口发送消息WM_HSCROLL,所以在应用程序中应重载父窗口的OnHScroll()成员函数,以便对消息进行正确处理。由于考虑到和水平卷动杆公用同一个成员函数,OnHScroll()函数参数表中的指针变量被定义为CScrollBar*类型,而实际上消息是由滑动条产生的,所以在程序中必须把这个指针变量强制转换为CSliderCtrl*类型。滑动条和卷动杆的消息代码和含义都非常类似如TB_BOTTOM等,所以这种处理方法比较合理。SetRange()函数用来设置范围,SetPos()函数用来设置当前位置。  滑动条控制的创建方法是首先建立滑动条控制对象,然后使用Create()函数建立滑动条控制并绑定到该对象。滑动条控制类CSliderCtrl::Create()函数的调用格式如下:BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );   其中参数dwStyle用来确定滑动条控制风格;参数rect用来确定滑动条控制的大小和位置;参数pParentWnd用来确定滑动条控制的父窗口指针;参数nID用来确定滑动条控制的控制符ID怠?BR>
  滑动条控制对象类的属性方法包括取得滑动条大小GetLineSize()、设置滑动条大小SetLineSize()、取得滑动条页大小GetPageSize()、设置滑动条页大小SetPageSize()、取得滑动条最大位置GetRangeMax()、取得滑动条最小位置GetRangeMin()、取得滑动条范围GetRange()、设置滑块最小位置SetRangeMin()、设置滑块最大位置SetRangeMax()、设置滑动条范围SetRange()、取得滑块当前位置GetSelection()、设置滑块当前位置SetSelection()、取得滑动条当前位置GetPos()和设置滑动条当前位置SetPos()等。  滑动条控制的操作方法包括清除滑动条当前选择ClearSel()、验证滑动条当前位置是否在最大最小位置之间VerifyPos()、设置滑动条刻度的频度SetTicFreq()、在指定的位置设置刻度SetTic()和清除当前刻度标志ClearTics()等。  讲述了滑动条控件的基本操作后,我们来介绍如何实现透明的滑动条。对于透明的滑动条控件来说,操作上并没有发生任何变化,发生变化的仅仅是它的外关而已。为了达到控件的透明效果,本实例定义了一个CSliderCtrl类的子类CmySliderControl,并在该类中重载了CSliderCtrl控件的NM_CUSTOMDRAW消息响应函数来实现透明效果的绘制工作。滑动条控件以WM_NOTIFY的形式发送该消息给其父窗口,通知其要进行外观的绘制操作。其消息映射和响应函数分别如下:  ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
  void CMySliderControl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)   在消息响应函数中,参数pResult将传递给控件的父窗口,而参数pNMHDR指针指向了一个NMCUSTOMDRAW结构,该结构定义如下:  typedef struct tagNMCUSTOMDRAWINFO 
  {
   NMHDR hdr;//含有通知信息的NMHDR结构;
   DWORD dwDrawStage; //目前绘制的步骤;
   HDC hdc; //设备上下文句柄;
   RECT rc; //绘制的区域;
   DWORD dwItemSpec; //绘制项目条的说明;
   UINT uItemState;//当前项目条的状态
   LPARAM lItemlParam;//应用程序规定的数据;
  } 
  NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW;   从上述结构我们可以得到这么一个绘制透明控件的思路,首先判断当前绘制步骤是否处于准备绘制阶段,也既是NMCUSTOMDRAW 结构对象的成员变量dwDrawStage是否等于CDDS_PREPAINT,如是,pResult的返回值将是CDRF_NOTIFYITEMDRAW,这个返回值的意思是该控件将向父窗口发送所有与绘制相关的操作;如果成员变量dwDrawStage等于CDDS_ITEMPREPAINT,也就是说当前滑动控件处于具体项目的绘制准备阶段,那么就判断当前滑动控件要绘制的是滑动控件的轨道还是滑动控件的滑标(滑动控件由三个部分组成,轨道、滑标和刻度,在实现透明的滑动控件时我们可以不用考虑其刻度问题),如果NMCUSTOMDRAW对象的成员变量dwItemSpec 等于TBCD_THUMB,那末表示将要绘制的滑动控件的项目是滑标,此时可以让pResult返回CDRF_DODEFAULT,通知其父窗口自己将绘制自己本身,此次绘制循环不再发送任何消息。如果dwItemSpec等于TBCD_CHANNEL,表示即将绘制滑动控件的轨道,此时,也就是我们大显身手实现透明的时候了,具体如何实现透明的效果,请参考《实例:透明位图的实现》,处理完透明显示效果后,不要忘记让pResult返回"0"

解决方案 »

  1.   

    二、编程步骤  1、启动Visual C++6.0,生成一个基于对话框的应用程序,将该程序命名为"TransparentSliderDemo";  2、使用Class Wizard在程序中定义新的类CmySliderControl,其基类选择为CSliderCtrl;  3、在程序的对话框中放置三个滑动控件,使用Class Wizar分别为其在对话框类中添加对应的CSliderCtrl类型变量m_slider1、m_slider2、m_slider3,然后将上述变量修改为 CMySliderControl类型;  4、添加代码,编译运行程序;  三、程序代码  //////////////////////////////////////////// MySliderControl.h : header file
      #if !defined(AFX_MYSLIDERCONTROL_H__C76FA857_51CC_4EB6_A8E2_8323BBEF10BD__INCLUDED_)
      #define AFX_MYSLIDERCONTROL_H__C76FA857_51CC_4EB6_A8E2_8323BBEF10BD__INCLUDED_
      #if _MSC_VER > 1000
      #pragma once
      #endif // _MSC_VER > 1000  class CMySliderControl : public CSliderCtrl
      {
       CDC m_dcBk;
       CBitmap m_bmpBk;
       CBitmap *m_bmpBkOld;
       //CBitmap* m_pbmpOldBk;
       CPen m_penThumb;
       CPen m_penThumbLight;
       CPen m_penThumbLighter;
       CPen m_penThumbDark;
       CPen m_penThumbDarker;
       COLORREF m_crThumb;
       COLORREF m_crThumbLight;
       COLORREF m_crThumbLighter;
       COLORREF m_crThumbDark;
       COLORREF m_crThumbDarker;
       // Construction
       public:
       CMySliderControl();
       // Attributes
       public:
       // Operations
       public:
       // Overrides
       // ClassWizard generated virtual function overrides
       //{{AFX_VIRTUAL(CMySliderControl)
       //}}AFX_VIRTUAL
       // Implementation
       public:
       virtual ~CMySliderControl();
       // Generated message map functions
       protected:
       //{{AFX_MSG(CMySliderControl)
       afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);
       afx_msg BOOL OnEraseBkgnd(CDC* pDC);
       //}}AFX_MSG
       DECLARE_MESSAGE_MAP()
      };
      #endif   //////////// MySliderControl.cpp : implementation file
      #include "stdafx.h"
      #include "MySliderControl.h"
      #include "windows.h"
      #ifdef _DEBUG
      #define new DEBUG_NEW
      #undef THIS_FILE
      static char THIS_FILE[] = __FILE__;
      #endif  CMySliderControl::CMySliderControl()
      {
       m_dcBk.m_hDC = NULL;
      }  CMySliderControl::~CMySliderControl()
      { 
       DeleteObject(m_dcBk.SelectObject(&m_bmpBkOld));
       DeleteDC(m_dcBk); 
      }  BEGIN_MESSAGE_MAP(CMySliderControl, CSliderCtrl)
      //{{AFX_MSG_MAP(CMySliderControl)
      ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
      ON_WM_ERASEBKGND()
      //}}AFX_MSG_MAP
      END_MESSAGE_MAP()  void CMySliderControl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) 
      {
       LPNMCUSTOMDRAW lpcd = (LPNMCUSTOMDRAW)pNMHDR;
       CDC *pDC = CDC::FromHandle(lpcd->hdc);
       switch(lpcd->dwDrawStage)
       {
        case CDDS_PREPAINT:
        *pResult = CDRF_NOTIFYITEMDRAW ;
        break;
        //return; 
        case CDDS_ITEMPREPAINT:
        if (lpcd->dwItemSpec == TBCD_THUMB)
        {
         *pResult = CDRF_DODEFAULT;
         break;
        }
        if (lpcd->dwItemSpec == TBCD_CHANNEL)
        {
         CClientDC clientDC(GetParent());
         CRect crect;
         CRect wrect;
         GetClientRect(crect);
         GetWindowRect(wrect);
         GetParent()->ScreenToClient(wrect);
         if (m_dcBk.m_hDC == NULL)
         {
          m_dcBk.CreateCompatibleDC(&clientDC);
          m_bmpBk.CreateCompatibleBitmap(&clientDC, crect.Width(), crect.Height());
          m_bmpBkOld = m_dcBk.SelectObject(&m_bmpBk);
          m_dcBk.BitBlt(0, 0, crect.Width(), crect.Height(), &clientDC, wrect.left, wrect.top, SRCCOPY);
         }
         //This bit does the tics s transparently.
         CDC SaveCDC;
         CBitmap SaveCBmp, maskBitmap;
         //set the colours for the monochrome mask bitmap
         COLORREF crOldBack = pDC->SetBkColor(RGB(0,0,0));
         COLORREF crOldText = pDC->SetTextColor(RGB(255,255,255));
         CDC maskDC;
         int iWidth = crect.Width();
         int iHeight = crect.Height();
         SaveCDC.CreateCompatibleDC(pDC);
         SaveCBmp.CreateCompatibleBitmap(&SaveCDC, iWidth, iHeight);
         CBitmap* SaveCBmpOld = (CBitmap *)SaveCDC.SelectObject(SaveCBmp);
         //fill in the memory dc for the mask
         maskDC.CreateCompatibleDC(&SaveCDC);
         //create a monochrome bitmap
         maskBitmap.CreateBitmap(iWidth, iHeight, 1, 1, NULL);
         //select the mask bitmap into the dc
         CBitmap* OldmaskBitmap = maskDC.SelectObject(&maskBitmap);
         //copy the oldbitmap data into the bitmap, this includes the tics.
         SaveCDC.BitBlt(0, 0, iWidth, iHeight, pDC, crect.left, crect.top, SRCCOPY);
         //now copy the background into the slider
         BitBlt(lpcd->hdc, 0, 0, iWidth, iHeight, m_dcBk.m_hDC, 0, 0, SRCCOPY);
         // Blit the mask based on background colour
         maskDC.BitBlt(0, 0, iWidth, iHeight, &SaveCDC, 0, 0, SRCCOPY);
         // Blit the image using the mask
         pDC->BitBlt(0, 0, iWidth, iHeight, &SaveCDC, 0, 0, SRCINVERT);
         pDC->BitBlt(0, 0, iWidth, iHeight, &maskDC, 0, 0, SRCAND);
         pDC->BitBlt(0, 0, iWidth, iHeight, &SaveCDC, 0, 0, SRCINVERT);
         //restore and clean up
         pDC->SetBkColor(crOldBack);
         pDC->SetTextColor(crOldText);
         DeleteObject(SelectObject(SaveCDC, SaveCBmpOld));
         DeleteDC(SaveCDC);
         DeleteObject(maskDC.SelectObject(OldmaskBitmap));
         DeleteDC(maskDC);
         *pResult = 0;
         break;
        }
       }
      }
      BOOL CMySliderControl::OnEraseBkgnd(CDC* pDC)
      {
       return FALSE;
      }   四、小结  本实例主要是通过分析NMCUSTOMDRAW结构的成员变量的各个含义,判断当前滑动控件处于什么绘制阶段,绘制的是哪个项目,来决定执行何种操作,当滑动控件需要绘制轨道项目的时候,我们进行了相应的处理,实现了滑动控件的透明效果。
    转http://develop.csai.cn/c/200610101439581910.htm