📄 winmdi.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// CMDIFrameWnd Diagnostics
#ifdef _DEBUG
void CMDIFrameWnd::AssertValid() const
{
CFrameWnd::AssertValid();
ASSERT(m_hWndMDIClient == NULL || ::IsWindow(m_hWndMDIClient));
ASSERT(m_hMenuDefault == NULL || ::IsMenu(m_hMenuDefault));
}
void CMDIFrameWnd::Dump(CDumpContext& dc) const
{
CFrameWnd::Dump(dc);
dc << "m_hWndMDIClient = " << (UINT)m_hWndMDIClient;
dc << "\nm_hMenuDefault = " << (UINT)m_hMenuDefault;
dc << "\n";
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CMDIChildWnd
BEGIN_MESSAGE_MAP(CMDIChildWnd, CFrameWnd)
//{{AFX_MSG_MAP(CMDIChildWnd)
ON_WM_MOUSEACTIVATE()
ON_WM_NCACTIVATE()
ON_WM_MDIACTIVATE()
ON_WM_SIZE()
ON_WM_WINDOWPOSCHANGING()
ON_WM_NCCREATE()
ON_WM_CREATE()
ON_WM_DESTROY()
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
CMDIChildWnd::CMDIChildWnd()
{
m_hMenuShared = NULL;
m_bPseudoInactive = FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CMDIChildWnd special processing
LRESULT CMDIChildWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
return ::DefMDIChildProc(m_hWnd, nMsg, wParam, lParam);
}
BOOL CMDIChildWnd::DestroyWindow()
{
if (m_hWnd == NULL)
return FALSE;
// avoid changing the caption during the destroy message(s)
CMDIFrameWnd* pFrameWnd = GetMDIFrame();
HWND hWndFrame = pFrameWnd->m_hWnd;
ASSERT(::IsWindow(hWndFrame));
DWORD dwStyle = SetWindowLong(hWndFrame, GWL_STYLE,
GetWindowLong(hWndFrame, GWL_STYLE) & ~FWS_ADDTOTITLE);
MDIDestroy();
if (::IsWindow(hWndFrame))
{
ASSERT(hWndFrame == pFrameWnd->m_hWnd);
SetWindowLong(hWndFrame, GWL_STYLE, dwStyle);
pFrameWnd->OnUpdateFrameTitle(TRUE);
}
return TRUE;
}
BOOL CMDIChildWnd::PreTranslateMessage(MSG* pMsg)
{
// check for special cancel modes for combo boxes
if (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN)
AfxCancelModes(pMsg->hwnd); // filter clicks
// allow tooltip messages to be filtered
if (CWnd::PreTranslateMessage(pMsg))
return TRUE;
// we can't call 'CFrameWnd::PreTranslate' since it will translate
// accelerators in the context of the MDI Child - but since MDI Child
// windows don't have menus this doesn't work properly. MDI Child
// accelerators must be translated in context of their MDI Frame.
if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
{
// use document specific accelerator table over m_hAccelTable
HACCEL hAccel = GetDefaultAccelerator();
return hAccel != NULL &&
::TranslateAccelerator(GetMDIFrame()->m_hWnd, hAccel, pMsg);
}
return FALSE;
}
BOOL CMDIChildWnd::PreCreateWindow(CREATESTRUCT& cs)
{
ASSERT(cs.style & WS_CHILD);
// MFC V2 requires that MDI Children are created with proper styles,
// usually: WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW.
// See Technical note TN019 for more details on MFC V1->V2 migration.
return CFrameWnd::PreCreateWindow(cs);
}
BOOL CMDIChildWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect, CMDIFrameWnd* pParentWnd,
CCreateContext* pContext)
{
if (pParentWnd == NULL)
{
CWnd* pMainWnd = AfxGetThread()->m_pMainWnd;
ASSERT(pMainWnd != NULL);
ASSERT_KINDOF(CMDIFrameWnd, pMainWnd);
pParentWnd = (CMDIFrameWnd*)pMainWnd;
}
ASSERT(::IsWindow(pParentWnd->m_hWndMDIClient));
// insure correct window positioning
pParentWnd->RecalcLayout();
// first copy into a CREATESTRUCT for PreCreate
CREATESTRUCT cs;
cs.dwExStyle = 0L;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.x = rect.left;
cs.y = rect.top;
cs.cx = rect.right - rect.left;
cs.cy = rect.bottom - rect.top;
cs.hwndParent = pParentWnd->m_hWnd;
cs.hMenu = NULL;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = (LPVOID)pContext;
if (!PreCreateWindow(cs))
{
PostNcDestroy();
return FALSE;
}
// extended style must be zero for MDI Children (except under Win4)
ASSERT(afxData.bWin4 || cs.dwExStyle == 0);
ASSERT(cs.hwndParent == pParentWnd->m_hWnd); // must not change
// now copy into a MDICREATESTRUCT for real create
MDICREATESTRUCT mcs;
mcs.szClass = cs.lpszClass;
mcs.szTitle = cs.lpszName;
mcs.hOwner = cs.hInstance;
mcs.x = cs.x;
mcs.y = cs.y;
mcs.cx = cs.cx;
mcs.cy = cs.cy;
mcs.style = cs.style & ~(WS_MAXIMIZE | WS_VISIBLE);
mcs.lParam = (LONG)cs.lpCreateParams;
// create the window through the MDICLIENT window
AfxHookWindowCreate(this);
HWND hWnd = (HWND)::SendMessage(pParentWnd->m_hWndMDIClient,
WM_MDICREATE, 0, (LPARAM)&mcs);
if (!AfxUnhookWindowCreate())
PostNcDestroy(); // cleanup if MDICREATE fails too soon
if (hWnd == NULL)
return FALSE;
// special handling of visibility (always created invisible)
if (cs.style & WS_VISIBLE)
{
// place the window on top in z-order before showing it
::BringWindowToTop(hWnd);
// show it as specified
if (cs.style & WS_MINIMIZE)
ShowWindow(SW_SHOWMINIMIZED);
else if (cs.style & WS_MAXIMIZE)
ShowWindow(SW_SHOWMAXIMIZED);
else
ShowWindow(SW_SHOWNORMAL);
// make sure it is active (visibility == activation)
pParentWnd->MDIActivate(this);
// refresh MDI Window menu
::SendMessage(pParentWnd->m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
}
ASSERT(hWnd == m_hWnd);
return TRUE;
}
BOOL CMDIChildWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
CWnd* pParentWnd, CCreateContext* pContext)
{
// only do this once
ASSERT_VALID_IDR(nIDResource);
ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);
ASSERT(m_hMenuShared == NULL); // only do once
m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)
// parent must be MDI Frame (or NULL for default)
ASSERT(pParentWnd == NULL || pParentWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)));
// will be a child of MDIClient
ASSERT(!(dwDefaultStyle & WS_POPUP));
dwDefaultStyle |= WS_CHILD;
// if available - get MDI child menus from doc template
ASSERT(m_hMenuShared == NULL); // only do once
CMultiDocTemplate* pTemplate;
if (pContext != NULL &&
(pTemplate = (CMultiDocTemplate*)pContext->m_pNewDocTemplate) != NULL)
{
ASSERT_KINDOF(CMultiDocTemplate, pTemplate);
// get shared menu from doc template
m_hMenuShared = pTemplate->m_hMenuShared;
m_hAccelTable = pTemplate->m_hAccelTable;
}
else
{
TRACE0("Warning: no shared menu/acceltable for MDI Child window.\n");
// if this happens, programmer must load these manually
}
CString strFullString, strTitle;
if (strFullString.LoadString(nIDResource))
AfxExtractSubString(strTitle, strFullString, 0); // first sub-string
ASSERT(m_hWnd == NULL);
if (!Create(GetIconWndClass(dwDefaultStyle, nIDResource),
strTitle, dwDefaultStyle, rectDefault,
(CMDIFrameWnd*)pParentWnd, pContext))
{
return FALSE; // will self destruct on failure normally
}
// it worked !
return TRUE;
}
void CMDIChildWnd::OnSize(UINT nType, int cx, int cy)
{
CFrameWnd::OnSize(nType, cx, cy);
// update our parent frame - in case we are now maximized or not
GetMDIFrame()->OnUpdateFrameTitle(TRUE);
}
BOOL CMDIChildWnd::UpdateClientEdge(LPRECT lpRect)
{
if (!afxData.bWin4)
return FALSE;
// only adjust for active MDI child window
CMDIFrameWnd* pFrameWnd = GetMDIFrame();
CMDIChildWnd* pChild = pFrameWnd->MDIGetActive();
if (pChild == NULL || pChild == this)
{
// need to adjust the client edge style as max/restore happens
DWORD dwStyle = ::GetWindowLong(pFrameWnd->m_hWndMDIClient, GWL_EXSTYLE);
DWORD dwNewStyle = dwStyle;
if (pChild != NULL && !(GetExStyle() & WS_EX_CLIENTEDGE) &&
(GetStyle() & WS_MAXIMIZE))
dwNewStyle &= ~(WS_EX_CLIENTEDGE);
else
dwNewStyle |= WS_EX_CLIENTEDGE;
if (dwStyle != dwNewStyle)
{
// SetWindowPos will not move invalid bits
::RedrawWindow(pFrameWnd->m_hWndMDIClient, NULL, NULL,
RDW_INVALIDATE | RDW_ALLCHILDREN);
// remove/add WS_EX_CLIENTEDGE to MDI client area
::SetWindowLong(pFrameWnd->m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle);
::SetWindowPos(pFrameWnd->m_hWndMDIClient, NULL, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE |
SWP_NOZORDER | SWP_NOCOPYBITS);
// return new client area
if (lpRect != NULL)
::GetClientRect(pFrameWnd->m_hWndMDIClient, lpRect);
return TRUE;
}
}
return FALSE;
}
void CMDIChildWnd::OnWindowPosChanging(LPWINDOWPOS lpWndPos)
{
if (afxData.bWin4 && !(lpWndPos->flags & SWP_NOSIZE))
{
CRect rectClient;
if (UpdateClientEdge(rectClient) && (GetStyle() & WS_MAXIMIZE))
{
// adjust maximized window size and position based on new
// size/position of the MDI client area.
::AdjustWindowRectEx(rectClient, GetStyle(), FALSE, GetExStyle());
lpWndPos->x = rectClient.left;
lpWndPos->y = rectClient.top;
lpWndPos->cx = rectClient.Width();
lpWndPos->cy = rectClient.Height();
}
}
CFrameWnd::OnWindowPosChanging(lpWndPos);
}
void CMDIChildWnd::OnDestroy()
{
UpdateClientEdge();
CFrameWnd::OnDestroy();
}
BOOL CMDIChildWnd::OnNcActivate(BOOL bActive)
{
// bypass CFrameWnd::OnNcActivate()
return CWnd::OnNcActivate(bActive);
}
int CMDIChildWnd::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
{
int nResult = CFrameWnd::OnMouseActivate(pDesktopWnd, nHitTest, message);
if (nResult == MA_NOACTIVATE || nResult == MA_NOACTIVATEANDEAT)
return nResult; // frame does not want to activate
// activate this window if necessary
CMDIFrameWnd* pFrameWnd = GetMDIFrame();
ASSERT_VALID(pFrameWnd);
CMDIChildWnd* pActive = pFrameWnd->MDIGetActive();
if (pActive != this)
MDIActivate();
return nResult;
}
BOOL CMDIChildWnd::OnToolTipText(UINT msg, NMHDR* pNMHDR, LRESULT* pResult)
{
ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);
UNUSED(pNMHDR);
// check to see if the message is going directly to this window or not
const MSG* pMsg = GetCurrentMessage();
if (pMsg->hwnd != m_hWnd)
{
// let top level frame handle this for us
return FALSE;
}
// otherwise, handle it ourselves
return CFrameWnd::OnToolTipText(msg, pNMHDR, pResult);
}
void CMDIChildWnd::ActivateFrame(int nCmdShow)
{
BOOL bVisibleThen = (GetStyle() & WS_VISIBLE) != 0;
CMDIFrameWnd* pFrameWnd = GetMDIFrame();
ASSERT_VALID(pFrameWnd);
// determine default show command
if (nCmdShow == -1)
{
// get maximized state of frame window (previously active child)
BOOL bMaximized;
pFrameWnd->MDIGetActive(&bMaximized);
// convert show command based on current style
DWORD dwStyle = GetStyle();
if (bMaximized || (dwStyle & WS_MAXIMIZE))
nCmdShow = SW_SHOWMAXIMIZED;
else if (dwStyle & WS_MINIMIZE)
nCmdShow = SW_SHOWMINIMIZED;
}
// finally, show the window
CFrameWnd::ActivateFrame(nCmdShow);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -