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

📄 dlgtabctrl.h

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

#pragma once

/////////////////////////////////////////////////////////////////////////////
// Tab controls with embedded views
//
// Written by Bjarke Viksoe (bjarke@viksoe.dk)
// Copyright (c) 2002 Bjarke Viksoe.
//
// Add the following macro to the parent's message map:
//   REFLECT_NOTIFICATIONS()
//
// 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.
//

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

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



/////////////////////////////////////////////////////////////////////////////
// CDlgContainerCtrl - A container for Dialog views

#ifndef TCN_INITIALIZE
   #define TCN_INITIALIZE TCN_FIRST-10
   #define TCN_INSERTITEM TCN_FIRST-11
   #define TCN_DELETEITEM TCN_FIRST-12
#endif // TCN_INITIALIZE

template< class T, class TBase = CWindow, class TWinTraits = CControlWinTraits >
class ATL_NO_VTABLE CDlgContainerImpl : 
   public CWindowImpl< T, TBase, TWinTraits >
{
public:
   CSimpleValArray<HWND> m_aViews;
   HWND m_hWndClient;
   int m_iCurPos;

   CDlgContainerImpl() : 
      m_iCurPos(-1), 
      m_hWndClient(NULL)
   {
   }

   // Operations

   BOOL SubclassWindow(HWND hWnd)
   {
      ATLASSERT(m_hWnd == NULL);
      ATLASSERT(::IsWindow(hWnd));
      BOOL bRet = CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
      if( bRet ) _Init();
      return bRet;
   }

   BOOL PreTranslateMessage(MSG* pMsg)
   {
      if( m_hWndClient ) {
         TCHAR szClassName[8] = { 0 };
         ::GetClassName(m_hWndClient, szClassName, 7);
         if( ::lstrcmp(_T("#32770"), szClassName) == 0 ) return ::IsDialogMessage(m_hWndClient, pMsg);
      }
      return FALSE;
   }

   int AddItem(HWND hWnd)
   {
      ATLASSERT(::IsWindow(hWnd));
      // Add view
      m_aViews.Add(hWnd);
      // Initially we hide the view
      CWindow wnd = hWnd;
      wnd.ShowWindow(SW_HIDE);
      // FIX: Important; see Q149501
      wnd.ModifyStyleEx(0, WS_EX_CONTROLPARENT);
      // Notify owner
      NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_INSERTITEM };
      ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
      // Return new position
      return m_aViews.GetSize() - 1;
   }
   BOOL RemoveItem(HWND hWnd)
   {
      ATLASSERT(::IsWindow(hWnd));
      int iPos = m_aViews.Find(hWnd);
      return RemoveItem(iPos);
   }
   BOOL RemoveItem(int iPos)
   {
      if( iPos < 0 || iPos >= m_aViews.GetSize() ) return NULL;
      // Notify owner
      NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_DELETEITEM };
      ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
      // Remove view
      return m_aViews.RemoveAt(iPos);
   }
   HWND GetItem(int iPos) const
   {
      if( iPos < 0 || iPos >= m_aViews.GetSize() ) return NULL;
      return m_aViews[iPos];
   }
   int GetItemCount() const
   {
      return m_aViews.GetSize();
   }
   BOOL SetCurSel(int iPos)
   {
      if( iPos < 0 || iPos >= m_aViews.GetSize() ) return FALSE;
      if( iPos == m_iCurPos ) return TRUE; // Already selected
      // Ask user if it's OK to change selection...
      NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_SELCHANGING };
      LRESULT lRes = ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
      if( lRes!=0 ) return FALSE; // User declined
      // Assign new state
      HWND hWndActive = GetItem(m_iCurPos);
      HWND hWndNew = GetItem(iPos);
      m_iCurPos = iPos;      
      m_hWndClient = hWndNew;
      // Hide old view
      if( hWndActive ) ::SetWindowPos(hWndActive, NULL, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_HIDEWINDOW);
      // Resize new view into place
      BOOL bDummy;
      OnSize(0, 0, 0, bDummy);
      if( hWndNew ) ::SetWindowPos(hWndNew, NULL, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
      // If this is the first selection, make sure container gets focus.
      // Otherwise give focus to new view (Windows might hang in case an old
      // view still has focus and IsDialogMessage() is called!)
      if( hWndActive == NULL ) {
         SetFocus(); 
      }
      else if( IsChild(::GetFocus()) ) {
         //::SetFocus(hWndNew);
         //::PostMessage(hWndNew, WM_NEXTDLGCTL, 0, (LPARAM) FALSE);
         ::SetFocus(::GetWindow(hWndNew, GW_CHILD));
      }
      // Send notification
      nmh.code = TCN_SELCHANGE;
      ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
      return TRUE;
   }
   int GetCurSel() const
   {
      return m_iCurPos;
   }

   // Message map and handlers

   BEGIN_MSG_MAP(CDlgContainerImpl)
      MESSAGE_HANDLER(WM_CREATE, OnCreate)
      MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
      MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
      MESSAGE_HANDLER(WM_SIZE, OnSize)
      CHAIN_CLIENT_COMMANDS()
      REFLECT_NOTIFICATIONS()
   END_MSG_MAP()

   LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      _Init();
      return 0;
   }
   LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      return TRUE; // View fills entire client area
   }
   LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      // Set focus to first child of the view instead
      if( m_hWndClient == NULL ) return 0;
      //HWND hWndChild = ::GetWindow(hWndNew, GW_CHILD);
      HWND hWndChild = ::GetNextDlgTabItem(m_hWndClient, NULL, FALSE);
      if( hWndChild ) ::SetFocus(hWndChild);
      return 0;
   }
   LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      if( m_hWndClient == NULL ) return 0;
      RECT rc;
      GetClientRect(&rc);
      ::SetWindowPos(m_hWndClient, NULL, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, SWP_NOACTIVATE | SWP_NOZORDER);
      return 0;
   }

   // Implementation

   void _Init()
   {
      // FIX: Important; see Q149501
      ModifyStyleEx(0, WS_EX_CONTROLPARENT);
      // This is a little WTL subclass helper notification
      NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_INITIALIZE };
      ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
   }
};

class CDlgContainerCtrl : public CDlgContainerImpl<CDlgContainerCtrl>
{
public:
   DECLARE_WND_CLASS(_T("WTL_DlgContainer"))
};



/////////////////////////////////////////////////////////////////////////////
// CDialogTabCtrl - A Tab like control with active pages/dialogs

template< class T, class TBase = CTabCtrl, class TWinTraits = CControlWinTraits >
class ATL_NO_VTABLE CDialogTabImpl : 
   public CWindowImpl< T, TBase, TWinTraits >
{
public:
   DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())

   CDlgContainerCtrl m_ctrlViews;
   HWND m_hWndClient;

   // Operations

   BOOL SubclassWindow(HWND hWnd)
   {
      ATLASSERT(m_hWnd == NULL);
      ATLASSERT(::IsWindow(hWnd));
      BOOL bRet = CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
      if( bRet ) _Init();
      return bRet;
   }

   BOOL InsertItem(int nItem, LPTCITEM pItem, HWND hWnd)
   {
      ATLASSERT(nItem==GetItemCount()); // Only append at this time!
      // Notify owner
      NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_INSERTITEM };
      ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
      // Set the window parent (for correct resizing)
      ::SetParent(hWnd, m_hWndClient);
      // Add view and tab
      m_ctrlViews.AddItem(hWnd);
      BOOL bRes = (int) TBase::InsertItem(nItem, pItem) != -1;
      // Resize client
      BOOL bDummy;
      OnSize(WM_SIZE, 0, 0, bDummy);
      return bRes;
   }
   BOOL DeleteItem(int nItem)
   {
      // Notify owner
      NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_DELETEITEM };
      ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
      // Remove view and tab
      m_ctrlViews.RemoveItem(nItem);
      return TBase::DeleteItem(nItem);
   }
   BOOL DeleteAllItems()
   {
      while( m_ctrlViews.GetItemCount() > 0 ) m_ctrlViews.RemoveItem(0);
      return TBase::DeleteAllItems();
   }
   int SetCurSel(int iTab)
   {
      // Trigger first tab selection
      int iLastTab = TBase::SetCurSel(iTab);
      if( iLastTab != -1 ) {
         // Tab controls will not send notifications on TCM_SETCURSEL.
         // I hate that! So I'll send it instead...
         NMHDR nmh = { m_hWnd, GetDlgCtrlID(), TCN_SELCHANGE };
         ::SendMessage(GetParent(), WM_NOTIFY, nmh.idFrom, (LPARAM) &nmh);
      }
      return iLastTab;
   }
   HWND GetContainer() const
   {
      return m_hWndClient;
   }

   // Message map and handlers

   BEGIN_MSG_MAP(CDialogTabImpl)
      MESSAGE_HANDLER(WM_CREATE, OnCreate)
      MESSAGE_HANDLER(WM_SIZE, OnSize)
      MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
      REFLECTED_NOTIFY_CODE_HANDLER(TCN_SELCHANGE, OnTabSelect)
      CHAIN_CLIENT_COMMANDS()
   END_MSG_MAP()

   LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      LRESULT lRes = DefWindowProc();
      _Init();
      return lRes;
   }
   LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      if( m_hWndClient == NULL ) return 0;
      RECT rc;
      GetClientRect(&rc);
      AdjustRect(FALSE, &rc);
      ::SetWindowPos(m_hWndClient, NULL, 
         rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 
         SWP_NOACTIVATE | SWP_NOZORDER);
      return 0;
   }
   LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
   {
      // Need to repaint only the outer regions of the tab control.
      // The tab's client area is filled by views, so there is no need
      // to paint that area. Also an embedded ListView control sometimes fail
      // to repaint properly if we don't do this...
      CDCHandle dc((HDC)wParam);
      RECT rc;
      GetClientRect(&rc);
      CRgn rgn1, rgn2, rgn;
      rgn1.CreateRectRgnIndirect(&rc);
      AdjustRect(FALSE, &rc);
      rgn2.CreateRectRgnIndirect(&rc);
      rgn.CreateRectRgnIndirect(&rc);
      rgn.CombineRgn(rgn1, rgn2, RGN_DIFF);
      dc.FillRgn(rgn, ::GetSysColorBrush(COLOR_BTNFACE));
      return TRUE;
   }

   LRESULT OnTabSelect(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& bHandled)
   {
      int iIndex = GetCurSel();
      m_ctrlViews.SetCurSel(iIndex);
      bHandled = FALSE;
      return 0;
   }

   // Implementation

   void _Init()
   {
      // Create dialog container
      m_hWndClient = m_ctrlViews.Create(m_hWnd, rcDefault);
      ATLASSERT(::IsWindow(m_hWndClient));
      // FIX: Important; see Q149501
      ModifyStyleEx(0, WS_EX_CONTROLPARENT);
   }
};

class CDialogTabCtrl : public CDialogTabImpl<CDialogTabCtrl>
{
public:
   DECLARE_WND_SUPERCLASS(_T("WTL_DialogTabCtrl"), GetWndClassName())
};


#endif // !defined(AFX_PAGECTRL_H__20020427_0B15_DD2C_8E81_0080AD509054__INCLUDED_)

⌨️ 快捷键说明

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