📄 tabbedmdi.h
字号:
}
if((pWinPos->flags & SWP_NOSIZE) == 0)
{
pWinPos->cy -= nTabAreaHeight;
}
}
}
}
// "base::OnWindowPosChanging()"
LRESULT lRet = this->DefWindowProc(uMsg, wParam, lParam);
bHandled = TRUE;
return lRet;
}
LRESULT OnNcPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
if(m_bDrawFlat &&
WS_EX_CLIENTEDGE == (this->GetExStyle() & WS_EX_CLIENTEDGE))
{
// When we have WS_EX_CLIENTEDGE and drawing "flat",
// we'll paint the non-client edges ourself with a more flat look.
// NOTE: If WS_EX_CLIENTEDGE ever takes up more than 2 pixels
// on each edge, update the drawing code.
WTL::CWindowDC dc(this->m_hWnd);
if(dc)
{
RECT rcWindow;
this->GetWindowRect(&rcWindow);
::OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top);
dc.DrawEdge(&rcWindow, EDGE_ETCHED, BF_FLAT|BF_RECT);
}
/*
// Note: The documentation says the flags should be
// DCX_WINDOW|DCX_INTERSECTRGN
// but that wasn't working.
// On http://freespace.virgin.net/james.brown7/tutorials/tips.htm
// they mention you also need to OR in the flag "0x10000".
CDCHandle dc = this->GetDCEx((HRGN)wParam, DCX_WINDOW|DCX_INTERSECTRGN | 0x10000));
if(!dc.IsNull())
{
RECT rcWindow;
this->GetWindowRect(&rcWindow);
::OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top);
dc.DrawEdge(&rcWindow, EDGE_ETCHED, BF_FLAT|BF_RECT);
::ReleaseDC(dc);
}
*/
bHandled = TRUE;
}
else
{
bHandled = FALSE;
}
return 0;
}
LRESULT OnMDIDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// NOTE: For symmetry, we could try to handle WM_MDICREATE
// for tab creation. There are 2 reasons we don't:
// 1. With WTL, the implementation doesn't use WM_MDICREATE,
// so it wouldn't be reliable to rely on it
// 2. We don't need to. Handling the change in child
// activation to display the tab, if its not there,
// creates, DisplayTab will create the corresponding tab.
// Remove the tab for the child being destroyed.
// Before removing the tab, we want the default happen,
// so that the MDI Client figures out who to activate next.
// If we removed the tab first, the "DeleteItem" on
// the tab wouldn't know the next best tab to select,
// and so if it's removing the tab that's currently selected,
// it changes the selection to 0.
// But by having the MDI client activate the child
// "next in line" (Z-Order), that child will be activated,
// and its tab will be selected, so that by the time we remove
// the tab for this child, the tab won't be selected.
LRESULT lRet = this->DefWindowProc(uMsg, wParam, lParam);
bHandled = TRUE;
if(wParam != NULL)
{
m_MdiTabOwner.RemoveTab((HWND)wParam);
}
return lRet;
}
LRESULT OnChildActivationChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// NOTE: We'd like to just handle WM_MDIACTIVATE when sent to
// the MDI client to know when the active MDI child has changed.
// Unfortunately, you don't HAVE to send WM_MDIACTIVATE to the
// MDI Client to change the active child (such as clicking
// a different MDI child to activate it).
// However, the MDI *child* will *always* receive WM_MDIACTIVATE.
// In fact, the child losing focus gets WM_MDIACTIVATE,
// and then the child gaining focus gets WM_MDIACTIVATE
// (the "deactivating" and "activating" windows are sent as
// the WPARAM and LPARAM both times).
// So we'll make the "activating" child window responsible for
// sending us a message (UWM_MDICHILDACTIVATIONCHANGE)
// when it gets a WM_MDIACTIVATE message. We'll use this
// to display the tab (switching the selected tab to the
// corresponding tab, or creating a tab for the child and
// setting it as selected)
if(wParam != NULL)
{
m_MdiTabOwner.DisplayTab((HWND)wParam, TRUE, m_bUseMDIChildIcon);
}
return 0;
}
LRESULT OnChildTabTextChange(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
// NOTE: Our direct children are Frame windows.
// We make the MDI child responsible for sending us a
// message (UWM_MDICHILDTABTEXTCHANGE) if they want to
// update the text of the corresponding tab.
if(wParam != NULL)
{
m_MdiTabOwner.UpdateTabText((HWND)wParam, (LPCTSTR)lParam);
}
return 0;
}
LRESULT OnChildTabToolTipChange(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
// We make the MDI child responsible for sending us a
// message (UWM_MDICHILDTABTOOLTIPCHANGE) with the tooltip
// if that tooltip is something different than the tab text.
if(wParam != NULL)
{
m_MdiTabOwner.UpdateTabToolTip((HWND)wParam, (LPCTSTR)lParam);
}
return 0;
}
LRESULT OnChildMaximized(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
HWND hWndMaximized = (HWND)wParam;
HWND hWndActiveChild = (HWND)this->SendMessage(WM_MDIGETACTIVE, 0, 0);
if(hWndMaximized == hWndActiveChild)
{
m_MdiTabOwner.ShowTabControlIfChildMaximized();
}
bHandled = FALSE;
return 0;
}
LRESULT OnChildUnMaximized(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
HWND hWndUnMaximized = (HWND)wParam;
HWND hWndActiveChild = (HWND)this->SendMessage(WM_MDIGETACTIVE, 0, 0);
if(hWndUnMaximized == hWndActiveChild)
{
m_MdiTabOwner.HideTabControlIfChildNotMaximized();
}
bHandled = FALSE;
return 0;
}
};
template <class T, class TBase = CCommandBarCtrlBase, class TWinTraits = ATL::CControlWinTraits>
class ATL_NO_VTABLE CTabbedMDICommandBarCtrlImpl : public WTL::CMDICommandBarCtrlImpl<T, TBase, TWinTraits>
{
protected:
typedef CTabbedMDICommandBarCtrlImpl thisClass;
typedef CMDICommandBarCtrlImpl<T, TBase, TWinTraits> baseClass;
typedef CCommandBarCtrlImpl<T, TBase, TWinTraits> grandparentClass;
// Extended data
protected:
bool m_bUseMaxChildDocIconAndFrameCaptionButtons:1;
// Constructors
public:
CTabbedMDICommandBarCtrlImpl() :
m_bUseMaxChildDocIconAndFrameCaptionButtons(true)
{
}
// Public methods
public:
void UseMaxChildDocIconAndFrameCaptionButtons(bool bUseMaxChildDocIconAndFrameCaptionButtons = true)
{
m_bUseMaxChildDocIconAndFrameCaptionButtons = bUseMaxChildDocIconAndFrameCaptionButtons;
}
// Overrides
public:
void GetSystemSettings()
{
baseClass::GetSystemSettings();
m_cxLeft += 4;
}
// Message Handling
public:
BEGIN_MSG_MAP(thisClass)
if(m_bUseMaxChildDocIconAndFrameCaptionButtons)
{
CHAIN_MSG_MAP(baseClass)
}
else
{
CHAIN_MSG_MAP(grandparentClass)
}
ALT_MSG_MAP(1) // Parent window messages
if(m_bUseMaxChildDocIconAndFrameCaptionButtons)
{
CHAIN_MSG_MAP_ALT(baseClass, 1)
}
else
{
CHAIN_MSG_MAP_ALT(grandparentClass, 1)
}
ALT_MSG_MAP(2) // MDI client window messages
MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)
if(m_bUseMaxChildDocIconAndFrameCaptionButtons)
{
MESSAGE_HANDLER(WM_MDIDESTROY, OnMDIDestroy)
MESSAGE_HANDLER(UWM_MDICHILDMAXIMIZED, OnChildMaximized)
MESSAGE_HANDLER(UWM_MDICHILDUNMAXIMIZED, OnChildUnMaximized)
}
// NOTE: If future implementations of CMDICommandBarCtrlImpl
// add MDI client related handlers for ALT_MSG_MAP(2),
// either add them here or chain to the base
ALT_MSG_MAP(3) // Message hook messages
// NOTE: We don't want to depend on the command bar's
// hooked messages for telling us about maximization
// changes. We can do the job with the normal
// MDI messages and our special MDI messages
//MESSAGE_RANGE_HANDLER(0, 0xFFFF, OnAllHookMessages)
CHAIN_MSG_MAP_ALT(grandparentClass, 3)
END_MSG_MAP()
// MDI client window message handlers
LRESULT OnMDISetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
m_wndMDIClient.DefWindowProc(uMsg, NULL, lParam);
HMENU hOldMenu = GetMenu();
BOOL bRet = AttachMenu((HMENU)wParam);
bRet; // avoid level 4 warning
ATLASSERT(bRet);
#if (_WTL_VER >= 0x0710) && (_WIN32_IE >= 0x0400)
T* pT = static_cast<T*>(this);
pT->UpdateRebarBandIdealSize();
#endif //(_WTL_VER >= 0x0710) && (_WIN32_IE >= 0x0400)
return (LRESULT)hOldMenu;
}
LRESULT OnMDIDestroy(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
HWND hWndChild = (HWND)wParam;
if(m_hWndChildMaximized == hWndChild)
{
bool bMaxOld = m_bChildMaximized;
HICON hIconOld = m_hIconChildMaximized;
m_bChildMaximized = false;
m_hWndChildMaximized = NULL;
m_hIconChildMaximized = NULL;
T* pT = static_cast<T*>(this);
pT->RefreshMaximizedState((bMaxOld != m_bChildMaximized), (hIconOld != m_hIconChildMaximized));
}
bHandled = FALSE;
return 0;
}
LRESULT OnChildMaximized(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
HWND hWndChild = (HWND)wParam;
bool bMaxOld = m_bChildMaximized;
HICON hIconOld = m_hIconChildMaximized;
m_bChildMaximized = true;
if(m_hWndChildMaximized != hWndChild)
{
ATL::CWindow wnd = m_hWndChildMaximized = hWndChild;
m_hIconChildMaximized = wnd.GetIcon(FALSE);
if(m_hIconChildMaximized == NULL) // no icon set with WM_SETICON, get the class one
{
// need conditional code because types don't match in winuser.h
#ifdef _WIN64
m_hIconChildMaximized = (HICON)::GetClassLongPtr(wnd, GCLP_HICONSM);
if(m_hIconChildMaximized == NULL)
{
m_hIconChildMaximized = (HICON) ::GetClassLongPtr(wnd, GCLP_HICON);
}
#else
m_hIconChildMaximized = (HICON)LongToHandle(::GetClassLongPtr(wnd, GCLP_HICONSM));
if(m_hIconChildMaximized == NULL)
{
m_hIconChildMaximized = (HICON) LongToHandle(::GetClassLongPtr(wnd, GCLP_HICON));
}
#endif
}
}
T* pT = static_cast<T*>(this);
pT->RefreshMaximizedState((bMaxOld != m_bChildMaximized), (hIconOld != m_hIconChildMaximized));
bHandled = FALSE;
return 0;
}
LRESULT OnChildUnMaximized(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
HWND hWndChild = (HWND)wParam;
if(m_hWndChildMaximized == hWndChild)
{
bool bMaxOld = m_bChildMaximized;
HICON hIconOld = m_hIconChildMaximized;
m_bChildMaximized = false;
m_hWndChildMaximized = NULL;
m_hIconChildMaximized = NULL;
T* pT = static_cast<T*>(this);
pT->RefreshMaximizedState((bMaxOld != m_bChildMaximized), (hIconOld != m_hIconChildMaximized));
}
bHandled = FALSE;
return 0;
}
void RefreshMaximizedState(bool bMaximizeChanged, bool bIconChanged)
{
// NOTE: This code comes out of CMDICommandBarCtrlImpl::OnAllHookMessages.
// If the base implementation changes, reflect those changes here.
if(bMaximizeChanged)
{
#ifdef _CMDBAR_EXTRA_TRACE
ATLTRACE2(atlTraceUI, 0, "MDI CmdBar - All messages hook change: m_bChildMaximized = %s\n", m_bChildMaximized ? "true" : "false");
#endif
// assuming we are in a rebar, change our size to accomodate new state
// we hope that if we are not in a rebar, nCount will be 0
int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L);
int cxDiff = (m_bChildMaximized ? 1 : -1) * (m_cxLeft + m_cxRight);
for(int i = 0; i < nCount; i++)
{
#if (_WIN32_IE >= 0x0500)
REBARBANDINFO rbi = { sizeof(REBARBANDINFO), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_STYLE };
::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
if(rbi.hwndChild == m_hWnd)
{
if((rbi.fStyle & RBBS_USECHEVRON) != 0)
{
rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;
rbi.cxMinChild += cxDiff;
rbi.cxIdeal += cxDiff;
::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);
}
break;
}
#elif (_WIN32_IE >= 0x0400)
REBARBANDINFO rbi = { sizeof(REBARBANDINFO), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE };
::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
if(rbi.hwndChild == m_hWnd)
{
rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;
rbi.cxMinChild += cxDiff;
rbi.cxIdeal += cxDiff;
::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);
break;
}
#else //(_WIN32_IE < 0x0400)
REBARBANDINFO rbi = { sizeof(REBARBANDINFO), RBBIM_CHILD | RBBIM_CHILDSIZE };
::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
if(rbi.hwndChild == m_hWnd)
{
rbi.fMask = RBBIM_CHILDSIZE;
rbi.cxMinChild += cxDiff;
::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPAR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -