📄 mdi.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Name: src/msw/mdi.cpp
// Purpose: MDI classes for wxMSW
// Author: Julian Smart
// Modified by:
// Created: 04/01/98
// RCS-ID: $Id: mdi.cpp,v 1.125.2.3 2006/01/23 20:10:29 RD Exp $
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ===========================================================================
// declarations
// ===========================================================================
// ---------------------------------------------------------------------------
// headers
// ---------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "mdi.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_MDI && !defined(__WXUNIVERSAL__)
#ifndef WX_PRECOMP
#include "wx/setup.h"
#include "wx/frame.h"
#include "wx/menu.h"
#include "wx/app.h"
#include "wx/utils.h"
#include "wx/dialog.h"
#if wxUSE_STATUSBAR
#include "wx/statusbr.h"
#endif
#include "wx/settings.h"
#include "wx/intl.h"
#include "wx/log.h"
#endif
#include "wx/stockitem.h"
#include "wx/mdi.h"
#include "wx/msw/private.h"
#if wxUSE_STATUSBAR && wxUSE_NATIVE_STATUSBAR
#include "wx/msw/statbr95.h"
#endif
#if wxUSE_TOOLBAR
#include "wx/toolbar.h"
#endif // wxUSE_TOOLBAR
#include <string.h>
// ---------------------------------------------------------------------------
// global variables
// ---------------------------------------------------------------------------
extern wxMenu *wxCurrentPopupMenu;
extern const wxChar *wxMDIFrameClassName; // from app.cpp
extern const wxChar *wxMDIChildFrameClassName;
extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
extern void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win);
extern void wxRemoveHandleAssociation(wxWindow *win);
static HWND invalidHandle = 0;
// ---------------------------------------------------------------------------
// constants
// ---------------------------------------------------------------------------
static const int IDM_WINDOWTILEHOR = 4001;
static const int IDM_WINDOWCASCADE = 4002;
static const int IDM_WINDOWICONS = 4003;
static const int IDM_WINDOWNEXT = 4004;
static const int IDM_WINDOWTILEVERT = 4005;
static const int IDM_WINDOWPREV = 4006;
// This range gives a maximum of 500 MDI children. Should be enough :-)
static const int wxFIRST_MDI_CHILD = 4100;
static const int wxLAST_MDI_CHILD = 4600;
// ---------------------------------------------------------------------------
// private functions
// ---------------------------------------------------------------------------
// set the MDI menus (by sending the WM_MDISETMENU message) and update the menu
// of the parent of win (which is supposed to be the MDI client window)
static void MDISetMenu(wxWindow *win, HMENU hmenuFrame, HMENU hmenuWindow);
// insert the window menu (subMenu) into menu just before "Help" submenu or at
// the very end if not found
static void InsertWindowMenu(wxWindow *win, WXHMENU menu, HMENU subMenu);
// Remove the window menu
static void RemoveWindowMenu(wxWindow *win, WXHMENU menu);
// is this an id of an MDI child?
inline bool IsMdiCommandId(int id)
{
return (id >= wxFIRST_MDI_CHILD) && (id <= wxLAST_MDI_CHILD);
}
// unpack the parameters of WM_MDIACTIVATE message
static void UnpackMDIActivate(WXWPARAM wParam, WXLPARAM lParam,
WXWORD *activate, WXHWND *hwndAct, WXHWND *hwndDeact);
// return the HMENU of the MDI menu
static inline HMENU GetMDIWindowMenu(wxMDIParentFrame *frame)
{
wxMenu *menu = frame->GetWindowMenu();
return menu ? GetHmenuOf(menu) : 0;
}
// ===========================================================================
// implementation
// ===========================================================================
// ---------------------------------------------------------------------------
// wxWin macros
// ---------------------------------------------------------------------------
IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame)
IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame)
IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
EVT_SIZE(wxMDIParentFrame::OnSize)
EVT_ICONIZE(wxMDIParentFrame::OnIconized)
EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
EVT_IDLE(wxMDIChildFrame::OnIdle)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(wxMDIClientWindow, wxWindow)
EVT_SCROLL(wxMDIClientWindow::OnScroll)
END_EVENT_TABLE()
// ===========================================================================
// wxMDIParentFrame: the frame which contains the client window which manages
// the children
// ===========================================================================
wxMDIParentFrame::wxMDIParentFrame()
{
m_clientWindow = NULL;
m_currentChild = NULL;
m_windowMenu = (wxMenu*) NULL;
m_parentFrameActive = true;
}
bool wxMDIParentFrame::Create(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
m_clientWindow = NULL;
m_currentChild = NULL;
// this style can be used to prevent a window from having the standard MDI
// "Window" menu
if ( style & wxFRAME_NO_WINDOW_MENU )
{
m_windowMenu = (wxMenu *)NULL;
}
else // normal case: we have the window menu, so construct it
{
m_windowMenu = new wxMenu;
m_windowMenu->Append(IDM_WINDOWCASCADE, _("&Cascade"));
m_windowMenu->Append(IDM_WINDOWTILEHOR, _("Tile &Horizontally"));
m_windowMenu->Append(IDM_WINDOWTILEVERT, _("Tile &Vertically"));
m_windowMenu->AppendSeparator();
m_windowMenu->Append(IDM_WINDOWICONS, _("&Arrange Icons"));
m_windowMenu->Append(IDM_WINDOWNEXT, _("&Next"));
m_windowMenu->Append(IDM_WINDOWPREV, _("&Previous"));
}
m_parentFrameActive = true;
if (!parent)
wxTopLevelWindows.Append(this);
SetName(name);
m_windowStyle = style;
if ( parent )
parent->AddChild(this);
if ( id != wxID_ANY )
m_windowId = id;
else
m_windowId = NewControlId();
WXDWORD exflags;
WXDWORD msflags = MSWGetCreateWindowFlags(&exflags);
msflags &= ~WS_VSCROLL;
msflags &= ~WS_HSCROLL;
if ( !wxWindow::MSWCreate(wxMDIFrameClassName,
title,
pos, size,
msflags,
exflags) )
{
return false;
}
// unlike (almost?) all other windows, frames are created hidden
m_isShown = false;
return true;
}
wxMDIParentFrame::~wxMDIParentFrame()
{
// see comment in ~wxMDIChildFrame
#if wxUSE_TOOLBAR
m_frameToolBar = NULL;
#endif
#if wxUSE_STATUSBAR
m_frameStatusBar = NULL;
#endif // wxUSE_STATUSBAR
DestroyChildren();
if (m_windowMenu)
{
delete m_windowMenu;
m_windowMenu = (wxMenu*) NULL;
}
// the MDI frame menubar is not automatically deleted by Windows unlike for
// the normal frames
if ( m_hMenu )
{
::DestroyMenu((HMENU)m_hMenu);
m_hMenu = (WXHMENU)NULL;
}
if ( m_clientWindow )
{
if ( m_clientWindow->MSWGetOldWndProc() )
m_clientWindow->UnsubclassWin();
m_clientWindow->SetHWND(0);
delete m_clientWindow;
}
}
#if wxUSE_MENUS_NATIVE
void wxMDIParentFrame::InternalSetMenuBar()
{
m_parentFrameActive = true;
InsertWindowMenu(GetClientWindow(), m_hMenu, GetMDIWindowMenu(this));
}
#endif // wxUSE_MENUS_NATIVE
void wxMDIParentFrame::SetWindowMenu(wxMenu* menu)
{
if (m_windowMenu)
{
if (GetMenuBar())
{
// Remove old window menu
RemoveWindowMenu(GetClientWindow(), m_hMenu);
}
delete m_windowMenu;
m_windowMenu = (wxMenu*) NULL;
}
if (menu)
{
m_windowMenu = menu;
if (GetMenuBar())
{
InsertWindowMenu(GetClientWindow(), m_hMenu,
GetHmenuOf(m_windowMenu));
}
}
}
void wxMDIParentFrame::DoMenuUpdates(wxMenu* menu)
{
wxMDIChildFrame *child = GetActiveChild();
if ( child )
{
wxEvtHandler* source = child->GetEventHandler();
wxMenuBar* bar = child->GetMenuBar();
if (menu)
{
menu->UpdateUI(source);
}
else
{
if ( bar != NULL )
{
int nCount = bar->GetMenuCount();
for (int n = 0; n < nCount; n++)
bar->GetMenu(n)->UpdateUI(source);
}
}
}
else
{
wxFrameBase::DoMenuUpdates(menu);
}
}
void wxMDIParentFrame::UpdateClientSize()
{
if ( GetClientWindow() )
{
int width, height;
GetClientSize(&width, &height);
GetClientWindow()->SetSize(0, 0, width, height);
}
}
void wxMDIParentFrame::OnSize(wxSizeEvent& WXUNUSED(event))
{
UpdateClientSize();
// do not call event.Skip() here, it somehow messes up MDI client window
}
void wxMDIParentFrame::OnIconized(wxIconizeEvent& event)
{
event.Skip();
if ( !event.Iconized() )
{
UpdateClientSize();
}
}
// Returns the active MDI child window
wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
{
HWND hWnd = (HWND)::SendMessage(GetWinHwnd(GetClientWindow()),
WM_MDIGETACTIVE, 0, 0L);
if ( hWnd == 0 )
return NULL;
else
return (wxMDIChildFrame *)wxFindWinFromHandle((WXHWND) hWnd);
}
// Create the client window class (don't Create the window, just return a new
// class)
wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
{
return new wxMDIClientWindow;
}
// Responds to colour changes, and passes event on to children.
void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
{
if ( m_clientWindow )
{
m_clientWindow->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
m_clientWindow->Refresh();
}
event.Skip();
}
WXHICON wxMDIParentFrame::GetDefaultIcon() const
{
// we don't have any standard icons (any more)
return (WXHICON)0;
}
// ---------------------------------------------------------------------------
// MDI operations
// ---------------------------------------------------------------------------
void wxMDIParentFrame::Cascade()
{
::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDICASCADE, 0, 0);
}
void wxMDIParentFrame::Tile(wxOrientation orient)
{
wxASSERT_MSG( orient == wxHORIZONTAL || orient == wxVERTICAL,
_T("invalid orientation value") );
::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDITILE,
orient == wxHORIZONTAL ? MDITILE_HORIZONTAL
: MDITILE_VERTICAL, 0);
}
void wxMDIParentFrame::ArrangeIcons()
{
::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDIICONARRANGE, 0, 0);
}
void wxMDIParentFrame::ActivateNext()
{
::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT, 0, 0);
}
void wxMDIParentFrame::ActivatePrevious()
{
::SendMessage(GetWinHwnd(GetClientWindow()), WM_MDINEXT, 0, 1);
}
// ---------------------------------------------------------------------------
// the MDI parent frame window proc
// ---------------------------------------------------------------------------
WXLRESULT wxMDIParentFrame::MSWWindowProc(WXUINT message,
WXWPARAM wParam,
WXLPARAM lParam)
{
WXLRESULT rc = 0;
bool processed = false;
switch ( message )
{
case WM_ACTIVATE:
{
WXWORD state, minimized;
WXHWND hwnd;
UnpackActivate(wParam, lParam, &state, &minimized, &hwnd);
processed = HandleActivate(state, minimized != 0, hwnd);
}
break;
case WM_COMMAND:
{
WXWORD id, cmd;
WXHWND hwnd;
UnpackCommand(wParam, lParam, &id, &hwnd, &cmd);
(void)HandleCommand(id, cmd, hwnd);
// even if the frame didn't process it, there is no need to try it
// once again (i.e. call wxFrame::HandleCommand()) - we just did it,
// so pretend we processed the message anyhow
processed = true;
}
// always pass this message DefFrameProc(), otherwise MDI menu
// commands (and sys commands - more surprisingly!) won't work
MSWDefWindowProc(message, wParam, lParam);
break;
case WM_CREATE:
m_clientWindow = OnCreateClient();
// Uses own style for client style
if ( !m_clientWindow->CreateClient(this, GetWindowStyleFlag()) )
{
wxLogMessage(_("Failed to create MDI parent frame."));
rc = -1;
}
processed = true;
break;
case WM_ERASEBKGND:
processed = true;
// we erase background ourselves
rc = true;
break;
case WM_MENUSELECT:
{
WXWORD item, flags;
WXHMENU hmenu;
UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu);
if ( m_parentFrameActive )
{
processed = HandleMenuSelect(item, flags, hmenu);
}
else if (m_currentChild)
{
processed = m_currentChild->
HandleMenuSelect(item, flags, hmenu);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -