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

📄 tabbedmdi.h

📁 These listed libraries are written in WTL. But it s really hard to mix both MFC & WTL together. Obvi
💻 H
📖 第 1 页 / 共 5 页
字号:
			}
		}
	}

	void HideTabControlIfChildNotMaximized(void)
	{
		if(m_bHideMDITabsWhenMDIChildNotMaximized)
		{
			T* pT = static_cast<T*>(this);
			pT->HideTabControl();
		}
	}

// Message Handling
public:
	DECLARE_WND_CLASS_EX(_T("MdiTabOwner"), 0, COLOR_APPWORKSPACE)

	BEGIN_MSG_MAP(thisClass)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
		MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
		NOTIFY_CODE_HANDLER(NM_CLICK, OnClick)
		NOTIFY_CODE_HANDLER(CTCN_ACCEPTITEMDRAG, OnAcceptItemDrag)
		NOTIFY_CODE_HANDLER(CTCN_CANCELITEMDRAG, OnCancelItemDrag)
		NOTIFY_CODE_HANDLER(CTCN_DELETEITEM, OnDeleteItem)
		NOTIFY_CODE_HANDLER(CTCN_SELCHANGING, OnSelChanging)
		NOTIFY_CODE_HANDLER(CTCN_SELCHANGE, OnSelChange)
		NOTIFY_CODE_HANDLER(CTCN_CLOSE, OnTabClose)

		// NOTE: CCustomTabCtrl derived classes no longer
		//  need notifications reflected.
		// REFLECT_NOTIFICATIONS()
	END_MSG_MAP()

	LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		// "baseClass::OnCreate()"
		LRESULT lRet = this->DefWindowProc(uMsg, wParam, lParam);
		bHandled = TRUE;
		if(lRet == -1)
		{
			return -1;
		}

		CreateTabWindow(m_hWnd, rcDefault, m_nTabStyles);

		return 0;
	}

	LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		DestroyTabWindow();

		// Say that we didn't handle it so that anyone else
		//  interested gets to handle the message
		bHandled = FALSE;
		return 0;
	}

	LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		if(m_TabCtrl)
		{
			// Let the tabs do all the drawing as flicker-free as possible
			return 1;
		}

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		RECT rect = {0};
		GetClientRect(&rect);

		m_TabCtrl.SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOACTIVATE);
		m_TabCtrl.UpdateLayout();

		bHandled = TRUE;

		return 0;
	}

	LRESULT OnContextMenu(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = TRUE;

		int nIndex = -1;

		POINT ptPopup = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
		if(ptPopup.x == -1 && ptPopup.y == -1)
		{
			nIndex = m_TabCtrl.GetCurSel();
			RECT rect = {0};
			if(nIndex >= 0)
			{
				// If there is a selected item, popup the menu under the node,
				// if not, pop it up in the top left of the tree view
				m_TabCtrl.GetItemRect(nIndex, &rect);
			}
			::MapWindowPoints(m_hWnd, NULL, (LPPOINT)&rect, 2);
			ptPopup.x = rect.left;
			ptPopup.y = rect.bottom;
		}
		else
		{
			POINT ptClient = ptPopup;
			::MapWindowPoints(NULL, m_hWnd, &ptClient, 1);
			CTCHITTESTINFO tchti = { 0 };
			tchti.pt = ptClient;
			//If we become templated, pT->HitTest(&tchti);
			nIndex = m_TabCtrl.HitTest(&tchti);
		}

		if( nIndex >= 0 )
		{
			TTabCtrl::TItem* pItem = m_TabCtrl.GetItem(nIndex);

			HWND hWndChild = pItem->GetTabView();
			if(hWndChild != NULL)
			{
				::SendMessage(hWndChild, UWM_MDICHILDSHOWTABCONTEXTMENU, wParam, MAKELPARAM(ptPopup.x, ptPopup.y));
			}
		}

		return 0;
	}

	LRESULT OnClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
	{
		// Be sure the notification is from the tab control
		// (and not from a sibling like a list view control)
		if(pnmh && (m_TabCtrl == pnmh->hwndFrom))
		{
			// If they left click on an item, set focus on the tab view,
			// but only if the view was already the active tab view
			// (otherwise our code to reduce flicker when switching
			// MDI children when maximized doesn't kick in).
			NMCTCITEM* item = (NMCTCITEM*)pnmh;
			if(item && (item->iItem >= 0) && (item->iItem == m_TabCtrl.GetCurSel()))
			{
				TTabCtrl::TItem* pItem = m_TabCtrl.GetItem(item->iItem);
				if(pItem->UsingTabView())
				{
					::SetFocus(pItem->GetTabView());
				}
			}
		}

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnAcceptItemDrag(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
	{
		// Be sure the notification is from the tab control
		// (and not from a sibling like a list view control)
		if(pnmh && (m_TabCtrl == pnmh->hwndFrom))
		{
			// If finished dragging, set focus on the tab view.
			NMCTC2ITEMS* item = (NMCTC2ITEMS*)pnmh;
			if(item && (item->iItem2 >= 0))
			{
				TTabCtrl::TItem* pItem = m_TabCtrl.GetItem(item->iItem2);
				if(pItem->UsingTabView())
				{
					::SetFocus(pItem->GetTabView());
				}
			}
		}

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnCancelItemDrag(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
	{
		// Be sure the notification is from the tab control
		// (and not from a sibling like a list view control)
		if(pnmh && (m_TabCtrl == pnmh->hwndFrom))
		{
			// If finished dragging, set focus on the tab view.
			NMCTCITEM* item = (NMCTCITEM*)pnmh;
			if(item && (item->iItem >= 0))
			{
				TTabCtrl::TItem* pItem = m_TabCtrl.GetItem(item->iItem);
				if(pItem->UsingTabView())
				{
					::SetFocus(pItem->GetTabView());
				}
			}
		}

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnDeleteItem(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
	{
		// Be sure the notification is from the tab control
		// (and not from a sibling like a list view control)
		if(pnmh && (m_TabCtrl == pnmh->hwndFrom))
		{
		}

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnSelChanging(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
	{
		// Be sure the notification is from the tab control
		// (and not from a sibling like a list view control)
		if(pnmh && (m_TabCtrl == pnmh->hwndFrom))
		{
		}

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnSelChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
	{
		// Be sure the notification is from the tab control
		// (and not from a sibling like a list view control)
		if(pnmh && (m_TabCtrl == pnmh->hwndFrom))
		{
			int nNewTab = m_TabCtrl.GetCurSel();

			if(nNewTab >= 0)
			{
				TTabCtrl::TItem* pItem = m_TabCtrl.GetItem(nNewTab);
				if(pItem->UsingTabView())
				{
					HWND hWndNew = pItem->GetTabView();
					HWND hWndOld = (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, NULL);
					if( hWndNew != hWndOld )
					{
						// We don't want any flickering when switching the active child
						//  when the child is maximized (when its not maximized, there's no flicker).
						//  There's probably more than one way to do this, but how we do
						//  it is to turn off redrawing for the MDI client window,
						//  activate the new child window, turn redrawing back on for
						//  the MDI client window, and force a redraw (not just a simple
						//  InvalidateRect, but an actual RedrawWindow to include
						//  all the child windows ).
						//  It might be nice to just turn off/on drawing for the window(s)
						//  that need it, but if you watch the messages in Spy++,
						//  the default implementation of the MDI client is forcing drawing
						//  to be on for the child windows involved.  Turning drawing off
						//  for the MDI client window itself seems to solve this problem.
						//

						LRESULT nResult = 0;

						WINDOWPLACEMENT wpOld = {0};
						wpOld.length = sizeof(WINDOWPLACEMENT);
						::GetWindowPlacement(hWndOld, &wpOld);
						if(wpOld.showCmd == SW_SHOWMAXIMIZED)
						{
							nResult = ::SendMessage(m_hWndMDIClient, WM_SETREDRAW, FALSE, 0);
						}

						nResult = ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (LPARAM)hWndNew, 0);

						WINDOWPLACEMENT wpNew = {0};
						wpNew.length = sizeof(WINDOWPLACEMENT);
						::GetWindowPlacement(hWndNew, &wpNew);
						if(wpNew.showCmd == SW_SHOWMINIMIZED)
						{
							::ShowWindow(hWndNew, SW_RESTORE);
						}

						if(wpOld.showCmd == SW_SHOWMAXIMIZED)
						{
							nResult = ::SendMessage(m_hWndMDIClient, WM_SETREDRAW, TRUE, 0);
							::RedrawWindow(m_hWndMDIClient, NULL, NULL,
								//A little more forceful if necessary: RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
								RDW_INVALIDATE | RDW_ALLCHILDREN);
						}
					}
				}
			}
		}

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnTabClose(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
	{
		// Be sure the notification is from the tab control
		// (and not from a sibling like a list view control)
		if(pnmh && (m_TabCtrl == pnmh->hwndFrom))
		{
			LPNMCTCITEM pnmCustomTab = (LPNMCTCITEM)pnmh;
			if(pnmCustomTab)
			{
				if(pnmCustomTab->iItem >= 0)
				{
					TTabCtrl::TItem* pItem = m_TabCtrl.GetItem(pnmCustomTab->iItem);
					if(pItem)
					{
						::PostMessage(pItem->GetTabView(), WM_SYSCOMMAND, SC_CLOSE, 0L);
					}
				}
			}
		}

		bHandled = FALSE;
		return 0;
	}

// Overrides from CCustomTabOwnerImpl
public:

	void ShowTabControl()
	{
		T* pT = static_cast<T*>(this);
		if(m_bHideMDITabsWhenMDIChildNotMaximized && m_hWndMDIClient)
		{
			HWND hWndActiveChild = (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, 0);
			if(hWndActiveChild && ::IsZoomed(hWndActiveChild))
			{
				pT->KeepTabsHidden(false);
			}
		}
		else
		{
			pT->KeepTabsHidden(false);
		}
	}

	void HideTabControl()
	{
		T* pT = static_cast<T*>(this);
		pT->KeepTabsHidden(true);
	}

	void KeepTabsHidden(bool bKeepTabsHidden = true)
	{
		if(m_bKeepTabsHidden != bKeepTabsHidden)
		{
			m_bKeepTabsHidden = bKeepTabsHidden;

			// CalcTabAreaHeight will end up doing UpdateLayout and Invalidate
			T* pT = static_cast<T*>(this);
			pT->CalcTabAreaHeight();

			// For MDI tabs, the UpdateLayout done by CalcTabAreaHeight
			//  is not quite enough to force the tab control to show or hide.
			//  So we'll force the tab control to be shown or hidden.
			if(m_bKeepTabsHidden)
			{
				pT->ForceHideMDITabControl();
			}
			else
			{
				pT->ForceShowMDITabControl();
			}
		}
	}

	void SetTabAreaHeight(int nNewTabAreaHeight)
	{
		if(m_bKeepTabsHidden)
		{
			m_nTabAreaHeight = 0;

			//T* pT = static_cast<T*>(this);
			//pT->UpdateLayout();
			//Invalidate();
		}
		else if(m_nTabAreaHeight != nNewTabAreaHeight)
		{
			int nOldTabAreaHeight = m_nTabAreaHeight;

			m_nTabAreaHeight = nNewTabAreaHeight;

			//T* pT = static_cast<T*>(this);
			//pT->UpdateLayout();
			//Invalidate();

			if(this->IsWindowVisible() == TRUE)
			{
				RECT rcMDIClient;
				::GetWindowRect(m_hWndMDIClient, &rcMDIClient);
				::MapWindowPoints(NULL, this->GetParent(), (LPPOINT)&rcMDIClient, 2);

				// Don't ask me why these two lines are necessary.
				// Take these lines out if you want to
				// convince yourself that they are :-)
				rcMDIClient.top -= nOldTabAreaHeight;
				rcMDIClient.bottom += nOldTabAreaHeight;

				// The tab resize/reposition logic happens when handling WM_WINDOWPOSCHANGING.
				// If that ever changes, make the appropriate change here.
				::SetWindowPos(
					m_hWndMDIClient, NULL,
					rcMDIClient.left, rcMDIClient.top,
					(rcMDIClient.right - rcMDIClient.left),(rcMDIClient.bottom - rcMDIClient.top),
					SWP_NOZORDER | SWP_NOACTIVATE);
			}
		}

⌨️ 快捷键说明

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