⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fadebutton.h

📁 这是一本学习 window编程的很好的参考教材
💻 H
字号:
#if !defined(AFX_FADEBUTTON_H__20020625_3FF0_6A9B_6234_0080AD509054__INCLUDED_)
#define AFX_FADEBUTTON_H__20020625_3FF0_6A9B_6234_0080AD509054__INCLUDED_

/////////////////////////////////////////////////////////////////////////////
// Fade Button - A DIB button control
//
// Written by Bjarke Viksoe (bjarke@viksoe.dk)
// Copyright (c) 2002 Bjarke Viksoe.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed by any means PROVIDING it is 
// not sold for profit without the authors written consent, and 
// providing that this notice and the authors name is included. 
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to you or your
// computer whatsoever. It's free, so don't hassle me about it.
//
// Beware of bugs.
//
#include "atldibfilters.h"
#pragma once

#ifndef __cplusplus
  #error WTL requires C++ compilation (use a .cpp suffix)
#endif

#ifndef __ATLAPP_H__
  #error This control requires atlapp.h to be included first
#endif

#ifndef __ATLCTRLS_H__
  #error This control requires atlctrls.h to be included first
#endif

#ifndef __ATLGDIX_H__
  #error This control requires my atlgdix.h header to be included first
#endif

#ifndef __ATLDIB_H__
  #error This control requires my atldib.h header to be included first
#endif

#ifndef __ATLDIBFILTERS_H__
  #error This control requires my atldibfilters.h header to be included first
#endif


// From Platform SDK (Windows 5.0 only)
#ifndef ODS_HOTLIGHT
#define ODS_HOTLIGHT 0x0040
#define ODS_INACTIVE 0x0080
#endif


/////////////////////////////////////////////////////////////////////////////
// DIB Fade button

template< class T, class TBase = CButton, class TWinTraits = CControlWinTraits >
class ATL_NO_VTABLE CFadeButtonImpl : 
   public CWindowImpl< T, TBase, TWinTraits >,
   public COwnerDraw< T >,
   public CMouseHover< T >
{
public:
   DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())

   enum { FADE_TIMERID = 33 };

   CToolTipCtrl m_tip;
   DWORD m_dwTickStart;
   DWORD m_dwDelay;
   DWORD m_dwSteps;
   COLORREF m_clrText;
   UINT m_uState;
   bool m_bAnimating;

   // Images
   CDib24 m_dibCurrent;
   CDib24 m_dibNormal;
   CDib24 m_dibOver;

   CFadeButtonImpl() : 
      m_dwDelay(300UL),
      m_dwSteps(4UL),
      m_uState(0U),
      m_bAnimating(false)
   {
   }

   // Operations
   
   BOOL SubclassWindow(HWND hWnd)
   {
      BOOL bRet = CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
      if( bRet ) _Init();
      return bRet;
   }
   BOOL SetToolTipText(LPCTSTR pstrText)
   {
      ATLASSERT(::IsWindow(m_hWnd));
      if( pstrText==NULL ) {
         if( m_tip.IsWindow() ) m_tip.Activate(FALSE);
         return TRUE;
      }
      m_tip.Activate(TRUE);
      m_tip.AddTool(m_hWnd, pstrText);
      return TRUE;
   }
   BOOL SetImages(UINT iNormal, UINT iOver)
   {
      if( !m_dibNormal.LoadBitmap(iNormal) ) return FALSE;
      if( !m_dibOver.LoadBitmap(iOver) ) return FALSE;
      return TRUE;
   }
   void SetTextColor(COLORREF clrText)
   {
      ATLASSERT(::IsWindow(m_hWnd));
      m_clrText = clrText;
      Invalidate();
   }
   void SetDelay(DWORD dwDelay, DWORD dwSteps)
   {
      ATLASSERT(dwDelay!=0 && dwSteps!=0);
      ATLASSERT(dwSteps<dwDelay);
      m_dwDelay = dwDelay;
      m_dwSteps = dwSteps;
   }

   // COwnerDraw

   void DrawItem(LPDRAWITEMSTRUCT lpDIS)
   {
      // Offscreen paint
      RECT rc = lpDIS->rcItem;
      CMemDC dc(lpDIS->hDC, &rc);

      // Paint black frame around buttons with focus
      if( lpDIS->itemState & ODS_FOCUS ) {
         HPEN hOldPen = dc.SelectStockPen(BLACK_PEN);
         HBRUSH hOldBrush = dc.SelectStockBrush(HOLLOW_BRUSH);
         dc.Rectangle(&rc);
         ::InflateRect(&rc, -1, -1);
         dc.SelectPen(hOldPen);
         dc.SelectBrush(hOldBrush);
      }

      // Paint the button canvas
      UINT uFrame = DFCS_BUTTONPUSH;
      if( lpDIS->itemState & ODS_SELECTED ) uFrame |= DFCS_PUSHED;
      if( lpDIS->itemState & ODS_DISABLED ) uFrame |= DFCS_INACTIVE;
      dc.DrawFrameControl(&rc, DFC_BUTTON, uFrame);

      RECT rcFocus = rc;
      ::InflateRect(&rcFocus, -3, -3);

      // Calculate a new image if needed.
      // Only change image if the state has changed from last time
      // we painted it...
      UINT uNewState = lpDIS->itemState;
      if( uNewState & ODS_DISABLED ) {
         if( (m_uState & ODS_DISABLED)==0 ) {
            m_dibCurrent = m_dibNormal;
            CGreyScaleImageFilter::Process(&m_dibCurrent);
         }
      }
      else if( uNewState & ODS_SELECTED ) {
         if( (m_uState & ODS_SELECTED)==0 ) m_dibCurrent = m_dibOver;
      }
      else if( m_fMouseOver ) {
         if( m_bAnimating  ) {
            // Create a new image (faded between the two bitmaps)
            DWORD dwTick = ::GetTickCount();
            short iPercent = (short)( (100UL * (dwTick - m_dwTickStart)) / m_dwDelay );
            if( iPercent > 100 ) iPercent = 100;
            m_dibCurrent = m_dibNormal;
            CFadeImageFilter::Process(&m_dibCurrent, &m_dibOver, iPercent);
         }
         else {
            m_dibCurrent = m_dibOver;
         }
         // Ok, it's actually a new button style...
         uNewState |= ODS_HOTLIGHT;
      }
      else {
         m_dibCurrent = m_dibNormal;
      }
      m_uState = uNewState;

      // Calculate where we should paint text and image
      DWORD dwStyle = GetStyle();  
      RECT rcImage = rc;
      int xOffset = 0;
      int yOffset = ( (rcImage.bottom-rcImage.top) - m_dibCurrent.GetHeight() )/2;
      if( dwStyle & BS_LEFT ) {
         xOffset = 4;
         rc.left += m_dibCurrent.GetWidth() + 8;
      }
      else {
         xOffset = rc.right-m_dibCurrent.GetWidth() - 4;
         rc.right -= m_dibCurrent.GetWidth() + 8;
      }

      // Draw image
      RECT rcText = rc;
      if( lpDIS->itemState & ODS_SELECTED ) {
         xOffset++;
         yOffset++;
         ::OffsetRect(&rcText, 1, 1);
      }
      m_dibCurrent.Draw(dc, rcImage.left + xOffset, rcImage.top + yOffset);
      
      // Draw text
      TCHAR szText[64] = { 0 };
      GetWindowText(szText, (sizeof(szText)/sizeof(TCHAR))-1);
      HFONT hOldFont = dc.SelectFont(GetFont());
      dc.SetBkMode(TRANSPARENT);
      dc.SetTextColor(m_clrText);
      dc.DrawText(szText, -1, &rcText, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
      dc.SelectFont(hOldFont);

      if( lpDIS->itemState & ODS_FOCUS ) dc.DrawFocusRect(&rcFocus);
   }

   // Message map and handlers

   typedef CFadeButtonImpl< T, TBase, TWinTraits > thisClass;

   BEGIN_MSG_MAP(thisClass)
      CHAIN_MSG_MAP( CMouseHover< T > )
      CHAIN_MSG_MAP_ALT( COwnerDraw<T>, 1 )
      MESSAGE_HANDLER(WM_CREATE, OnCreate)
      MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
      MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClick)
      MESSAGE_HANDLER(WM_MOUSEENTER, OnMouseEnter)
      MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
      MESSAGE_HANDLER(WM_TIMER, OnTimer)
   END_MSG_MAP()

   LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {      
      LRESULT lRes = DefWindowProc();
      _Init();
      return lRes;
   }
   LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      return 1;
   }
   LRESULT OnLButtonDblClick(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
   {
      // HACK: Ideally we would remove the CS_DBLCLCKS class style, but since we're
      //       subclassing the control we're forced to make it act like a regular click.
      //       Otherwise double-clicks will not show the button as pushed.
      return DefWindowProc(WM_LBUTTONDOWN, wParam, lParam);
   }   
   LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
   {
      if( m_tip.IsWindow() ) {
         MSG msg = { m_hWnd, uMsg, wParam, lParam };
         m_tip.RelayEvent(&msg);
      }
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnMouseEnter(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      // Don't fade on displays with 256 colours or less...
      CWindowDC dc(NULL);
      if( dc.GetDeviceCaps(BITSPIXEL) <= 8 ) return 0;
      // Start fade
      m_dwTickStart = ::GetTickCount();
      SetTimer(FADE_TIMERID, m_dwDelay / m_dwSteps);
      m_bAnimating = true;
      return 0;
   }
   LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
   {
      if( wParam != FADE_TIMERID ) {
         bHandled = FALSE;
         return 0;
      }
      DWORD dwTick = ::GetTickCount();
      if( dwTick - m_dwTickStart > m_dwDelay ) {
         KillTimer(FADE_TIMERID);
         m_bAnimating = false;
      }
      Invalidate();
      UpdateWindow();
      return 0;
   }

   // Implementation
   
   void _Init()
   {
      // We need this style to prevent Windows from painting the button
      ModifyStyle(0x0F | BS_NOTIFY, BS_OWNERDRAW);
      
      // Create a tool tip
      m_tip.Create(m_hWnd);
      ATLASSERT(m_tip.IsWindow());

      // Set other data members
      m_clrText = ::GetSysColor(COLOR_BTNTEXT);
      m_dibCurrent = m_dibNormal;
   }
};

class CFadeButtonCtrl : public CFadeButtonImpl<CFadeButtonCtrl>
{
public:
   DECLARE_WND_SUPERCLASS(_T("WTL_FadeButton"), GetWndClassName())
};


#endif // !defined(AFX_FADEBUTTON_H__20020625_3FF0_6A9B_6234_0080AD509054__INCLUDED_)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -