📄 tabbedmdi.h
字号:
public:
// Either call the normal "CreateMDIClient"
HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD)
{
HWND hWndClient = baseClass::CreateMDIClient(hWindowMenu, nID, nFirstChildID);
this->SubclassMDIClient();
return hWndClient;
}
// Or, after creating the client, call SubclassMDIClient
BOOL SubclassMDIClient()
{
ATLASSERT(m_hWndMDIClient && ::IsWindow(m_hWndMDIClient));
return m_tabbedClient.SubclassWindow(m_hWndMDIClient);
}
void SetTabOwnerParent(HWND hWndTabOwnerParent)
{
m_tabbedClient.SetTabOwnerParent(hWndTabOwnerParent);
}
HWND GetTabOwnerParent() const
{
return m_tabbedClient.GetTabOwnerParent();
}
// Message Handling
public:
typedef CTabbedMDIFrameWindowImpl< T, TBase, TWinTraits > thisClass;
typedef CMDIFrameWindowImpl<T, TBase, TWinTraits > baseClass;
BEGIN_MSG_MAP(thisClass)
CHAIN_MSG_MAP(baseClass)
END_MSG_MAP()
};
template <class T, class TBase = CMDIWindow, class TWinTraits = CMDIChildWinTraits>
class ATL_NO_VTABLE CTabbedMDIChildWindowImpl : public 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 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.
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 CWindowImpl<T>,
public CCustomTabOwnerImpl<T, TTabCtrl>
{
public:
// Expose the type of tab control
typedef typename TTabCtrl TTabCtrl;
protected:
typedef CMDITabOwnerImpl< T, TTabCtrl > thisClass;
typedef CWindowImpl<T> baseClass;
typedef CCustomTabOwnerImpl<T, TTabCtrl> customTabOwnerClass;
// Member variables
protected:
HWND m_hWndMDIClient;
DWORD m_nTabStyles;
bool m_bKeepTabsHidden;
// Constructors
public:
CMDITabOwnerImpl() :
m_hWndMDIClient(NULL),
m_nTabStyles(CTCS_TOOLTIPS | CTCS_BOLDSELECTEDTAB | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_DRAGREARRANGE),
m_bKeepTabsHidden(false)
{
ATLASSERT(UWM_MDICHILDACTIVATIONCHANGE != 0 && "The TabbedMDI Messages didn't get registered properly");
}
// 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 KeepTabsHidden(bool bKeepTabsHidden = true)
{
if(m_bKeepTabsHidden != bKeepTabsHidden)
{
m_bKeepTabsHidden = bKeepTabsHidden;
this->CalcTabAreaHeight();
if(m_bKeepTabsHidden)
{
this->OnRemoveLastTab();
}
else if(this->GetTabCtrl().GetItemCount() > 0)
{
this->OnAddFirstTab();
}
}
}
// 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -