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

📄 cooltabctrls.h

📁 这是一本学习 window编程的很好的参考教材
💻 H
📖 第 1 页 / 共 3 页
字号:
   BOOL GetItemRect(int iItem, LPRECT prcItem) const
   {
      ATLASSERT(::IsWindow(m_hWnd));
      ATLASSERT(prcItem);
      if( prcItem == NULL ) return FALSE;
      ::SetRectEmpty(prcItem);
      if( iItem < 0 || iItem >= m_Items.GetSize() ) return FALSE;
      *prcItem = m_Items[iItem]->rcSize;
      return TRUE;
   }

   void GetMetrics(TCMETRICS *pMetrics) const
   {
      ATLASSERT(!::IsBadWritePtr(pMetrics,sizeof(TCMETRICS)));
      *pMetrics = m_metrics;
   }
   void SetMetrics(const TCMETRICS *pMetrics)
   {
      ATLASSERT(::IsWindow(m_hWnd));
      ATLASSERT(!::IsBadReadPtr(pMetrics,sizeof(TCMETRICS)));
      m_metrics = *pMetrics;
      _Repaint();
   }

   void SetSelFont(HFONT hFont)
   {
      m_hSelFont = hFont;
   }
   HFONT GetSelFont() const
   {
      return (m_dwExtStyle & TCS_EX_SELHIGHLIGHT) != 0 ? m_hSelFont : m_hFont;
   }

   int FindItem(LPTCITEM pFindInfo, int nStart = -1) const
   {
      ATLASSERT(::IsWindow(m_hWnd));
      if( nStart < 0 ) nStart = -1;     
      // Find the next item matching the criteria specified
      const UINT maskFind = pFindInfo->mask;
      int nCount = m_Items.GetSize();
      for( int i = nStart + 1; i < nCount; i++ ) {
         LPTCITEM pItem = m_Items[i];
         UINT mask = pItem->mask;
         if( (maskFind & mask) != maskFind ) continue;
         if( (maskFind & TCIF_PARAM) != 0 && pItem->lParam != pFindInfo->lParam ) continue;
         if( (maskFind & TCIF_TEXT) != 0 && pItem->pszText != NULL && pFindInfo->pszText != NULL && ::lstrcmp(pItem->pszText, pFindInfo->pszText) != 0 ) continue;
         if( (maskFind & TCIF_IMAGE) != 0 && pItem->iImage != pFindInfo->iImage ) continue;
         if( (maskFind & TCIF_STATE) != 0 && pItem->dwState != pFindInfo->dwState ) continue;
         return i;
      }
      return -1;
   }

   // Implementation

   void _Init()
   {
      ATLASSERT(::IsWindow(m_hWnd));
      ATLASSERT(GetStyle() & WS_CHILD);

      m_idDlgCtrl = GetDlgCtrlID();
      m_wndNotify = GetParent();

      SendMessage(WM_SETTINGCHANGE);

      // This is a little WTL subclass helper notification
      NMHDR nmh = { m_hWnd, m_idDlgCtrl, TCN_INITIALIZE };
      m_wndNotify.SendMessage(WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
   }

   ATLINLINE bool _ValidateItem(int iItem) const
   {
      ATLASSERT(iItem>=0 && iItem<m_Items.GetSize());
      if( iItem < 0 || iItem >= m_Items.GetSize() ) return false;
      return true;
   }
   ATLINLINE void _Repaint()
   {
      T* pT = static_cast<T*>(this);
      pT->UpdateLayout();
      Invalidate();
   }

   // Message map and handlers

   BEGIN_MSG_MAP(CCustomTabCtrl)
      CHAIN_MSG_MAP(COffscreenDrawRect< T >)
      MESSAGE_HANDLER(WM_CREATE, OnCreate)
      MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
      MESSAGE_HANDLER(WM_SIZE, OnSize)
      MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
      MESSAGE_HANDLER(WM_GETFONT, OnGetFont)
      MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
      MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
      MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
      MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
      MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonClick)
      MESSAGE_HANDLER(WM_RBUTTONDOWN, OnRButtonClick)
      MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage) 
   END_MSG_MAP()

   LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      LRESULT lRes = DefWindowProc();
      _Init();
      return lRes;
   }
   LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
   {      
      DeleteAllItems();  // Make sure to clean up memory
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
   {
      T* pT = static_cast<T*>(this);
      pT->UpdateLayout();
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnNcHitTest(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
   {
      POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
      ScreenToClient(&pt);
      T* pT = static_cast<T*>(this);
      int iItem = pT->HitTest(pt);
      if( iItem == -1 ) return HTTRANSPARENT;
      return HTCLIENT;
   }
   LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      return (LRESULT) (HFONT)( m_hFont != NULL ? m_hFont : AtlGetDefaultGuiFont() );
   }
   LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
   {
      m_hFont = (HFONT) wParam;
      if( lParam != 0 && IsWindowVisible() ) _Repaint();
      return 0;
   }

   LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      _Repaint();
      return 0;
   }
   LRESULT OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
   {
      return DefWindowProc(uMsg, wParam, lParam) | DLGC_WANTARROWS;
   }

   LRESULT OnLButtonClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
   {
      POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
      // Send click notification
      NMHDR nmh = { m_hWnd, m_idDlgCtrl, NM_CLICK };
      m_wndNotify.SendMessage(WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
      // Select tab below
      T* pT = static_cast<T*>(this);
      int iItem = pT->HitTest(pt);
      if( iItem != -1 ) {
         SetFocus();
         SetCurSel(iItem);
      }
      return 0;
   }
   LRESULT OnRButtonClick(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
   {
      SendMessage(WM_LBUTTONDOWN, wParam, lParam); // BUG: Triggers NM_CLICK as well!
      NMHDR nmh = { m_hWnd, m_idDlgCtrl, NM_RCLICK };
      m_wndNotify.SendMessage(WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
      return 0;
   }

   LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
   {
      MSG msg = { m_hWnd, uMsg, wParam, lParam };
      if( m_Tip.IsWindow() ) m_Tip.RelayEvent(&msg);
      bHandled = FALSE;
      return 1;
   }

   LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
   {
      switch( wParam ) {
      case VK_LEFT:
         if( m_iCurSel > 0 ) SetCurSel(m_iCurSel - 1);
         return 0;
      case VK_RIGHT:
         if( m_iCurSel < m_Items.GetSize() - 1 ) SetCurSel(m_iCurSel + 1);
         return 0;
      }
      bHandled = FALSE;
      return 0;
   }

   // Overridables

   void UpdateLayout()
   {
      int nCount = m_Items.GetSize();
      if( nCount == 0 ) return;

      CClientDC dc(m_hWnd);
      HFONT hOldFont = dc.SelectStockFont(DEFAULT_GUI_FONT);

      RECT rcClient;
      GetClientRect(&rcClient);

      SIZE szIcon = { 0 };
      if( !m_ImageList.IsNull() ) m_ImageList.GetIconSize(szIcon);

      HFONT hFont = GetFont();
      HFONT hSelFont = GetSelFont();
      DWORD dwStyle = GetStyle();

      // Reposition buttons
      int xpos = m_metrics.cxIndent;
      for( int i = 0; i < nCount; i++ ) {
         COOLTCITEM* pItem = m_Items[i];
         // Hidden button?
         if( (pItem->dwState & TCIS_HIDDEN) != 0 ) continue;
         // Determine width...
         int cx = 0;
         // Expand width according to decorations
         if( pItem->iImage >= 0 && (pItem->mask & TCIF_IMAGE) != 0 && !m_ImageList.IsNull() ) {
            cx += szIcon.cx + (m_metrics.cxImagePadding * 2);
         }
         if( pItem->mask & TCIF_TEXT ) {
            RECT rcText = { 0 };
            dc.SelectFont(i == m_iCurSel ? hSelFont : hFont);
            dc.DrawText(pItem->pszText, ::lstrlen(pItem->pszText), &rcText, DT_SINGLELINE|DT_CALCRECT);
            cx += (rcText.right - rcText.left) + (m_metrics.cxPadding * 2);
         }
         // Add margins
         cx += m_metrics.cxMargin * 2;
         // Selected button is allowed to grow further
         if( m_iCurSel == i ) cx += m_metrics.cxSelMargin * 2;
         // Need separators?
         if( m_dwExtStyle & TCS_EX_FLATSEPARATORS ) cx += 2;
         // Fixed width?
         if( pItem->mask & TCIF_WIDTH ) cx = pItem->cx;
         // Minimum width?
         if( cx < m_nMinWidth ) cx = m_nMinWidth;
         // Finally...
         RECT& rc = pItem->rcSize;
         rc.top = 0;
         rc.bottom = rcClient.bottom - rcClient.top;
         rc.left = xpos;
         rc.right = xpos + cx;
         xpos += cx + m_metrics.cxButtonSpacing;
      }

      // Allow buttons to fill entire row
      int cx = (rcClient.right - rcClient.left) - xpos;
      if( dwStyle & TCS_RAGGEDRIGHT ) {
         if( cx > 0 ) {
            int iDiff = cx / m_Items.GetSize();
            for( int i = 0; i < nCount; i++ ) {
               m_Items[i]->rcSize.right += iDiff;
               if( i > 0 ) m_Items[i]->rcSize.left += iDiff;
               iDiff *= 2;
            }
         }
      }
      // Compress buttons on same line
      if( cx < 0 && (m_dwExtStyle & TCS_EX_COMPRESSLINE) != 0 ) {
         int xpos = m_metrics.cxIndent;
         int iWidth = (rcClient.right - rcClient.left) / nCount;
         for( int i = 0; i < nCount; i++ ) {
            COOLTCITEM* pItem = m_Items[i];
            int cx = min( iWidth, pItem->rcSize.right - pItem->rcSize.left );
            pItem->rcSize.right = xpos + cx;
            pItem->rcSize.left = xpos;
            xpos += cx;
         }
      }
    
      // Expand currently selected button to overlap other buttons.
      // NOTE: To make sense, take into the cxIndent/cxMargin/cxSelMargin into
      //       account when choosing a value.
      if( m_iCurSel != - 1 ) ::InflateRect(&m_Items[m_iCurSel]->rcSize, m_metrics.cxOverlap, 0);

      dc.SelectFont(hOldFont);

      // Remove tooltips
      if( m_Tip.IsWindow() ) {
         TOOLINFO ti = { 0 };
         ti.cbSize = sizeof(ti);
         while( m_Tip.EnumTools(0, &ti) ) m_Tip.DelTool(&ti);
      }
      // Recreate tooltip rects
      for( int j = 0; j < nCount; j++ ) {
         if( m_Items[j]->mask & TCIF_TOOLTIP ) {
            if( !m_Tip.IsWindow() ) m_Tip.Create(m_hWnd);
            m_Tip.AddTool(m_hWnd, m_Items[j]->pszTipText, &m_Items[j]->rcSize, j + 1);
         }
         else if( dwStyle & TCS_TOOLTIPS ) {
            if( !m_Tip.IsWindow() ) m_Tip.Create(m_hWnd);
            m_Tip.AddTool(m_hWnd, m_Items[j]->pszText, &m_Items[j]->rcSize, j + 1);
         }
      }
      // Reactivate tooltips
      if( m_Tip.IsWindow() ) m_Tip.Activate(m_Tip.GetToolCount() > 0);
   }

   void DoPaint(CDCHandle dc, RECT &rcClip)
   {
      // NOTE: The handling of NM_CUSTOMDRAW is probably not entirely correct
      //       in the code below. But at least it makes a brave attempt to
      //       implement all the states described in MSDN docs.

      // Save current DC selections
      int save = dc.SaveDC();
      ATLASSERT(save!=0);

      // Make sure we don't paint outside client area (possible with paint dc)
      RECT rcClient;
      GetClientRect(&rcClient);
      ::IntersectClipRect(dc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);

      dc.FillRect(&rcClient, ::GetSysColorBrush(COLOR_3DFACE));

      // Prepare DC
      dc.SelectFont(GetFont());

      T* pT = static_cast<T*>(this);
      LRESULT lResStage;
      NMCUSTOMDRAW nmc = { 0 };
      nmc.hdr.hwndFrom = m_hWnd;
      nmc.hdr.idFrom = m_idDlgCtrl;
      nmc.hdr.code = NM_CUSTOMDRAW;
      nmc.hdc = dc;

      nmc.dwDrawStage = CDDS_PREPAINT;
      lResStage = m_wndNotify.SendMessage(WM_NOTIFY, nmc.hdr.idFrom, (LPARAM) &nmc);
      if( lResStage == CDRF_NOTIFYITEMDRAW || lResStage == CDRF_DODEFAULT ) {
         RECT rc;
         int nCount = m_Items.GetSize();
         // Draw the list items, except the selected one. It is drawn last
         // so it can cover the tabs below it.
         RECT rcIntersect;
         for( int i = 0; i < nCount; i++ ) {
            rc = m_Items[i]->rcSize;
            if( rc.bottom - rc.top == 0 ) pT->UpdateLayout();
            if( i != m_iCurSel ) {
               if( ::IntersectRect(&rcIntersect, &rc, &rcClip) ) {
                  nmc.dwItemSpec = i;
                  nmc.uItemState = 0;
                  if( (m_Items[i]->dwState & TCIS_DISABLED) != 0 ) nmc.uItemState |= CDIS_DISABLED;
                  nmc.rc = rc;
                  pT->ProcessItem(lResStage, nmc);
               }
            }
         }
         if( m_iCurSel != -1 ) {
            rc = m_Items[m_iCurSel]->rcSize;
            if( ::IntersectRect(&rcIntersect, &rc, &rcClip) ) {
               nmc.dwItemSpec = m_iCurSel;
               nmc.uItemState = CDIS_SELECTED;
               nmc.rc = rc;
               pT->ProcessItem(lResStage, nmc);
            }
         }
      }

      if( lResStage == CDRF_NOTIFYPOSTPAINT ) {
         nmc.dwItemSpec = 0;
         nmc.uItemState = 0;
         nmc.dwDrawStage = CDDS_POSTPAINT;
         m_wndNotify.SendMessage(WM_NOTIFY, nmc.hdr.idFrom, (LPARAM) &nmc);
      }

      dc.RestoreDC(save);
   }

   void ProcessItem(LRESULT lResStage, NMCUSTOMDRAW &nmc)
   {
      LRESULT lResItem = CDRF_DODEFAULT;
      if( lResStage == CDRF_NOTIFYITEMDRAW ) {
         nmc.dwDrawStage = CDDS_ITEMPREPAINT;
         lResItem = m_wndNotify.SendMessage(WM_NOTIFY, nmc.hdr.idFrom, (LPARAM) &nmc);
      }
      if( lResItem != CDRF_SKIPDEFAULT ) {
         // Do default item-drawing
         T* pT = static_cast<T*>(this);
         pT->DoItemPaint(nmc);
      }
      if( lResStage == CDRF_NOTIFYITEMDRAW && lResItem == CDRF_NOTIFYPOSTPAINT ) {
         nmc.dwDrawStage = CDDS_ITEMPOSTPAINT;
         m_wndNotify.SendMessage(WM_NOTIFY, nmc.hdr.idFrom, (LPARAM) &nmc);
      }
   }

   void DoItemPaint(NMCUSTOMDRAW &/*nmc*/)
   {
   }
};


/////////////////////////////////////////////////////////////////////////////
//
// The sample tab controls
//
// The follwing samples derive directly from CCustomTabCtrl.
// This means that they can actually use the internal members
// of this class. But they will not! To keep the code clean, I'm only

⌨️ 快捷键说明

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