Сделайте мне красиво – Часть II – wxAUI в Multi-View приложений

Использование возможностей библиотеки wxAUI для создания Multi-View приложений

Ну вот, «Ножки дошли до ручки» (c) < один-очень-хороший-человек>, вернее, ручки дошли до новых возможностей библиотеки wxAUI. И, сдается мне, что эти новые возможности будут востребованы в моих последующих проектах, ибо удобство и эстетичность GUI, созданного с их помощью, лично меня приводит в восторг.

Создадим базу для нашего приложения. Разница между приложением, использующим возможности библиотеки wxAUI для создания нескольких представлений (views), заключается лишь в том, что класс главной формы наследуется не от wxFrame, а от wxAuiMDIParentFrame. В этом случае на форме автоматически будет создан wxAuiNotebook, который будет служить контейнером для дочерних окон и доступ к которому можно получить через метод GetNotebook()
Для создания статических окон (которые будут отображаться вне зависимости от активного дочернего окна), будем использовать wxAuiManager, как и в обычном приложении.
Хотелось бы добавить вот что… Пусть вас не смущают названия типа AUIDocView*.h, на самом деле архитектура Document/View в данном примере не используется и на данный момент библиотека wxAUI не предоставляет такой возможности, но… я, в данный момент, серьезно подумываю о ее реализации и, если окажется, что в официальном RoadMap’е wxAUI планов по созданию данного функционала нет, то можно будет попробовать его реализовать вручную, благо там привязка к GUI минимальна.
Итак, начнем:

AUIDocViewMainFrame.h

#ifndef _AUI_DOCVIEW_MAINFRAME_H
#define _AUI_DOCVIEW_MAINFRAME_H

#include 
#include 
#include 
#include 

#define AUIDocViewMainFrameTitle wxT("AUI DocView Test")

enum
{
	ID_LOG_TEXTCTRL = 10001,
	ID_TOGGLE_LOGWINDOW
};

class AUIDocViewMainFrame : public wxAuiMDIParentFrame
{		
	DECLARE_DYNAMIC_CLASS(AUIDocViewMainFrame);
	wxTextCtrl * m_LOGTextCtrl;
	wxAuiManager m_FrameManager;
	void CreateControls();	
	static wxMenuBar * CreateMainMenuBar();
public:
	AUIDocViewMainFrame();
	AUIDocViewMainFrame(wxWindow * parent, wxWindowID id = wxID_ANY, 
		const wxString & title = AUIDocViewMainFrameTitle);
	~AUIDocViewMainFrame();
	bool Create(wxWindow * parent, wxWindowID id = wxID_ANY, 
		const wxString & title = AUIDocViewMainFrameTitle);

	wxTextCtrl * GetLOGTextCtrl();

	bool GetPaneVisibility(wxString pane_name);
	void TogglePaneVisibility(wxString pane_name);

	DECLARE_EVENT_TABLE()
	void OnExit(wxCommandEvent & event);
	void OnAbout(wxCommandEvent & event);
void OnToggleLogWindow(wxCommandEvent & event);	
	void OnToggleLogWindowUpdateUI(wxUpdateUIEvent & event);
};

#endif

AUIDocViewMainFrame.cpp

#include "AUIDocViewMainFrame.h"
#include 

IMPLEMENT_DYNAMIC_CLASS(AUIDocViewMainFrame, wxAuiMDIParentFrame);

BEGIN_EVENT_TABLE(AUIDocViewMainFrame , wxAuiMDIParentFrame)
EVT_MENU(wxID_EXIT, AUIDocViewMainFrame::OnExit)
EVT_MENU(wxID_ABOUT, AUIDocViewMainFrame::OnAbout)
EVT_MENU(ID_TOGGLE_LOGWINDOW, AUIDocViewMainFrame::OnToggleLogWindow)
EVT_UPDATE_UI(ID_TOGGLE_LOGWINDOW, AUIDocViewMainFrame::OnToggleLogWindowUpdateUI)
END_EVENT_TABLE()

AUIDocViewMainFrame::AUIDocViewMainFrame ()
{
}

AUIDocViewMainFrame::AUIDocViewMainFrame (wxWindow * parent, wxWindowID id,const wxString & title)
{
	Create(parent, id, title);
}

AUIDocViewMainFrame::~AUIDocViewMainFrame()
{
	m_FrameManager.UnInit();
}

bool AUIDocViewMainFrame::Create(wxWindow * parent, wxWindowID id,const wxString & title)
{
	bool res = wxAuiMDIParentFrame::Create(parent, id, title, wxDefaultPosition, 
		wxSize(600,500), wxDEFAULT_FRAME_STYLE|wxFRAME_NO_WINDOW_MENU);
	if(res)
	{
		m_HeaderStyle = HS_DEFAULT;
		CreateControls();
	}
	return res;
}

wxMenuBar * AUIDocViewMainFrame::CreateMainMenuBar()
{
	wxMenuBar * menuBar = new wxMenuBar;
	
	wxMenu * fileMenu = new wxMenu;
	fileMenu->Append(wxID_EXIT, _("Exit\tAlt+F4"));
	menuBar->Append(fileMenu, _("File"));

	wxMenu * viewMenu = new wxMenu;	
	viewMenu->AppendCheckItem(ID_TOGGLE_LOGWINDOW, _("Toggle Help Window"));
	menuBar->Append(viewMenu, _("View"));

	wxMenu * helpMenu = new wxMenu;
	helpMenu->Append(wxID_ABOUT, _("About..."));
	menuBar->Append(helpMenu, _("Help"));

	return menuBar;
}

void AUIDocViewMainFrame::CreateControls()
{	
	SetMenuBar(AUIDocViewMainFrame::CreateMainMenuBar());
	CreateStatusBar(2);
	m_LOGTextCtrl = new wxTextCtrl(this, ID_LOG_TEXTCTRL, wxEmptyString, 
		wxDefaultPosition, wxSize(250, 100), 
		wxTE_MULTILINE|wxTE_READONLY|wxNO_BORDER);

	GetNotebook()->SetWindowStyleFlag(wxAUI_NB_TOP|
		wxAUI_NB_TAB_MOVE |
		wxAUI_NB_SCROLL_BUTTONS |		
		wxNO_BORDER);

	m_FrameManager.SetManagedWindow(this);
	m_FrameManager.AddPane(GetNotebook(), wxAuiPaneInfo().
		Name(wxT("CenterPane")).CenterPane());
	m_FrameManager.AddPane(m_LOGTextCtrl, wxAuiPaneInfo().Bottom().
		Name(wxT("Help")).Caption(_("Help Window")));
	m_FrameManager.Update();
}

void AUIDocViewMainFrame::OnExit(wxCommandEvent & event)
{
	Close();
}

void AUIDocViewMainFrame::OnAbout(wxCommandEvent & event)
{
	wxAboutDialogInfo info;
	info.SetName(wxT("MultiView Test"));
	info.SetVersion(wxT("v0.1"));
	info.SetWebSite(wxT("https://wxwidgets.info"));
	info.AddDeveloper(wxT("Volodymir (T-Rex) Tryapichko"));
	wxAboutBox(info);
}

wxTextCtrl * AUIDocViewMainFrame::GetLOGTextCtrl()
{
	return m_LOGTextCtrl;
}

void AUIDocViewMainFrame::OnToggleLogWindow(wxCommandEvent & event)
{
	TogglePaneVisibility(wxT("Help"));
}

void AUIDocViewMainFrame::OnToggleLogWindowUpdateUI(wxUpdateUIEvent & event)
{
	event.Check(GetPaneVisibility(wxT("Help")));
}

bool AUIDocViewMainFrame::GetPaneVisibility(wxString pane_name)
{
	wxAuiPaneInfoArray& all_panes = m_FrameManager.GetAllPanes();
	size_t i, count;
	for (i = 0, count = all_panes.GetCount(); i < count; ++i)
	{		
		if(all_panes.Item(i).name == pane_name)
		{
				return all_panes.Item(i).IsShown();
		}
	}
	return false;
}

void AUIDocViewMainFrame::TogglePaneVisibility(wxString pane_name)
{
	wxAuiPaneInfoArray& all_panes = m_FrameManager.GetAllPanes();
	size_t i, count;
	for (i = 0, count = all_panes.GetCount(); i < count; ++i)
	{		
		if(all_panes.Item(i).name == pane_name)
		{
			all_panes.Item(i).Show(!all_panes.Item(i).IsShown());
			m_FrameManager.Update();
			break;
		}
	}
}
[/sourcecode]

AUIDocViewApp.h

#ifndef _AUI_DOCVIEW_APP_H
#define _AUI_DOCVIEW_APP_H

#include 

class AUIDocViewApp : public wxApp
{
public:
	virtual bool OnInit();	
};

DECLARE_APP(AUIDocViewApp);

#endif

AUIDocViewApp.cpp

#include "AUIDocViewApp.h"
#include "AUIDocViewMainFrame.h"
#include 

IMPLEMENT_APP(AUIDocViewApp)

bool AUIDocViewApp::OnInit()
{
	srand(time(NULL));

	wxImage::AddHandler(new wxXPMHandler);
	wxImage::AddHandler(new wxPNGHandler);

	AUIDocViewMainFrame * frame = new AUIDocViewMainFrame(NULL);
	SetTopWindow(frame);
	frame->Centre();
	frame->Show();
	return true;
}

Сделайте мне красиво - Часть II - wxAUI в Multi-View приложении
Как видно, мы создали окно, содержащее строку меню, строку состояния и плавающую панель «Help Window». Плавающая панель может бать спрятана или отображена с помощью пункта меню «Toggle Help Window»
Теперь можно приступить к созданию дочерних окон.

AUIDocViewChildFrame.h

#ifndef _AUI_DOCVIEW_CHILDFRAME_H
#define _AUI_DOCVIEW_CHILDFRAME_H

#include 
#include 
#include 

class AUIDocViewChildFrame : public wxAuiMDIChildFrame
{
	bool m_HasToolBar;
	void CreateControls();
	wxToolBar * m_ToolBar;
	wxMenuBar * CreateMenuBar();
public:
	AUIDocViewChildFrame();
	AUIDocViewChildFrame(wxAuiMDIParentFrame * parent, wxWindowID id = wxID_ANY, 
		const wxString & title = wxEmptyString, bool has_toolbar = true);
	bool Create(wxAuiMDIParentFrame * parent, wxWindowID id = wxID_ANY, 
		const wxString & title = wxEmptyString, bool has_toolbar = true);

	virtual wxToolBar* CreateToolBar(long style,
                                     wxWindowID winid,
                                     const wxString& WXUNUSED(name));        
    virtual wxToolBar *GetToolBar() const;
private:
	void OnToolButton(wxCommandEvent & event);
	void OnToggleToolbar(wxCommandEvent & event);
	void OnActivated(wxActivateEvent & event);	
};

#endif

AUIDocViewChildFrame.cpp

#include "AUIDocViewChildFrame.h"
#include "AUIDocViewMainFrame.h"

#include "news_sticky.xpm"
#include "news_question.xpm"

enum
{
	ID_CHILD_TOGGLE_TOOLBAR = 11001,
	//--- BUTTONS ---
	ID_CHILD_BUTTON_ID_START = 12000
};

AUIDocViewChildFrame::AUIDocViewChildFrame()
{
}

AUIDocViewChildFrame::AUIDocViewChildFrame(wxAuiMDIParentFrame * parent, 
wxWindowID id, const wxString & title, bool has_toolbar)
{
	m_ToolBar = NULL;	
	Create(parent, id, title, has_toolbar);
}

bool AUIDocViewChildFrame::Create(wxAuiMDIParentFrame * parent, wxWindowID id, 
	const wxString & title, bool has_toolbar)
{	
	bool res = wxAuiMDIChildFrame::Create(parent, id, title);
	if(res)
	{
		m_HasToolBar = has_toolbar;
		CreateControls();
	}
	return res;
}

void AUIDocViewChildFrame::CreateControls()
{
	SetSizer(new wxBoxSizer(wxVERTICAL));
	Connect(wxID_ANY, wxEVT_ACTIVATE, 
		wxActivateEventHandler(AUIDocViewChildFrame::OnActivated));
	wxToolBar * toolBar = CreateToolBar(wxTB_FLAT|wxTB_NODIVIDER, 
		wxID_ANY, GetTitle());
	if(toolBar)
	{
		GetSizer()->Add(toolBar, 0, wxGROW);
		Connect(ID_CHILD_TOGGLE_TOOLBAR,
				wxEVT_COMMAND_MENU_SELECTED,
				wxCommandEventHandler(AUIDocViewChildFrame::OnToggleToolbar));
	}
	SetMenuBar(CreateMenuBar());
	SetBackgroundColour(wxColour(100+rand()%156, 
		100+rand()%156, 100+rand()%156));
}

wxMenuBar * AUIDocViewChildFrame::CreateMenuBar()
{
	wxMenuBar * menuBar = new wxMenuBar;
	
	wxMenu * fileMenu = new wxMenu;
	fileMenu->Append(wxID_EXIT, _("Exit\tAlt+F4"));
	menuBar->Append(fileMenu, _("File"));

	wxMenu * viewMenu = new wxMenu;	
	viewMenu->AppendCheckItem(ID_TOGGLE_LOGWINDOW, _("Toggle Help Window"));
	if(m_HasToolBar)
	{		
		viewMenu->Append(ID_CHILD_TOGGLE_TOOLBAR, _("Toggle toolbar"));			
	}
	menuBar->Append(viewMenu, _("View"));

	wxMenu * helpMenu = new wxMenu;
	helpMenu->Append(wxID_ABOUT, _("About..."));
	menuBar->Append(helpMenu, _("Help"));

	return menuBar;
}

void AUIDocViewChildFrame::OnToggleToolbar(wxCommandEvent & event)
{
	if(m_ToolBar)
	{
		if(m_ToolBar->IsShown())
		{
			GetSizer()->Detach(m_ToolBar);
			m_ToolBar->Hide();
		}
		else
		{
			m_ToolBar->Show();
			GetSizer()->Insert(0, m_ToolBar, 0, wxGROW);
		}
	}
}

wxToolBar * AUIDocViewChildFrame::CreateToolBar(long style, 
wxWindowID winid, const wxString& WXUNUSED(name))
{
	if(!m_ToolBar && m_HasToolBar)
	{
		m_ToolBar = new wxToolBar(this, winid, wxDefaultPosition, 
			wxDefaultSize, style);
		wxBitmap bmp;
		for(int i = 0; i < 1+rand()%10; i++)
		{
			if(rand()%2)
			{
				bmp = wxBitmap(news_sticky_xpm);
			} else bmp = wxBitmap(news_question_xpm);
			wxWindowID id = ID_CHILD_BUTTON_ID_START+i;
			m_ToolBar->AddTool(id, bmp, wxString::Format(wxT("Tool %i"), i));
			Connect(id, wxEVT_COMMAND_MENU_SELECTED,
					wxCommandEventHandler(AUIDocViewChildFrame::OnToolButton));
		}
		m_ToolBar->Realize();
	}
	return m_ToolBar;
}
						
wxToolBar * AUIDocViewChildFrame::GetToolBar() const
{
	return m_ToolBar;
}

void AUIDocViewChildFrame::OnToolButton(wxCommandEvent & event)
{
	wxMessageBox(wxString::Format(_("Button %u pressed"), 
		event.GetId()-ID_CHILD_BUTTON_ID_START+1));
}

void AUIDocViewChildFrame::OnActivated(wxActivateEvent & event)
{	
	AUIDocViewMainFrame * frame = wxDynamicCast(GetMDIParentFrame(), 
		AUIDocViewMainFrame);
	if(frame)
	{
		frame->GetLOGTextCtrl()->SetValue(wxString::Format(
			_("Some help text about '%s'"),	GetTitle().GetData()));
	}
}

AUIDocViewMainFrame.cpp

void AUIDocViewMainFrame::CreateControls()
{	
	...
	for(int i = 0; i < 5; i++)
	{
		AUIDocViewChildFrame * frame = new AUIDocViewChildFrame(this, wxID_ANY, 
			wxString::Format(wxT("View %i"), i+1), (rand()%2)?true:false);
		wxUnusedVar(frame);
	}	
	GetNotebook()->SetWindowStyleFlag(wxAUI_NB_TOP|
		wxAUI_NB_TAB_MOVE |
		wxAUI_NB_SCROLL_BUTTONS |		
		wxNO_BORDER);
	GetNotebook()->SetSelection(0);
...
}

Итак, мы создали класс дочернего окна, которое может иметь (или не иметь) панель инструментов (в зависимости от параметров, передаваемых конструктору). Кроме того, каждое дочернее окно может иметь свою строку меню (см. AUIDocViewChildFrame::CreateMenuBar()) . Если дочернее окно содержит панель инструментов, то в строке меню отображается пункт «Toggle toolbar».
При активизации дочернего окна, в панели «HelpWindow» отображается соответствующий текст. Доступ к главной форме из дочернего окна можно получить, используя метод wxAuiMDIChildFrame::GetMDIParentFrame().
Вот так будет выглядеть наше приложение после внесения всех изменений.

Сделайте мне красиво - Часть II - wxAUI в Multi-View приложении

А вот как наше приложение будет выглядеть в Liunx

Сделайте мне красиво - Часть II - wxAUI в Multi-View приложении

Но это еще не все. Существует интересная возможность смены интерфейса закладок в wxAuiNotebook. Для этого используются классы, производные от wxAuiTabArt (о них я расскажу как-нибудь позже). В нашем приложении мы будем использовать классы wxAuiDefaultTabArt и wxAuiSimpleTabArt, которые доступны в стандартной поставке wxAUI.
К сожалению, класс wxAuiTabArt не является потомком wxObject и для него недоступен RTTI, что не дает возможности определить, какой скин установлен в данный момент. Поэтому для определения активного скина заведем дополнительный enum HeaderStyle.
Ну что же, пора вносить новые изменения в исходный код:

AUIDocViewMainFrame.h

#ifndef _AUI_DOCVIEW_MAINFRAME_H
#define _AUI_DOCVIEW_MAINFRAME_H
...

enum HeaderStyle
{
	HS_DEFAULT,
	HS_SIMPLE
};

enum
{
	ID_LOG_TEXTCTRL = 10001,
	ID_HEADER_DEFAULT_STYLE,
	ID_HEADER_SIMPLE_STYLE,
	ID_TOGGLE_LOGWINDOW
};
...
class AUIDocViewMainFrame : public wxAuiMDIParentFrame
{		
	DECLARE_DYNAMIC_CLASS(AUIDocViewMainFrame);
	HeaderStyle m_HeaderStyle;
	...
public:
	...
	HeaderStyle GetHeaderStyle();
	...
	DECLARE_EVENT_TABLE()
	...
	void OnSwitchHeaderStyle(wxCommandEvent & event);
	void OnSwitchHeaderStyleUpdateUI(wxUpdateUIEvent & event);
	...
};

#endif

AUIDocViewMainFrame.cpp

#include "AUIDocViewMainFrame.h"
#include "AUIDocViewChildFrame.h"
#include 

IMPLEMENT_DYNAMIC_CLASS(AUIDocViewMainFrame, wxAuiMDIParentFrame);

BEGIN_EVENT_TABLE(AUIDocViewMainFrame , wxAuiMDIParentFrame)
...
EVT_MENU(ID_HEADER_DEFAULT_STYLE, AUIDocViewMainFrame::OnSwitchHeaderStyle)
EVT_MENU(ID_HEADER_SIMPLE_STYLE, AUIDocViewMainFrame::OnSwitchHeaderStyle)
...
EVT_UPDATE_UI(ID_HEADER_DEFAULT_STYLE, AUIDocViewMainFrame::OnSwitchHeaderStyleUpdateUI)
EVT_UPDATE_UI(ID_HEADER_SIMPLE_STYLE, AUIDocViewMainFrame::OnSwitchHeaderStyleUpdateUI)
...
END_EVENT_TABLE()
...
wxMenuBar * AUIDocViewMainFrame::CreateMainMenuBar()
{
	...
	wxMenu * viewMenu = new wxMenu;	
	wxMenu * headerMenu = new wxMenu;
	headerMenu->AppendRadioItem(ID_HEADER_DEFAULT_STYLE, _("Default"));
	headerMenu->AppendRadioItem(ID_HEADER_SIMPLE_STYLE, _("Simple"));
	viewMenu->Append(wxID_ANY, _("Header"), headerMenu);
	...
}

...
void AUIDocViewMainFrame::OnSwitchHeaderStyle(wxCommandEvent & event)
{
	wxAuiTabArt * art(NULL);
	switch(event.GetId())
	{
	default:
	case ID_HEADER_DEFAULT_STYLE:
		art = new wxAuiDefaultTabArt;
		m_HeaderStyle = HS_DEFAULT;
		break;
	case ID_HEADER_SIMPLE_STYLE:
		art = new wxAuiSimpleTabArt;
		m_HeaderStyle = HS_SIMPLE;
		break;	
	}
	if(art)
	{
		GetNotebook()->SetArtProvider(art);
	}
}

HeaderStyle AUIDocViewMainFrame::GetHeaderStyle()
{
	return m_HeaderStyle;
}

void AUIDocViewMainFrame::OnSwitchHeaderStyleUpdateUI(wxUpdateUIEvent & event)
{
	switch(event.GetId())
	{
	case ID_HEADER_DEFAULT_STYLE:
		event.Check(GetHeaderStyle() == HS_DEFAULT);
		break;
	case ID_HEADER_SIMPLE_STYLE:
		event.Check(GetHeaderStyle() == HS_SIMPLE);
		break;
	default:
		event.Skip();
	}
}
...

В принципе, внесенные изменениядовольно просты. Мы добавили переменную-индикатор текущего скина, меню «Header» с двумя пунктами, которые позволяют сменить активный скин, а также обработчики события wxUpdateUIEvent, необходимые для того, чтобы маркер активного скина корректно отображался в меню.
После всего сделанного, мы должны получить вот приблизительно такой результат.

Сделайте мне красиво - Часть II - wxAUI в Multi-View приложении

Но и это еще не всё. Интересной особенностью является также возможность использования плавающих панелей внутри каждого дочернего окна. В этом случае докинг будет осуществляться только внутри дочернего окна.

Для демонстрации этих возможностей изменим немного класс дочернего окна и создадим производный от него класс, который будет частично наследовать уже существующий функционал, а также будет предоставлять возможность размещения плавающих панелей.

AUIDocViewChildFrame.h

#ifndef _AUI_DOCVIEW_CHILDFRAME_H
#define _AUI_DOCVIEW_CHILDFRAME_H

#include 
#include 
#include 
#include 

class AUIDocViewChildFrame : public wxAuiMDIChildFrame
{
protected:
	wxToolBar * m_ToolBar;
	bool m_HasToolBar;
	virtual wxMenuBar * CreateMenuBar();
	virtual void CreateControls();
public:
	AUIDocViewChildFrame();
	AUIDocViewChildFrame(wxAuiMDIParentFrame * parent, wxWindowID id = wxID_ANY, 
		const wxString & title = wxEmptyString, bool has_toolbar = true);
	bool Create(wxAuiMDIParentFrame * parent, wxWindowID id = wxID_ANY, 
		const wxString & title = wxEmptyString, bool has_toolbar = true);
		
	virtual wxToolBar* CreateToolBar(long style,
                                     wxWindowID winid,
                                     const wxString& WXUNUSED(name));        
    virtual wxToolBar *GetToolBar() const;
	DECLARE_EVENT_TABLE()	
	void OnActivated(wxActivateEvent & event);
	void OnToolButton(wxCommandEvent & event);
	virtual void OnToggleToolbar(wxCommandEvent & event);
	virtual void OnToggleToolbarUpdateUI(wxUpdateUIEvent & event);
};

class AUIManagedChildFrame : public AUIDocViewChildFrame
{
	wxAuiManager m_FrameManager;
	wxTreeCtrl * m_TreeCtrl;
	virtual wxMenuBar * CreateMenuBar();
	virtual void CreateControls();	
public:
	~AUIManagedChildFrame();
	
	bool GetPaneVisibility(wxString pane_name);
	void TogglePaneVisibility(wxString pane_name);
	DECLARE_EVENT_TABLE()
	void OnToggleTreeCtrl(wxCommandEvent & event);
	void OnToggleTreeCtrlUpdateUI(wxUpdateUIEvent & event);
	virtual void OnToggleToolbar(wxCommandEvent & event);
	virtual void OnToggleToolbarUpdateUI(wxUpdateUIEvent & event);
};

#endif

AUIDocViewChildFrame.cpp

#include "AUIDocViewChildFrame.h"
#include "AUIDocViewMainFrame.h"

#include "news_sticky.xpm"
#include "news_question.xpm"

enum
{
	ID_CHILD_TOGGLE_TOOLBAR = 11001,
	ID_CHILD_TOGGLE_TREECTRL,
	//--- BUTTONS ---
	ID_CHILD_BUTTON_ID_START = 12000
};

BEGIN_EVENT_TABLE(AUIDocViewChildFrame, wxAuiMDIChildFrame)
EVT_ACTIVATE(AUIDocViewChildFrame::OnActivated)
END_EVENT_TABLE()

AUIDocViewChildFrame::AUIDocViewChildFrame()
{
}

bool AUIDocViewChildFrame::Create(wxAuiMDIParentFrame * parent, wxWindowID id, 
	const wxString & title, bool has_toolbar)
{	
	bool res = wxAuiMDIChildFrame::Create(parent, id, title);
	if(res)
	{
		m_ToolBar = NULL;
		m_HasToolBar = has_toolbar;
		CreateControls();
	}
	return res;
}

void AUIDocViewChildFrame::CreateControls()
{
	SetSizer(new wxBoxSizer(wxVERTICAL));
	m_ToolBar = CreateToolBar(wxTB_FLAT|wxTB_NODIVIDER, wxID_ANY, GetTitle());
	if(m_ToolBar)
	{
		GetSizer()->Add(m_ToolBar, 0, wxGROW);
		Connect(ID_CHILD_TOGGLE_TOOLBAR,
				wxEVT_COMMAND_MENU_SELECTED,
				wxCommandEventHandler(AUIDocViewChildFrame::OnToggleToolbar));
		Connect(ID_CHILD_TOGGLE_TOOLBAR,
				wxEVT_UPDATE_UI,
				wxUpdateUIEventHandler(AUIDocViewChildFrame::OnToggleToolbarUpdateUI));
	}
	SetMenuBar(CreateMenuBar());
	SetBackgroundColour(wxColour(100+rand()%156, 100+rand()%156, 100+rand()%156));
}

wxMenuBar * AUIDocViewChildFrame::CreateMenuBar()
{
	wxMenuBar * menuBar = new wxMenuBar;
	
	wxMenu * fileMenu = new wxMenu;
	fileMenu->Append(wxID_EXIT, _("Exit\tAlt+F4"));
	menuBar->Append(fileMenu, _("File"));

	wxMenu * viewMenu = new wxMenu;	
	wxMenu * headerMenu = new wxMenu;
	headerMenu->AppendRadioItem(ID_HEADER_DEFAULT_STYLE, _("Default"));
	headerMenu->AppendRadioItem(ID_HEADER_SIMPLE_STYLE, _("Simple"));
	viewMenu->Append(wxID_ANY, _("Header"), headerMenu);
	viewMenu->AppendCheckItem(ID_TOGGLE_LOGWINDOW, _("Toggle Help Window"));
	if(m_HasToolBar)
	{		
		viewMenu->AppendCheckItem(ID_CHILD_TOGGLE_TOOLBAR, _("Toggle toolbar"));			
	}
	menuBar->Append(viewMenu, _("View"));

	wxMenu * helpMenu = new wxMenu;
	helpMenu->Append(wxID_ABOUT, _("About..."));
	menuBar->Append(helpMenu, _("Help"));

	return menuBar;
}

void AUIDocViewChildFrame::OnToggleToolbar(wxCommandEvent & event)
{
	if(m_ToolBar)
	{
		if(m_ToolBar->IsShown())
		{
			GetSizer()->Detach(m_ToolBar);
			m_ToolBar->Hide();
		}
		else
		{
			m_ToolBar->Show();
			GetSizer()->Insert(0, m_ToolBar, 0, wxGROW);
		}
	}
}

void AUIDocViewChildFrame::OnToggleToolbarUpdateUI(wxUpdateUIEvent & event)
{
	if(m_ToolBar)
	{
		event.Check(m_ToolBar->IsShown());
	}
	else event.Skip();
}

wxToolBar * AUIDocViewChildFrame::CreateToolBar(long style, 
wxWindowID winid, const wxString& WXUNUSED(name))
{
	if(!m_ToolBar && m_HasToolBar)
	{
		m_ToolBar = new wxToolBar(this, winid, wxDefaultPosition, wxDefaultSize, style);
		wxBitmap bmp;
		for(int i = 0; i < 1+rand()%10; i++)
		{
			if(rand()%2)
			{
				bmp = wxBitmap(news_sticky_xpm);
			} else bmp = wxBitmap(news_question_xpm);
			wxWindowID id = ID_CHILD_BUTTON_ID_START+i;
			m_ToolBar->AddTool(id, bmp, wxString::Format(wxT("Tool %i"), i));
			Connect(id, wxEVT_COMMAND_MENU_SELECTED,
					wxCommandEventHandler(AUIDocViewChildFrame::OnToolButton));
		}
		m_ToolBar->Realize();
	}
	return m_ToolBar;
}
						
wxToolBar * AUIDocViewChildFrame::GetToolBar() const
{
	return m_ToolBar;
}

void AUIDocViewChildFrame::OnToolButton(wxCommandEvent & event)
{
	wxMessageBox(wxString::Format(_("Button %u pressed"), 
		event.GetId()-ID_CHILD_BUTTON_ID_START+1));
}

void AUIDocViewChildFrame::OnActivated(wxActivateEvent & event)
{	
	AUIDocViewMainFrame * frame = wxDynamicCast(GetMDIParentFrame(), AUIDocViewMainFrame);
	if(frame)
	{
		frame->GetLOGTextCtrl()->SetValue(wxString::Format(
			_("Some help text about '%s'"),	GetTitle().GetData()));
	}
}

BEGIN_EVENT_TABLE(AUIManagedChildFrame, AUIDocViewChildFrame)
EVT_MENU(ID_CHILD_TOGGLE_TREECTRL, AUIManagedChildFrame::OnToggleTreeCtrl)
EVT_UPDATE_UI(ID_CHILD_TOGGLE_TREECTRL, AUIManagedChildFrame::OnToggleTreeCtrlUpdateUI)
END_EVENT_TABLE()

AUIManagedChildFrame::~AUIManagedChildFrame()
{
	m_FrameManager.UnInit();
}

void AUIManagedChildFrame::CreateControls()
{
	AUIDocViewChildFrame::CreateControls();
	m_FrameManager.SetManagedWindow(this);	
	wxPanel * panel = new wxPanel(this, wxID_ANY);
	panel->SetBackgroundColour(
		wxColour(100+rand()%156, 100+rand()%156, 100+rand()%156));
	m_FrameManager.AddPane(panel, 
		wxAuiPaneInfo().Name(wxT("CenterPane")).CenterPane());

	SetMenuBar(CreateMenuBar());	
	
	wxToolBar * toolBar = CreateToolBar(wxTB_FLAT|wxTB_NODIVIDER, wxID_ANY, GetTitle());
	if(toolBar)
	{
		m_FrameManager.AddPane(toolBar, wxAuiPaneInfo().Name(wxT("ToolBar")).
			ToolbarPane().Top());
		Connect(ID_CHILD_TOGGLE_TOOLBAR,
				wxEVT_COMMAND_MENU_SELECTED,
				wxCommandEventHandler(AUIManagedChildFrame::OnToggleToolbar));
		Connect(ID_CHILD_TOGGLE_TOOLBAR,
				wxEVT_UPDATE_UI,
				wxUpdateUIEventHandler(AUIManagedChildFrame::OnToggleToolbarUpdateUI));
	}	
			
	m_TreeCtrl = new wxTreeCtrl(this, wxID_ANY, wxDefaultPosition,
		wxSize(150, 300));
	wxTreeItemId root = m_TreeCtrl->AddRoot(_("Root"));
	m_TreeCtrl->AppendItem(root, _("Node 1"));
	m_TreeCtrl->AppendItem(root, _("Node 2"));
	m_TreeCtrl->AppendItem(root, _("Node 3"));
	m_TreeCtrl->Expand(root);	
	m_FrameManager.AddPane(m_TreeCtrl, wxAuiPaneInfo().Name(wxT("Tree")).Left());	
	m_FrameManager.Update();		
}

void AUIManagedChildFrame::OnToggleToolbar(wxCommandEvent & event)
{
	TogglePaneVisibility(wxT("ToolBar"));
}

void AUIManagedChildFrame::OnToggleToolbarUpdateUI(wxUpdateUIEvent & event)
{
	event.Check(GetPaneVisibility(wxT("ToolBar")));
}

void AUIManagedChildFrame::OnToggleTreeCtrl(wxCommandEvent & event)
{
	TogglePaneVisibility(wxT("Tree"));
}

void AUIManagedChildFrame::OnToggleTreeCtrlUpdateUI(wxUpdateUIEvent & event)
{
	event.Check(GetPaneVisibility(wxT("Tree")));
}

bool AUIManagedChildFrame::GetPaneVisibility(wxString pane_name)
{
	wxAuiPaneInfoArray& all_panes = m_FrameManager.GetAllPanes();
	size_t i, count;
	for (i = 0, count = all_panes.GetCount(); i < count; ++i)
	{		
		if(all_panes.Item(i).name == pane_name)
		{
				return all_panes.Item(i).IsShown();
		}
	}
	return false;
}

void AUIManagedChildFrame::TogglePaneVisibility(wxString pane_name)
{
	wxAuiPaneInfoArray& all_panes = m_FrameManager.GetAllPanes();
	size_t i, count;
	for (i = 0, count = all_panes.GetCount(); i < count; ++i)
	{		
		if(all_panes.Item(i).name == pane_name)
		{
			all_panes.Item(i).Show(!all_panes.Item(i).IsShown());
			m_FrameManager.Update();
			break;
		}
	}
}

wxMenuBar * AUIManagedChildFrame::CreateMenuBar()
{
	wxMenuBar * menuBar = new wxMenuBar;
	
	wxMenu * fileMenu = new wxMenu;
	fileMenu->Append(wxID_EXIT, _("Exit\tAlt+F4"));
	menuBar->Append(fileMenu, _("File"));

	wxMenu * viewMenu = new wxMenu;	
	wxMenu * headerMenu = new wxMenu;
	headerMenu->AppendRadioItem(ID_HEADER_DEFAULT_STYLE, _("Default"));
	headerMenu->AppendRadioItem(ID_HEADER_SIMPLE_STYLE, _("Simple"));
	viewMenu->Append(wxID_ANY, _("Header"), headerMenu);
	viewMenu->AppendCheckItem(ID_TOGGLE_LOGWINDOW, _("Toggle Help Window"));
	viewMenu->AppendCheckItem(ID_CHILD_TOGGLE_TREECTRL, _("Toggle tree"));
	if(m_HasToolBar)
	{		
		viewMenu->AppendCheckItem(ID_CHILD_TOGGLE_TOOLBAR, _("Toggle toolbar"));
	}
	menuBar->Append(viewMenu, _("View"));

	wxMenu * helpMenu = new wxMenu;
	helpMenu->Append(wxID_ABOUT, _("About..."));
	menuBar->Append(helpMenu, _("Help"));

	return menuBar;
}

AUIDocViewMainFrame.cpp

void AUIDocViewMainFrame::CreateControls()
{	
	SetMenuBar(AUIDocViewMainFrame::CreateMainMenuBar());
	...

	AUIDocViewChildFrame * f1 = new AUIDocViewChildFrame;
	f1->Create(this, wxID_ANY, wxT("View 1"), true);
	
	AUIManagedChildFrame * f2 = new AUIManagedChildFrame;
	f2->Create(this, wxID_ANY, wxT("View 2"), true);
	...
	
	GetNotebook()->SetWindowStyleFlag(wxAUI_NB_TOP|
		wxAUI_NB_TAB_MOVE |
		wxAUI_NB_SCROLL_BUTTONS |		
		wxNO_BORDER);
	GetNotebook()->SetSelection(0);
...
}

Теперь у нас должно получиться что-то типа этого:
Сделайте мне красиво - Часть II - wxAUI в Multi-View приложении
А вот как наше приложение будет выглядеть в Linux:
Сделайте мне красиво - Часть II - wxAUI в Multi-View приложении
Исходный код примеров:
Пример 1 (VS 2005)
Пример 2 (VS 2005 – Windows|Eclipse – Linux)

2 comments

  1. Vanya   •  

    Привет, я воспользовался вашим примером ( на 2.9.0 и 2.8.3) и в обоих случаях при закрытии программы получаю ошибку про то что “Нарушение прав доступа при чтении…” и выскакивает файл framemanager.cpp с указанием на строку :
    …..
    else
    {
    if (p.window->IsShown() != p.IsShown())
    >> p.window->Show(p.IsShown());
    }
    ….

    Не подскажите в чем подвох?

  2. T-Rex   •  

    Возможно просто пофиксили баг с утечкой памяти для незадоченных окон и теперь этот кусок кода уже не нужен.

Leave a Reply

Your email address will not be published. Required fields are marked *

Please leave these two fields as-is: