📄 mdi.cpp
字号:
wxMenu *popupMenu = wxCurrentPopupMenu;
wxCurrentPopupMenu = NULL;
if (popupMenu->MSWCommand(cmd, id))
return true;
}
bool processed;
if (GetMenuBar() && GetMenuBar()->FindItem(id))
{
processed = ProcessCommand(id);
}
else
{
processed = false;
}
return processed;
}
bool wxMDIChildFrame::HandleMDIActivate(long WXUNUSED(activate),
WXHWND hwndAct,
WXHWND hwndDeact)
{
wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
HMENU menuToSet = 0;
bool activated;
if ( m_hWnd == hwndAct )
{
activated = true;
parent->m_currentChild = this;
HMENU child_menu = (HMENU)GetWinMenu();
if ( child_menu )
{
parent->m_parentFrameActive = false;
menuToSet = child_menu;
}
}
else if ( m_hWnd == hwndDeact )
{
wxASSERT_MSG( parent->m_currentChild == this,
wxT("can't deactivate MDI child which wasn't active!") );
activated = false;
parent->m_currentChild = NULL;
HMENU parent_menu = (HMENU)parent->GetWinMenu();
// activate the the parent menu only when there is no other child
// that has been activated
if ( parent_menu && !hwndAct )
{
parent->m_parentFrameActive = true;
menuToSet = parent_menu;
}
}
else
{
// we have nothing to do with it
return false;
}
if ( menuToSet )
{
MDISetMenu(parent->GetClientWindow(),
menuToSet, GetMDIWindowMenu(parent));
}
wxActivateEvent event(wxEVT_ACTIVATE, activated, m_windowId);
event.SetEventObject( this );
ResetWindowStyle((void *)NULL);
return GetEventHandler()->ProcessEvent(event);
}
bool wxMDIChildFrame::HandleWindowPosChanging(void *pos)
{
WINDOWPOS *lpPos = (WINDOWPOS *)pos;
#if defined(__WIN95__)
if (!(lpPos->flags & SWP_NOSIZE))
{
RECT rectClient;
DWORD dwExStyle = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE);
DWORD dwStyle = ::GetWindowLong(GetHwnd(), GWL_STYLE);
if (ResetWindowStyle((void *) & rectClient) && (dwStyle & WS_MAXIMIZE))
{
::AdjustWindowRectEx(&rectClient, dwStyle, false, dwExStyle);
lpPos->x = rectClient.left;
lpPos->y = rectClient.top;
lpPos->cx = rectClient.right - rectClient.left;
lpPos->cy = rectClient.bottom - rectClient.top;
}
#if wxUSE_TOOLBAR
wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
if (pFrameWnd && pFrameWnd->GetToolBar() && pFrameWnd->GetToolBar()->IsShown())
{
pFrameWnd->GetToolBar()->Refresh();
}
#endif
}
#endif // Win95
return false;
}
bool wxMDIChildFrame::HandleGetMinMaxInfo(void *mmInfo)
{
MINMAXINFO *info = (MINMAXINFO *)mmInfo;
// let the default window proc calculate the size of MDI children
// frames because it is based on the size of the MDI client window,
// not on the values specified in wxWindow m_max variables
bool processed = MSWDefWindowProc(WM_GETMINMAXINFO, 0, (LPARAM)mmInfo) != 0;
int minWidth = GetMinWidth(),
minHeight = GetMinHeight();
// but allow GetSizeHints() to set the min size
if ( minWidth != -1 )
{
info->ptMinTrackSize.x = minWidth;
processed = true;
}
if ( minHeight != -1 )
{
info->ptMinTrackSize.y = minHeight;
processed = true;
}
return processed;
}
// ---------------------------------------------------------------------------
// MDI specific message translation/preprocessing
// ---------------------------------------------------------------------------
WXLRESULT wxMDIChildFrame::MSWDefWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
{
return DefMDIChildProc(GetHwnd(),
(UINT)message, (WPARAM)wParam, (LPARAM)lParam);
}
bool wxMDIChildFrame::MSWTranslateMessage(WXMSG* pMsg)
{
// NB: this duplicates the code in wxFrame::MSWTranslateMessage() to avoid
// breaking backwards compatibility; cvs HEAD has a better version of
// this fix
if ( wxWindow::MSWTranslateMessage(pMsg) )
return true;
#if wxUSE_MENUS && wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
// try the menu bar accels
wxMenuBar *menuBar = GetMenuBar();
if ( menuBar )
{
const wxAcceleratorTable& acceleratorTable = menuBar->GetAccelTable();
// the difference with wxFrame version is that we must pass the top
// level frame to Translate() here, not "this" pointer
return acceleratorTable.Translate(GetParent(), pMsg);
}
#endif // wxUSE_MENUS && wxUSE_ACCEL
return false;
}
// ---------------------------------------------------------------------------
// misc
// ---------------------------------------------------------------------------
void wxMDIChildFrame::MSWDestroyWindow()
{
invalidHandle = GetHwnd();
wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
// Must make sure this handle is invalidated (set to NULL) since all sorts
// of things could happen after the child client is destroyed, but before
// the wxFrame is destroyed.
HWND oldHandle = (HWND)GetHWND();
SendMessage(GetWinHwnd(parent->GetClientWindow()), WM_MDIDESTROY,
(WPARAM)oldHandle, 0);
if (parent->GetActiveChild() == (wxMDIChildFrame*) NULL)
ResetWindowStyle((void*) NULL);
invalidHandle = 0;
if (m_hMenu)
{
::DestroyMenu((HMENU) m_hMenu);
m_hMenu = 0;
}
wxRemoveHandleAssociation(this);
m_hWnd = 0;
}
// Change the client window's extended style so we don't get a client edge
// style when a child is maximised (a double border looks silly.)
bool wxMDIChildFrame::ResetWindowStyle(void *vrect)
{
#if defined(__WIN95__)
RECT *rect = (RECT *)vrect;
wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild();
if (!pChild || (pChild == this))
{
HWND hwndClient = GetWinHwnd(pFrameWnd->GetClientWindow());
DWORD dwStyle = ::GetWindowLong(hwndClient, GWL_EXSTYLE);
// we want to test whether there is a maximized child, so just set
// dwThisStyle to 0 if there is no child at all
DWORD dwThisStyle = pChild
? ::GetWindowLong(GetWinHwnd(pChild), GWL_STYLE) : 0;
DWORD dwNewStyle = dwStyle;
if ( dwThisStyle & WS_MAXIMIZE )
dwNewStyle &= ~(WS_EX_CLIENTEDGE);
else
dwNewStyle |= WS_EX_CLIENTEDGE;
if (dwStyle != dwNewStyle)
{
// force update of everything
::RedrawWindow(hwndClient, NULL, NULL,
RDW_INVALIDATE | RDW_ALLCHILDREN);
::SetWindowLong(hwndClient, GWL_EXSTYLE, dwNewStyle);
::SetWindowPos(hwndClient, NULL, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOACTIVATE |
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
SWP_NOCOPYBITS);
if (rect)
::GetClientRect(hwndClient, rect);
return true;
}
}
#endif // Win95
return false;
}
// ===========================================================================
// wxMDIClientWindow: the window of predefined (by Windows) class which
// contains the child frames
// ===========================================================================
bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
{
m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
CLIENTCREATESTRUCT ccs;
m_windowStyle = style;
m_parent = parent;
ccs.hWindowMenu = GetMDIWindowMenu(parent);
ccs.idFirstChild = wxFIRST_MDI_CHILD;
DWORD msStyle = MDIS_ALLCHILDSTYLES | WS_VISIBLE | WS_CHILD |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
if ( style & wxHSCROLL )
msStyle |= WS_HSCROLL;
if ( style & wxVSCROLL )
msStyle |= WS_VSCROLL;
#if defined(__WIN95__)
DWORD exStyle = WS_EX_CLIENTEDGE;
#else
DWORD exStyle = 0;
#endif
wxWindowCreationHook hook(this);
m_hWnd = (WXHWND)::CreateWindowEx
(
exStyle,
wxT("MDICLIENT"),
NULL,
msStyle,
0, 0, 0, 0,
GetWinHwnd(parent),
NULL,
wxGetInstance(),
(LPSTR)(LPCLIENTCREATESTRUCT)&ccs);
if ( !m_hWnd )
{
wxLogLastError(wxT("CreateWindowEx(MDI client)"));
return false;
}
SubclassWin(m_hWnd);
return true;
}
// Explicitly call default scroll behaviour
void wxMDIClientWindow::OnScroll(wxScrollEvent& event)
{
// Note: for client windows, the scroll position is not set in
// WM_HSCROLL, WM_VSCROLL, so we can't easily determine what
// scroll position we're at.
// This makes it hard to paint patterns or bitmaps in the background,
// and have the client area scrollable as well.
if ( event.GetOrientation() == wxHORIZONTAL )
m_scrollX = event.GetPosition(); // Always returns zero!
else
m_scrollY = event.GetPosition(); // Always returns zero!
event.Skip();
}
void wxMDIClientWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags)
{
// Try to fix a problem whereby if you show an MDI child frame, then reposition the
// client area, you can end up with a non-refreshed portion in the client window
// (see OGL studio sample). So check if the position is changed and if so,
// redraw the MDI child frames.
const wxPoint oldPos = GetPosition();
wxWindow::DoSetSize(x, y, width, height, sizeFlags | wxSIZE_FORCE);
const wxPoint newPos = GetPosition();
if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y))
{
if (GetParent())
{
wxWindowList::compatibility_iterator node = GetParent()->GetChildren().GetFirst();
while (node)
{
wxWindow *child = node->GetData();
if (child->IsKindOf(CLASSINFO(wxMDIChildFrame)))
{
::RedrawWindow(GetHwndOf(child),
NULL,
NULL,
RDW_FRAME |
RDW_ALLCHILDREN |
RDW_INVALIDATE);
}
node = node->GetNext();
}
}
}
}
void wxMDIChildFrame::OnIdle(wxIdleEvent& event)
{
// wxMSW prior to 2.5.3 created MDI child frames as visible, which resulted
// in flicker e.g. when the frame contained controls with non-trivial
// layout. Since 2.5.3, the frame is created hidden as all other top level
// windows. In order to maintain backward compatibility, the frame is shown
// in OnIdle, unless Show(false) was called by the programmer before.
if ( m_needsInitialShow )
{
Show(true);
}
// MDI child frames get their WM_SIZE when they're constructed but at this
// moment they don't have any children yet so all child windows will be
// positioned incorrectly when they are added later - to fix this, we
// generate an artificial size event here
if ( m_needsResize )
{
m_needsResize = false; // avoid any possibility of recursion
SendSizeEvent();
}
event.Skip();
}
// ---------------------------------------------------------------------------
// non member functions
// ---------------------------------------------------------------------------
static void MDISetMenu(wxWindow *win, HMENU hmenuFrame, HMENU hmenuWindow)
{
::SendMessage(GetWinHwnd(win), WM_MDISETMENU,
#ifdef __WIN32__
(WPARAM)hmenuFrame, (LPARAM)hmenuWindow
#else
0, MAKELPARAM(hmenuFrame, hmenuWindow)
#endif
);
// update menu bar of the parent window
wxWindow *parent = win->GetParent();
wxCHECK_RET( parent, wxT("MDI client without parent frame? weird...") );
::SendMessage(GetWinHwnd(win), WM_MDIREFRESHMENU, 0, 0L);
::DrawMenuBar(GetWinHwnd(parent));
}
static void InsertWindowMenu(wxWindow *win, WXHMENU menu, HMENU subMenu)
{
// Try to insert Window menu in front of Help, otherwise append it.
HMENU hmenu = (HMENU)menu;
if (subMenu)
{
int N = GetMenuItemCount(hmenu);
bool success = false;
for ( int i = 0; i < N; i++ )
{
wxChar buf[256];
int chars = GetMenuString(hmenu, i, buf, WXSIZEOF(buf), MF_BYPOSITION);
if ( chars == 0 )
{
wxLogLastError(wxT("GetMenuString"));
continue;
}
wxString strBuf(buf);
if ( wxStripMenuCodes(strBuf) == wxGetStockLabel(wxID_HELP,false) )
{
success = true;
::InsertMenu(hmenu, i, MF_BYPOSITION | MF_POPUP | MF_STRING,
(UINT)subMenu, _("&Window"));
break;
}
}
if ( !success )
{
::AppendMenu(hmenu, MF_POPUP, (UINT)subMenu, _("&Window"));
}
}
MDISetMenu(win, hmenu, subMenu);
}
static void RemoveWindowMenu(wxWindow *win, WXHMENU menu)
{
HMENU hMenu = (HMENU)menu;
if ( hMenu )
{
wxChar buf[1024];
int N = ::GetMenuItemCount(hMenu);
for ( int i = 0; i < N; i++ )
{
if ( !::GetMenuString(hMenu, i, buf, WXSIZEOF(buf), MF_BYPOSITION) )
{
// Ignore successful read of menu string with length 0 which
// occurs, for example, for a maximized MDI childs system menu
if ( ::GetLastError() != 0 )
{
wxLogLastError(wxT("GetMenuString"));
}
continue;
}
if ( wxStrcmp(buf, _("&Window")) == 0 )
{
if ( !::RemoveMenu(hMenu, i, MF_BYPOSITION) )
{
wxLogLastError(wxT("RemoveMenu"));
}
break;
}
}
}
if ( win )
{
// we don't change the windows menu, but we update the main one
MDISetMenu(win, hMenu, NULL);
}
}
static void UnpackMDIActivate(WXWPARAM wParam, WXLPARAM lParam,
WXWORD *activate, WXHWND *hwndAct, WXHWND *hwndDeact)
{
*activate = true;
*hwndAct = (WXHWND)lParam;
*hwndDeact = (WXHWND)wParam;
}
#endif // wxUSE_MDI && !defined(__WXUNIVERSAL__)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -