📄 tabbedmdi.h
字号:
HWND GetTabOwnerParent() const
{
return m_tabbedClient.GetTabOwnerParent();
}
TTabCtrl& GetMDITabCtrl()
{
return m_tabbedClient.GetTabOwner().GetTabCtrl();
}
// Message Handling
public:
typedef CTabbedMDIFrameWindowImpl< T, TBase, TWinTraits > thisClass;
typedef WTL::CMDIFrameWindowImpl<T, TBase, TWinTraits > baseClass;
BEGIN_MSG_MAP(thisClass)
CHAIN_MSG_MAP(baseClass)
END_MSG_MAP()
};
template <class T, class TBase = WTL::CMDIWindow, class TWinTraits = ATL::CMDIChildWinTraits>
class ATL_NO_VTABLE CTabbedMDIChildWindowImpl : public WTL::CMDIChildWindowImpl<T, TBase, TWinTraits>
{
// Member variables
protected:
bool m_bMaximized;
// Constructors
public:
CTabbedMDIChildWindowImpl() :
m_bMaximized(false)
{
ATLASSERT(UWM_MDICHILDACTIVATIONCHANGE != 0 && "The TabbedMDI Messages didn't get registered properly");
}
// Overrides ofCMDIChildWindowImpl
public:
// NOTE: CreateEx also calls this (through T*)
HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0U, DWORD dwExStyle = 0U,
UINT nMenuID = 0U, LPVOID lpCreateParam = NULL)
{
// NOTE: hWndParent is going to become m_hWndMDIClient
// in CMDIChildWindowImpl::Create
ATLASSERT(::IsWindow(hWndParent));
BOOL bMaximizeNewChild = (WS_MAXIMIZE == (T::GetWndStyle(dwStyle) & WS_MAXIMIZE));
if(bMaximizeNewChild == FALSE)
{
// If WS_MAXIMIZE wasn't requested, check if the currently
// active MDI child (if there is one) is maximized. If so,
// maximize the new child window to match.
::SendMessage(hWndParent, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximizeNewChild);
}
if(bMaximizeNewChild == TRUE)
{
::SendMessage(hWndParent, WM_SETREDRAW, FALSE, 0);
// We'll ShowWindow(SW_SHOWMAXIMIZED) instead of using
// WS_MAXIMIZE (which would cause visual anomolies in some cases)
dwStyle = (T::GetWndStyle(dwStyle) & ~WS_MAXIMIZE);
}
HWND hWnd = baseClass::Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, nMenuID, lpCreateParam);
if(bMaximizeNewChild == TRUE)
{
::ShowWindow(hWnd, SW_SHOWMAXIMIZED);
::SendMessage(hWndParent, WM_SETREDRAW, TRUE, 0);
::RedrawWindow(hWndParent, NULL, NULL,
//A little more forceful if necessary: RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
RDW_INVALIDATE | RDW_ALLCHILDREN);
}
if(hWnd != NULL && ::IsWindow(m_hWnd) && !::IsChild(hWnd, ::GetFocus()))
::SetFocus(hWnd);
return hWnd;
}
// Methods
public:
void SetTitle(LPCTSTR sNewTitle, BOOL bUpdateTabText = TRUE)
{
this->SetWindowText(sNewTitle);
if(bUpdateTabText)
{
::SendMessage(m_hWndMDIClient, UWM_MDICHILDTABTEXTCHANGE, (WPARAM)m_hWnd, (LPARAM)sNewTitle);
}
}
void SetTabText(LPCTSTR sNewTabText)
{
::SendMessage(m_hWndMDIClient, UWM_MDICHILDTABTEXTCHANGE, (WPARAM)m_hWnd, (LPARAM)sNewTabText);
}
void SetTabToolTip(LPCTSTR sNewToolTip)
{
::SendMessage(m_hWndMDIClient, UWM_MDICHILDTABTOOLTIPCHANGE, (WPARAM)m_hWnd, (LPARAM)sNewToolTip);
}
// Message Handling
public:
typedef CTabbedMDIChildWindowImpl< T, TBase, TWinTraits > thisClass;
typedef WTL::CMDIChildWindowImpl<T, TBase, TWinTraits > baseClass;
BEGIN_MSG_MAP(thisClass)
MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate)
MESSAGE_HANDLER(WM_SETTEXT, OnSetText)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
MESSAGE_HANDLER(UWM_MDICHILDSHOWTABCONTEXTMENU, OnShowTabContextMenu)
MESSAGE_HANDLER(UWM_MDICHILDSAVEMODIFIED, OnSaveModified)
MESSAGE_HANDLER(UWM_MDICHILDCLOSEWITHNOPROMPT, OnCloseWithNoPrompt)
CHAIN_MSG_MAP(baseClass)
END_MSG_MAP()
LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
//HWND hWndDeactivating = (HWND)wParam;
HWND hWndActivating = (HWND)lParam;
if(m_hWnd == hWndActivating)
{
::SendMessage(m_hWndMDIClient, UWM_MDICHILDACTIVATIONCHANGE, (WPARAM)m_hWnd, 0);
}
bHandled = FALSE;
return 0;
}
LRESULT OnSetText(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
//::SendMessage(m_hWndMDIClient, UWM_MDICHILDTABTEXTCHANGE, (WPARAM)m_hWnd, lParam);
bHandled = FALSE;
return 0;
}
LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if(wParam == SIZE_MAXIMIZED && m_bMaximized == false)
{
m_bMaximized = true;
::SendMessage(m_hWndMDIClient, UWM_MDICHILDMAXIMIZED, (WPARAM)m_hWnd, lParam);
}
else if(wParam != SIZE_MAXIMIZED && m_bMaximized == true)
{
m_bMaximized = false;
::SendMessage(m_hWndMDIClient, UWM_MDICHILDUNMAXIMIZED, (WPARAM)m_hWnd, lParam);
}
bHandled = FALSE;
return 0;
}
LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
LRESULT lRes = this->DefWindowProc(uMsg, wParam, lParam);
if(lRes == MA_NOACTIVATE || lRes == MA_NOACTIVATEANDEAT)
return lRes; // frame does not want to activate
// activate window if necessary
HWND hWndActive = this->MDIGetActive();
if(m_hWnd != hWndActive)
{
this->MDIActivate(m_hWnd);
}
return lRes;
}
LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
// NOTE: ::IsWindowVisible(m_hWndClient) will be false if
// the frame is maximized. So just use "IsWindow" instead.
if(m_hWndClient != NULL && ::IsWindow(m_hWndClient))
{
::SetFocus(m_hWndClient);
}
bHandled = FALSE;
return 1;
}
LRESULT OnShowTabContextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
bHandled = TRUE;
// NOTE: Your deriving class doesn't have to do the context menu
// this way (show the system menu, use TPM_RETURNCMD, etc.)
// It can do whatever it wants. This is just the "fall through"
// implementation if you don't want to specialize.
// NOTE: The sender of the message has already handled the case
// when launching the context menu from the keyboard
// (translating -1,-1 into a usable position)
// We use essentially the same code as CMDICommandBarCtrl::OnNcLButtonDown
// (for when it handles the menu for the maximized child when clicking
// on the document icon to the left of the menus).
// NOTE: On Windows 2000 and 98 and later, we'll get bitmaps in the menu.
// Also note that when running on NT 4 or Win 95, CMDICommandBarCtrl::OnNcLButtonDown
// will fail to show the system menu at all because it doesn't like
// the real definition of TPM_VERPOSANIMATION. To avoid that
// problem, we won't even try to use TPM_VERPOSANIMATION.
WTL::CMenuHandle menu = this->GetSystemMenu(FALSE);
UINT command = (UINT)menu.TrackPopupMenu(TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), m_hWnd);
// See MSDN about "GetSystemMenu". Returns codes greater than
// 0xF000 (which happens to be SC_SIZE) are sent with WM_SYSCOMMAND
if(command >= SC_SIZE)
{
::PostMessage(m_hWnd, WM_SYSCOMMAND, command, 0L);
}
else if(command != 0)
{
// Non SC_* commands don't work with WM_SYSCOMMAND. We could handle
// the situation here by using WM_COMMAND, but there's other places
// where the "window menu" is dealt with that wouldn't have the same handling
// (like CMDICommandBarCtrl::OnNcLButtonDown). To help prevent
// errors, do an assert to warn. Instead of depending on this base
// implementation, you should override handling UWM_MDICHILDSHOWTABCONTEXTMENU
// in a derived class, and do your own context menu there.
// See the "TabDemo" sample for an example.
ATLASSERT(0 &&
"You've tried to put a non SC_* command in the window menu. "
"Please override the default context menu handling, and use a custom menu.");
}
return 0;
}
LRESULT OnSaveModified(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
// A derived class should handle this message.
// Return non-zero if you want to "cancel"
bHandled = FALSE;
return 0;
}
LRESULT OnCloseWithNoPrompt(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// When getting a real WM_CLOSE, you usually want to
// prompt to save if there's been modifications, and
// return TRUE to cancel. However, this is here for
// the cases when we need to close the window with no
// prompt and no chance to cancel
// (such as when we've already given the user the
// chance to save the file, but they said no).
return this->DefWindowProc(WM_CLOSE, 0, 0L);
}
};
/////////////////////////////////////////////////////////////////////////////
//
// CMDITabOwner
//
/////////////////////////////////////////////////////////////////////////////
template< class T, class TTabCtrl >
class CMDITabOwnerImpl :
public ATL::CWindowImpl<T>,
public CCustomTabOwnerImpl<T, TTabCtrl>
{
public:
// Expose the type of tab control
typedef typename TTabCtrl TTabCtrl;
protected:
typedef CMDITabOwnerImpl<T, TTabCtrl> thisClass;
typedef ATL::CWindowImpl<T> baseClass;
typedef CCustomTabOwnerImpl<T, TTabCtrl> customTabOwnerClass;
// Member variables
protected:
HWND m_hWndMDIClient;
DWORD m_nTabStyles;
BOOL m_bHideMDITabsWhenMDIChildNotMaximized;
// Constructors
public:
CMDITabOwnerImpl() :
m_hWndMDIClient(NULL),
m_nTabStyles(CTCS_TOOLTIPS | CTCS_BOLDSELECTEDTAB | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_DRAGREARRANGE),
m_bHideMDITabsWhenMDIChildNotMaximized(FALSE)
{
ATLASSERT(UWM_MDICHILDACTIVATIONCHANGE != 0 && "The TabbedMDI Messages didn't get registered properly");
m_nMinTabCountForVisibleTabs = 1;
m_bKeepTabsHidden = (m_nMinTabCountForVisibleTabs > 0);
}
// Methods
public:
void SetMDIClient(HWND hWndMDIClient)
{
m_hWndMDIClient = hWndMDIClient;
}
void SetTabStyles(DWORD nTabStyles)
{
m_nTabStyles = nTabStyles;
}
DWORD GetTabStyles(void) const
{
return m_nTabStyles;
}
void ModifyTabStyles(DWORD dwRemove, DWORD dwAdd)
{
DWORD dwNewStyle = (m_nTabStyles & ~dwRemove) | dwAdd;
if(m_nTabStyles != dwNewStyle)
{
m_nTabStyles = dwNewStyle;
}
}
void HideMDITabsWhenMDIChildNotMaximized(BOOL bHideMDITabsWhenMDIChildNotMaximized = TRUE)
{
m_bHideMDITabsWhenMDIChildNotMaximized = bHideMDITabsWhenMDIChildNotMaximized;
}
// Overrideables
public:
void ForceShowMDITabControl()
{
if(m_hWnd && !this->IsWindowVisible())
{
RECT rcMDIClient;
::GetWindowRect(m_hWndMDIClient, &rcMDIClient);
::MapWindowPoints(NULL, ::GetParent(m_hWndMDIClient), (LPPOINT)&rcMDIClient, 2);
this->ShowWindow(SW_SHOW);
// the MDI client resizes and shows our window when
// handling messages related to SetWindowPos
::SetWindowPos(
m_hWndMDIClient, NULL,
rcMDIClient.left, rcMDIClient.top,
(rcMDIClient.right - rcMDIClient.left),(rcMDIClient.bottom - rcMDIClient.top),
SWP_NOZORDER);
}
}
void ForceHideMDITabControl()
{
if(m_hWnd && this->IsWindowVisible())
{
RECT rcTabs;
m_TabCtrl.GetWindowRect(&rcTabs);
::MapWindowPoints(NULL, m_TabCtrl.GetParent(), (LPPOINT)&rcTabs, 2);
this->ShowWindow(SW_HIDE);
RECT rcMDIClient;
::GetWindowRect(m_hWndMDIClient, &rcMDIClient);
::MapWindowPoints(NULL, ::GetParent(m_hWndMDIClient), (LPPOINT)&rcMDIClient, 2);
// the MDI client resizes and shows our window when
// handling messages related to SetWindowPos
// TODO: Is there a better way to do this?
// We're basically hiding the tabs and
// resizing the MDI client area to "cover up"
// where the tabs were
DWORD dwStyle = m_TabCtrl.GetStyle();
if(CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM))
{
::SetWindowPos(
m_hWndMDIClient, NULL,
rcMDIClient.left, rcMDIClient.top,
(rcMDIClient.right - rcMDIClient.left),
(rcMDIClient.bottom - rcMDIClient.top) + (rcTabs.bottom - rcTabs.top),
SWP_NOZORDER);
}
else
{
::SetWindowPos(
m_hWndMDIClient, NULL,
rcMDIClient.left, rcMDIClient.top - (rcTabs.bottom - rcTabs.top),
(rcMDIClient.right - rcMDIClient.left),
(rcMDIClient.bottom - rcMDIClient.top) + (rcTabs.bottom - rcTabs.top),
SWP_NOZORDER);
}
}
}
void ShowTabControlIfChildMaximized(void)
{
if(m_bHideMDITabsWhenMDIChildNotMaximized)
{
size_t nTabCount = m_TabCtrl.GetItemCount();
if(nTabCount >= m_nMinTabCountForVisibleTabs)
{
T* pT = static_cast<T*>(this);
pT->ShowTabControl();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -