Сделайте мне красиво – Часть I – Знакомство с wxAUI

Сегодня я хочу рассказать о таком полезном явлении в wxWidgets, как плавающие окна (Docking Windows). Со временем, каждого из нас посещает желание, так или иначе, сделать интерфейс своих программных продуктов более привлекательным и более удобным. Одним из способов достичь этого являются плавающие окна. Использование плавающих панелей инструментов, информационных и прочих панелей в приложении, позволяет настроить внешний вид программного продукта, которым вы пользуетесь очень часто, как говорится «под себя» и тем самым сделать работу с ним более комфортной. Эта возможность используется во многих современных приложениях и многие пользователи, сами того не замечая, уже давно привыкли к ней.

Итак, начнем наше знакомство…

Создадим простейшее приложение wxWidgets.

Сделайте мне красиво - Часть I - Знакомство с wxAUI

В настройках Application Type необходимо указать Windows Application, а в Additional Properties выставить флаг Empty Project

Сделайте мне красиво - Часть I - Знакомство с wxAUI

Добавим заголовочные файлы и файлы исходного кода в наше приложение

Сделайте мне красиво - Часть I - Знакомство с wxAUI

Всё, теперь можно писать код:

MainFrame.h

#ifndef _DOCKING_WINDOWS_SAMPLE_MAINFRAME_H
#define _DOCKING_WINDOWS_SAMPLE_MAINFRAME_H

#include 

#define wxDWSTitleStr _("Docking Windows Sample")

class DockingWindowsSampleMainFrame : public wxFrame
{
	void CreateControls();
	DECLARE_DYNAMIC_CLASS(DockingWindowsSampleMainFrame)
public:
	DockingWindowsSampleMainFrame();
	DockingWindowsSampleMainFrame(wxWindow * parent, 
				wxWindowID id = wxID_ANY,
				const wxString & title = wxDWSTitleStr,
				const wxPoint & pos = wxDefaultPosition,
				const wxSize & size = wxDefaultSize,
				long style = wxDEFAULT_FRAME_STYLE);
	~DockingWindowsSampleMainFrame();

	bool Create(wxWindow * parent, 
				wxWindowID id = wxID_ANY,
				const wxString & title = wxDWSTitleStr,
				const wxPoint & pos = wxDefaultPosition,
				const wxSize & size = wxDefaultSize,
				long style = wxDEFAULT_FRAME_STYLE);

	DECLARE_EVENT_TABLE()
	void OnExit(wxCommandEvent & event);

};

#endif

MainFrame.cpp

#include "DockingWindowsSampleMainFrame.h"

IMPLEMENT_DYNAMIC_CLASS(DockingWindowsSampleMainFrame, wxFrame);

enum
{
	ID_TOGGLE_STANDARD_TOOLBAR = 10001,
	ID_TOGGLE_ADDITIONAL_TOOLBAR,
	ID_TOGGLE_STATUSBAR,
	ID_LOAD_LAYOUT,
	ID_SAVE_LAYOUT
};

BEGIN_EVENT_TABLE(DockingWindowsSampleMainFrame, wxFrame)
EVT_MENU(wxID_EXIT, DockingWindowsSampleMainFrame::OnExit)
END_EVENT_TABLE()

DockingWindowsSampleMainFrame::DockingWindowsSampleMainFrame()
{
}

DockingWindowsSampleMainFrame::DockingWindowsSampleMainFrame(wxWindow * parent, 
	wxWindowID id, const wxString & title, const wxPoint & pos,
				const wxSize & size, long style)
{
	Create(parent, id, title, pos, size, style);
}

DockingWindowsSampleMainFrame::~DockingWindowsSampleMainFrame()
{
}

bool DockingWindowsSampleMainFrame::Create(wxWindow * parent, 
	wxWindowID id, const wxString & title, const wxPoint & pos,
	const wxSize & size, long style)
{
	bool res = wxFrame::Create(parent, id, title, pos, size, style);
	if(res)
	{
		CreateControls();
	}
	return res;
}

void DockingWindowsSampleMainFrame::CreateControls()
{
	wxMenuBar * menuBar = new wxMenuBar;
	SetMenuBar(menuBar);

	wxMenu * fileMenu = new wxMenu;
	fileMenu->Append(wxID_NEW, _("New\tCtrl+N"));
	fileMenu->Append(wxID_OPEN, _("Open\tCtrl+O"));
	fileMenu->Append(wxID_SAVE, _("Save\tCtrl+S"));
	fileMenu->AppendSeparator();
	fileMenu->Append(wxID_EXIT, _("Exit\tAlt+F4"));

	wxMenu * toolbarsMenu = new wxMenu;
	toolbarsMenu->Append(ID_TOGGLE_STANDARD_TOOLBAR, _("Standard"));
	toolbarsMenu->Append(ID_TOGGLE_ADDITIONAL_TOOLBAR, _("Additional"));

	wxMenu * layoutMenu = new wxMenu;
	layoutMenu->Append(ID_LOAD_LAYOUT, _("Load"));
	layoutMenu->Append(ID_SAVE_LAYOUT, _("Save"));

	wxMenu * viewMenu = new wxMenu;
	viewMenu->Append(wxID_ANY, _("Toolbars"), toolbarsMenu);
	viewMenu->Append(wxID_ANY, _("Layout"), layoutMenu);
	viewMenu->Append(ID_TOGGLE_STATUSBAR, _("Status Bar"));	
	

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

	menuBar->Append(fileMenu, _("File"));
	menuBar->Append(viewMenu, _("View"));
	menuBar->Append(helpMenu, _("Help"));

	CreateStatusBar();
}

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

App.h

#ifndef _DOCKING_WINDOWS_SAMPLE_APP_H
#define _DOCKING_WINDOWS_SAMPLE_APP_H

#include 

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

DECLARE_APP(DockingWindowsSampleApp)

#endif

App.cpp

#include "DockingWindowsSampleApp.h"
#include "DockingWindowsSampleMainFrame.h"
#include 

IMPLEMENT_APP(DockingWindowsSampleApp)

bool DockingWindowsSampleApp::OnInit()
{
	wxImage::AddHandler(new wxXPMHandler);
	wxImage::AddHandler(new wxPNGHandler);
	DockingWindowsSampleMainFrame * frame = new DockingWindowsSampleMainFrame(NULL);
	SetTopWindow(frame);
	frame->Centre();
	frame->Show();
	return true;
}

Запускаем. У нас должно получиться простейшее окно с меню и строкой состояния.
Итак, база у нас готова, теперь можно приступать к созданию плавающих панелей (Docking Windows).
Поодержка Docking Windows в wxWidgets реализована библиотекой wxAUI, которая с недавнего времени является частью wxWidgets. Основным элементом движка, отвечающего за работу Docking Windows, является класс wxAuiFrameManager. Этот класс отвечает за размещение плавающих окон, установку их размеров и параметров в процессе работы приложения.
Внесем некоторые изменения в наш исходный код и посмотрим, что получилось.

MainFrame.h

#ifndef _DOCKING_WINDOWS_SAMPLE_MAINFRAME_H
#define _DOCKING_WINDOWS_SAMPLE_MAINFRAME_H

#include 
#include 
#include 

#define wxDWSTitleStr _("Docking Windows Sample")

class DockingWindowsSampleMainFrame : public wxFrame
{
	wxAuiManager m_Manager;
	wxToolBar * m_StdToolBar;
	wxToolBar * m_AddToolBar;
	wxTreeCtrl * m_InfoTree;
	wxAuiNotebook * m_Notebook;	

	wxPanel * m_Page1;
	wxPanel * m_Page2;
	void CreateControls();
	void CreateStdToolBar();
	void CreateAddToolBar();
	void CreateInfoTree();
	DECLARE_DYNAMIC_CLASS(DockingWindowsSampleMainFrame)
public:
	DockingWindowsSampleMainFrame();
	DockingWindowsSampleMainFrame(wxWindow * parent, 
				wxWindowID id = wxID_ANY,
				const wxString & title = wxDWSTitleStr,
				const wxPoint & pos = wxDefaultPosition,
				const wxSize & size = wxSize(650, 450),
				long style = wxDEFAULT_FRAME_STYLE);
	~DockingWindowsSampleMainFrame();

	bool Create(wxWindow * parent, 
				wxWindowID id = wxID_ANY,
				const wxString & title = wxDWSTitleStr,
				const wxPoint & pos = wxDefaultPosition,
				const wxSize & size = wxSize(650, 450),
				long style = wxDEFAULT_FRAME_STYLE);

	DECLARE_EVENT_TABLE()
	void OnExit(wxCommandEvent & event);

};

#endif

MainFrame.cpp

#include "DockingWindowsSampleMainFrame.h"

#include "wxwin16x16.xpm"
#include "new.xpm"
#include "fileopen.xpm"
#include "filesave.xpm"
#include "htmfoldr.xpm"

#include "cut.xpm"
#include "copy.xpm"
#include "find.xpm"

IMPLEMENT_DYNAMIC_CLASS(DockingWindowsSampleMainFrame, wxFrame);

enum
{
	ID_TOGGLE_STANDARD_TOOLBAR = 10001,
	ID_TOGGLE_ADDITIONAL_TOOLBAR,
	ID_TOGGLE_STATUSBAR,
	ID_LOAD_LAYOUT,
	ID_SAVE_LAYOUT,
	ID_NOTEBOOK,
	ID_INFO_TREE
};

BEGIN_EVENT_TABLE(DockingWindowsSampleMainFrame, wxFrame)
EVT_MENU(wxID_EXIT, DockingWindowsSampleMainFrame::OnExit)
END_EVENT_TABLE()

DockingWindowsSampleMainFrame::DockingWindowsSampleMainFrame()
{
}

DockingWindowsSampleMainFrame::DockingWindowsSampleMainFrame(wxWindow * parent, 
	wxWindowID id, const wxString & title, const wxPoint & pos,
				const wxSize & size, long style)
{
	m_StdToolBar = NULL;
	m_AddToolBar = NULL;
	m_Page1 = NULL;
	m_Page2 = NULL;
	m_Notebook = NULL;
	Create(parent, id, title, pos, size, style);
}

DockingWindowsSampleMainFrame::~DockingWindowsSampleMainFrame()
{	
	m_Manager.UnInit();
}

bool DockingWindowsSampleMainFrame::Create(wxWindow * parent, 
	wxWindowID id, const wxString & title, const wxPoint & pos,
	const wxSize & size, long style)
{
	bool res = wxFrame::Create(parent, id, title, pos, size, style);
	if(res)
	{
		SetIcon(wxIcon(wxwin16x16_xpm));
		CreateControls();
	}
	return res;
}

void DockingWindowsSampleMainFrame::CreateControls()
{
	SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
	wxMenuBar * menuBar = new wxMenuBar;
	SetMenuBar(menuBar);	

	wxMenu * fileMenu = new wxMenu;
	fileMenu->Append(wxID_NEW, _("New\tCtrl+N"));
	fileMenu->Append(wxID_OPEN, _("Open\tCtrl+O"));
	fileMenu->Append(wxID_SAVE, _("Save\tCtrl+S"));
	fileMenu->AppendSeparator();
	fileMenu->Append(wxID_EXIT, _("Exit\tAlt+F4"));

	wxMenu * toolbarsMenu = new wxMenu;
	toolbarsMenu->Append(ID_TOGGLE_STANDARD_TOOLBAR, _("Standard"));
	toolbarsMenu->Append(ID_TOGGLE_ADDITIONAL_TOOLBAR, _("Additional"));

	wxMenu * layoutMenu = new wxMenu;
	layoutMenu->Append(ID_LOAD_LAYOUT, _("Load"));
	layoutMenu->Append(ID_SAVE_LAYOUT, _("Save"));

	wxMenu * viewMenu = new wxMenu;
	viewMenu->Append(wxID_ANY, _("Toolbars"), toolbarsMenu);
	viewMenu->Append(wxID_ANY, _("Layout"), layoutMenu);
	viewMenu->Append(ID_TOGGLE_STATUSBAR, _("Status Bar"));	
	

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

	menuBar->Append(fileMenu, _("File"));
	menuBar->Append(viewMenu, _("View"));
	menuBar->Append(helpMenu, _("Help"));
	
	m_Manager.SetManagedWindow(this);

	CreateStatusBar();
	CreateStdToolBar();
	CreateAddToolBar();
	CreateInfoTree();
	
	m_Notebook = new wxAuiNotebook(this, ID_NOTEBOOK, wxDefaultPosition, wxSize(600, 450), 
		wxAUI_NB_DEFAULT_STYLE|wxNO_BORDER);
	m_Page1 = new wxPanel(m_Notebook, wxID_ANY);
	m_Page2 = new wxPanel(m_Notebook, wxID_ANY);
	m_Notebook->AddPage(m_Page1, _("Page1"));
	m_Notebook->AddPage(m_Page2, _("Page2"));

	m_Manager.AddPane(m_Notebook, wxAuiPaneInfo().CenterPane());
	m_Manager.AddPane(m_StdToolBar, wxAuiPaneInfo().ToolbarPane().Top().Floatable(false));
	m_Manager.AddPane(m_AddToolBar, wxAuiPaneInfo().ToolbarPane().Top().Position(2).
		Floatable(false));
	m_Manager.AddPane(m_InfoTree, wxAuiPaneInfo().Left().Layer(1).PinButton().
		MinimizeButton().MaximizeButton().Caption(wxT("Information")));

	m_Manager.Update();
}

void DockingWindowsSampleMainFrame::CreateStdToolBar()
{	
	m_StdToolBar = new wxToolBar(this, wxID_ANY, wxDefaultPosition,
		wxDefaultSize, wxBORDER_NONE|wxTB_HORIZONTAL|wxTB_NODIVIDER|wxTB_FLAT);
	m_StdToolBar->SetToolBitmapSize(wxSize(16, 15));
	m_StdToolBar->AddTool(wxID_NEW, _("New"), wxBitmap(new_xpm));
	m_StdToolBar->AddTool(wxID_OPEN, _("Open"), wxBitmap(fileopen_xpm));
	m_StdToolBar->AddTool(wxID_SAVE, _("Save"), wxBitmap(filesave_xpm));
	m_StdToolBar->AddSeparator();
	m_StdToolBar->AddTool(wxID_ABOUT, _("About..."), wxBitmap(htmfoldr_xpm));
	m_StdToolBar->Realize();
}

void DockingWindowsSampleMainFrame::CreateAddToolBar()
{
	m_AddToolBar = new wxToolBar(this, wxID_ANY, wxDefaultPosition,
		wxDefaultSize, wxBORDER_NONE|wxTB_HORIZONTAL|wxTB_NODIVIDER|wxTB_FLAT);
	m_AddToolBar->SetToolBitmapSize(wxSize(16, 15));
	m_AddToolBar->AddTool(wxID_CUT, _("Cut"), wxBitmap(cut_xpm));
	m_AddToolBar->AddTool(wxID_COPY, _("Copy"), wxBitmap(copy_xpm));
	m_AddToolBar->AddTool(wxID_FIND, _("Find"), wxBitmap(find_xpm));
	m_AddToolBar->Realize();
}

void DockingWindowsSampleMainFrame::CreateInfoTree()
{
	m_InfoTree = new wxTreeCtrl(this, ID_INFO_TREE, wxDefaultPosition, wxSize(170, 250),
		wxTR_HAS_BUTTONS|wxTR_LINES_AT_ROOT|wxTR_SINGLE);
	wxTreeItemId root = m_InfoTree->AddRoot(_("Document"));
	m_InfoTree->AppendItem(root, _("Item 1"));
	m_InfoTree->AppendItem(root, _("Item 2"));
	m_InfoTree->AppendItem(root, _("Item 3"));
	m_InfoTree->Expand(root);
}

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

Для ассоциации менеджера плавающих окон с формой необходимо вызвать метод wxAuiFrameManager::SetManagedWindow() и передать в качестве параметр указатель на объект класса wxFrame (или производного). В нашем примере это реализовано строкой m_Manager.SetManagedWindow(this);
Перед тем, как форма, ассоциированная с менеджером плавающих окон будет удалена, необходимо обязательно произвести деинициализацию менеджера. Лучше всего это делать в деструкторе класса формы. В нашем примере это строка m_Manager.UnInit();
После внесения изменений необходимо сообщить менеджеру плавающих окон о том, что необходимо применить эти изменения. Это можно сделать, вызвав метод wxAuiFrameManager::Update. В нашем примере єто реализуется строкой m_Manager.Update().
Для создания плавающей панели необходимо вызвать метод wxAuiFrameManager::AddPane, котрому в качестве параметров передать указатель на компонент, который будет помещен на плавающую панель, а также объект wxAuiPaneInfo, который описывает параметры плавающей панели.

Теперь пара слов о том, что же делает приведенный выше пример.
В дополнение к уже созданным панели меню и строке состояния, мы создаем две плавающие панели инструментов, wxAuiNotebook с двумя страницами в центре формы и плавающий wxTreeCtrl.
Как видно из исходного кода, мы используем несколько XPM-изображений в качестве иконок для кнопок панели инструментов. Эти изображения можно взять в подкаталоге art каталога с исходным кодом wxWidgets.

Сделайте мне красиво - Часть I - Знакомство с wxAUI

Теперь наше приложение выглядит подобным образом.

Сделайте мне красиво - Часть I - Знакомство с wxAUI

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

Сделайте мне красиво - Часть I - Знакомство с wxAUI

Страницы нашего wxAuiNotebook можно перетаскивать и размещать рядом друг с другм по горизонтали илм по вертикали

Сделайте мне красиво - Часть I - Знакомство с wxAUI

У каждой плавающей панели есть свойство, разрешающее или запрещающее отстыковку от главной формы. Отстыкованные панели (а также неотстыкованные, при условии установленного флага HasCloseButton()) имеют кнопку закрытия, которая позволяет скрыть плавающую панель. При нажатии на кнопку закрытия, панель и связанный с ней компонент не удаляются, а становятся невидимыми (если не установлен флаг IsDestroyOnClose(), который обеспечивает удаление панели и связанного с ней компонента при закрытии панели).

Сделайте мне красиво - Часть I - Знакомство с wxAUI

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

MainFrame.h

...
class DockingWindowsSampleMainFrame : public wxFrame
{
	...
	bool GetPaneVisibility(wxString pane_name);
	void TogglePaneVisibility(wxString pane_name);
public:
	...
	DECLARE_EVENT_TABLE()
	void OnExit(wxCommandEvent & event);

	void OnToggleStdToolbar(wxCommandEvent & event);
	void OnToggleAddToolbar(wxCommandEvent & event);
	void OnToggleInfoTree(wxCommandEvent & event);
	void OnToggleStatusbar(wxCommandEvent & event);

	void OnToggleStdToolbarUpdateUI(wxUpdateUIEvent & event);
	void OnToggleAddToolbarUpdateUI(wxUpdateUIEvent & event);
	void OnToggleInfoTreeUpdateUI(wxUpdateUIEvent & event);
	void OnToggleStatusbarUpdateUI(wxUpdateUIEvent & event);

};
...

MainFrame.cpp

...
enum
{
	ID_TOGGLE_STANDARD_TOOLBAR = 10001,
	ID_TOGGLE_ADDITIONAL_TOOLBAR,
	ID_TOGGLE_INFO_TREE,
	ID_TOGGLE_STATUSBAR,
	ID_LOAD_LAYOUT,
	ID_SAVE_LAYOUT,
	ID_NOTEBOOK,
	ID_INFO_TREE
};

BEGIN_EVENT_TABLE(DockingWindowsSampleMainFrame, wxFrame)
EVT_MENU(wxID_EXIT, DockingWindowsSampleMainFrame::OnExit)
EVT_MENU(ID_TOGGLE_STANDARD_TOOLBAR, DockingWindowsSampleMainFrame::OnToggleStdToolbar)
EVT_MENU(ID_TOGGLE_ADDITIONAL_TOOLBAR, DockingWindowsSampleMainFrame::OnToggleAddToolbar)
EVT_MENU(ID_TOGGLE_INFO_TREE, DockingWindowsSampleMainFrame::OnToggleInfoTree)
EVT_MENU(ID_TOGGLE_STATUSBAR, DockingWindowsSampleMainFrame::OnToggleStatusbar)
EVT_UPDATE_UI(ID_TOGGLE_STANDARD_TOOLBAR, DockingWindowsSampleMainFrame::OnToggleStdToolbarUpdateUI)
EVT_UPDATE_UI(ID_TOGGLE_ADDITIONAL_TOOLBAR, DockingWindowsSampleMainFrame::OnToggleAddToolbarUpdateUI)
EVT_UPDATE_UI(ID_TOGGLE_INFO_TREE, DockingWindowsSampleMainFrame::OnToggleInfoTreeUpdateUI)
EVT_UPDATE_UI(ID_TOGGLE_STATUSBAR, DockingWindowsSampleMainFrame::OnToggleStatusbarUpdateUI)
END_EVENT_TABLE()

...
void DockingWindowsSampleMainFrame::CreateControls()
{
	SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
	wxMenuBar * menuBar = new wxMenuBar;
	SetMenuBar(menuBar);	

	wxMenu * fileMenu = new wxMenu;
	fileMenu->Append(wxID_NEW, _("New\tCtrl+N"));
	fileMenu->Append(wxID_OPEN, _("Open\tCtrl+O"));
	fileMenu->Append(wxID_SAVE, _("Save\tCtrl+S"));
	fileMenu->AppendSeparator();
	fileMenu->Append(wxID_EXIT, _("Exit\tAlt+F4"));

	wxMenu * toolbarsMenu = new wxMenu;
	toolbarsMenu->AppendCheckItem(ID_TOGGLE_STANDARD_TOOLBAR, _("Standard"));
	toolbarsMenu->AppendCheckItem(ID_TOGGLE_ADDITIONAL_TOOLBAR, _("Additional"));

	wxMenu * layoutMenu = new wxMenu;
	layoutMenu->Append(ID_LOAD_LAYOUT, _("Load"));
	layoutMenu->Append(ID_SAVE_LAYOUT, _("Save"));

	wxMenu * viewMenu = new wxMenu;
	viewMenu->Append(wxID_ANY, _("Toolbars"), toolbarsMenu);
	viewMenu->Append(wxID_ANY, _("Layout"), layoutMenu);
	viewMenu->AppendCheckItem(ID_TOGGLE_INFO_TREE, _("Tree"));
	viewMenu->AppendCheckItem(ID_TOGGLE_STATUSBAR, _("Status Bar"));
	

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

	menuBar->Append(fileMenu, _("File"));
	menuBar->Append(viewMenu, _("View"));
	menuBar->Append(helpMenu, _("Help"));
	
	m_Manager.SetManagedWindow(this);

	CreateStatusBar();
	CreateStdToolBar();
	CreateAddToolBar();
	CreateInfoTree();
	
	m_Notebook = new wxAuiNotebook(this, ID_NOTEBOOK, wxDefaultPosition, 
		wxSize(600, 450), wxAUI_NB_DEFAULT_STYLE|wxNO_BORDER);
	m_Page1 = new wxPanel(m_Notebook, wxID_ANY);
	m_Page2 = new wxPanel(m_Notebook, wxID_ANY);
	m_Notebook->AddPage(m_Page1, _("Page1"));
	m_Notebook->AddPage(m_Page2, _("Page2"));

	m_Manager.AddPane(m_Notebook, wxAuiPaneInfo().CenterPane());
	m_Manager.AddPane(m_StdToolBar, wxAuiPaneInfo().ToolbarPane().
		Name(wxT("Standard Toolbar")).Top().Floatable(false));
	m_Manager.AddPane(m_AddToolBar, wxAuiPaneInfo().ToolbarPane().Left().Layer(2).
		Name(wxT("Additional Toolbar")).GripperTop().Floatable(false));
	m_Manager.AddPane(m_InfoTree, wxAuiPaneInfo().Left().Layer(1).PinButton().
		MinimizeButton().MaximizeButton().
		Name(wxT("Information")).Caption(wxT("Information")));

	m_Manager.Update();
}

void DockingWindowsSampleMainFrame::CreateStdToolBar()
{	
	m_StdToolBar = new wxToolBar(this, wxID_ANY, wxDefaultPosition,
		wxDefaultSize, wxBORDER_NONE|wxTB_HORIZONTAL|wxTB_NODIVIDER|wxTB_FLAT);
	m_StdToolBar->SetToolBitmapSize(wxSize(16, 15));
	m_StdToolBar->AddTool(wxID_NEW, _("New"), wxBitmap(new_xpm));
	m_StdToolBar->AddTool(wxID_OPEN, _("Open"), wxBitmap(fileopen_xpm));
	m_StdToolBar->AddTool(wxID_SAVE, _("Save"), wxBitmap(filesave_xpm));
	m_StdToolBar->AddSeparator();
	m_StdToolBar->AddTool(wxID_ABOUT, _("About..."), wxBitmap(htmfoldr_xpm));
	m_StdToolBar->Realize();
}

void DockingWindowsSampleMainFrame::CreateAddToolBar()
{
	m_AddToolBar = new wxToolBar(this, wxID_ANY, wxDefaultPosition,
		wxDefaultSize, wxBORDER_NONE|wxTB_NODIVIDER|wxTB_FLAT|wxTB_VERTICAL);
	m_AddToolBar->SetToolBitmapSize(wxSize(16, 15));
	m_AddToolBar->AddTool(wxID_CUT, _("Cut"), wxBitmap(cut_xpm));
	m_AddToolBar->AddTool(wxID_COPY, _("Copy"), wxBitmap(copy_xpm));
	m_AddToolBar->AddTool(wxID_FIND, _("Find"), wxBitmap(find_xpm));
	m_AddToolBar->Realize();
}

void DockingWindowsSampleMainFrame::CreateInfoTree()
{
	m_InfoTree = new wxTreeCtrl(this, ID_INFO_TREE, wxDefaultPosition, wxSize(170, 250),
		wxTR_HAS_BUTTONS|wxTR_LINES_AT_ROOT|wxTR_SINGLE);
	wxTreeItemId root = m_InfoTree->AddRoot(_("Document"));
	m_InfoTree->AppendItem(root, _("Item 1"));
	m_InfoTree->AppendItem(root, _("Item 2"));
	m_InfoTree->AppendItem(root, _("Item 3"));
	m_InfoTree->Expand(root);
}

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

bool DockingWindowsSampleMainFrame::GetPaneVisibility(wxString pane_name)
{
	wxAuiPaneInfoArray& all_panes = m_Manager.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 DockingWindowsSampleMainFrame::TogglePaneVisibility(wxString pane_name)
{
	wxAuiPaneInfoArray& all_panes = m_Manager.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_Manager.Update();
			break;
		}
	}
}

void DockingWindowsSampleMainFrame::OnToggleStdToolbarUpdateUI(wxUpdateUIEvent & event)
{
	event.Check(GetPaneVisibility(wxT("Standard Toolbar")));
}

void DockingWindowsSampleMainFrame::OnToggleAddToolbarUpdateUI(wxUpdateUIEvent & event)
{
	event.Check(GetPaneVisibility(wxT("Additional Toolbar")));
}

void DockingWindowsSampleMainFrame::OnToggleInfoTreeUpdateUI(wxUpdateUIEvent & event)
{
	event.Check(GetPaneVisibility(wxT("Information")));
}

void DockingWindowsSampleMainFrame::OnToggleStatusbarUpdateUI(wxUpdateUIEvent & event)
{
	event.Check(GetStatusBar() != NULL);
}

void DockingWindowsSampleMainFrame::OnToggleStdToolbar(wxCommandEvent & event)
{
	TogglePaneVisibility(wxT("Standard Toolbar"));
	m_Manager.Update();
}

void DockingWindowsSampleMainFrame::OnToggleAddToolbar(wxCommandEvent & event)
{
	TogglePaneVisibility(wxT("Additional Toolbar"));
	m_Manager.Update();
}

void DockingWindowsSampleMainFrame::OnToggleInfoTree(wxCommandEvent & event)
{
	TogglePaneVisibility(wxT("Information"));
	m_Manager.Update();
}

void DockingWindowsSampleMainFrame::OnToggleStatusbar(wxCommandEvent & event)
{
	wxStatusBar * statusBar = GetStatusBar();
	if(statusBar != NULL)
	{
		SetStatusBar(NULL);
		statusBar->Destroy();
	}
	else
	{
		CreateStatusBar();
	}
	m_Manager.Update();
}

Как видно из исходного кода, основной функционал, связанный с отображением/скрытием плавающих панелей обеспечивается методами DockingWindowsSampleMainFrame::GetPaneVisibility и DockingWindowsSampleMainFrame::TogglePaneVisibility. В качестве параметра мы передаем имя плавающей панели, далее выполняется поиск панели с указанным именем, и производятся необходимые действия. Список панелей можно получить с помощью метода wxAuiFrameManager::GetAllPanes.
Из такого вида формы

Сделайте мне красиво - Часть I - Знакомство с wxAUI

вот такой

Сделайте мне красиво - Часть I - Знакомство с wxAUI

Существует также возможность задания позиции панели на форме (положение в ряду и номер ряда).
Номер позиции в ряду задается методом wxAuiPaneInfo::Position, а номер ряда методом wxAuiPaneInfo::Layer.
Например, для указания того, что дополнительная панель инструментов должна находиться на первой позиции, а главная панель инструментов – на второй в первом ряду, нам необходимо при создании панелей использовать следующий код:

MainFrame.cpp

m_Manager.AddPane(m_StdToolBar, wxAuiPaneInfo().ToolbarPane().
		Name(wxT("Standard Toolbar")).Top().Position(2).Floatable(false));
	m_Manager.AddPane(m_AddToolBar, wxAuiPaneInfo().ToolbarPane().Top().Position(1).
		Name(wxT("Additional Toolbar")).Floatable(false));
	m_Manager.AddPane(m_InfoTree, wxAuiPaneInfo().Left().Layer(1).PinButton().
		MinimizeButton().MaximizeButton(). Name(wxT("Information")).Caption(wxT("Information")));

Библиотека wxAUI предоставляет возможность сохранения и загрузки общего расположения панелей. Общее расположение панелей называется перспективой (Perspective).
Для получения настроек расположения панелей используется метод wxAuiFrameManager::SavePerspective, а для установки – метод wxAuiFrameManager::LoadPerspective.

Давайте добавим в наш пример возможность загрузки и сохранения перспектив.

MainFrame.h

...
class DockingWindowsSampleMainFrame : public wxFrame
{
	...
	void LoadLayout(wxString filename);
	void SaveLayout(wxString filename);
public:
	...
	DECLARE_EVENT_TABLE()
	...
	void OnLoadLayout(wxCommandEvent & event);
	void OnSaveLayout(wxCommandEvent & event);
	...

};
...

MainFrame.cpp

...
#include 
#include 
...
BEGIN_EVENT_TABLE(DockingWindowsSampleMainFrame, wxFrame)
...
EVT_MENU(ID_LOAD_LAYOUT, DockingWindowsSampleMainFrame::OnLoadLayout)
EVT_MENU(ID_SAVE_LAYOUT, DockingWindowsSampleMainFrame::OnSaveLayout)
...
END_EVENT_TABLE()
...
void DockingWindowsSampleMainFrame::OnLoadLayout(wxCommandEvent & event)
{
	wxFileDialog dlg(this, wxT("Choose a file"), wxEmptyString, wxEmptyString,
		wxT("wxAUI Layout (*.layout)|*.layout"), wxFD_OPEN);
	if(dlg.ShowModal() == wxID_OK)
	{
		LoadLayout(dlg.GetPath());
	}
}

void DockingWindowsSampleMainFrame::OnSaveLayout(wxCommandEvent & event)
{
	wxFileDialog dlg(this, wxT("Choose a file"), wxEmptyString, wxEmptyString,
		wxT("wxAUI Layout (*.layout)|*.layout"), wxFD_SAVE);
	if(dlg.ShowModal() == wxID_OK)
	{
		SaveLayout(dlg.GetPath());
	}
}

void DockingWindowsSampleMainFrame::LoadLayout(wxString filename)
{
	if(!wxFileExists(filename)) return;
	wxFileInputStream stream(filename);
	if(!stream.Ok()) return;
	int cnt = stream.GetLength()/sizeof(wxChar);
	wxChar * tmp = new wxChar[cnt+1];
	stream.Read(tmp, stream.GetLength());
	tmp[cnt] = wxChar(0);
	wxString perspective(tmp);
	delete [] tmp;
	m_Manager.LoadPerspective(perspective);
}

void DockingWindowsSampleMainFrame::SaveLayout(wxString filename)
{
	wxString perspective = m_Manager.SavePerspective();	
	wxFileOutputStream stream(filename);
	if(!stream.Ok()) return;
	stream.Write(perspective.GetData(), perspective.Length()*sizeof(wxChar));
}

После сохранения, файл .layout будет содержать параметры всех панелей. Необходимо запомнить, что при внесении изменений в приложение, в случае, если некоторые панели біли удалены и больше не используются (в случаях, когда менеджер плавающих окон не содержит некоторых пенелей из .layout файла), такой .layout файл использовать нельзя.

Сделайте мне красиво - Часть I - Знакомство с wxAUI

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

Скачать исходный код примера к статье.

Leave a Reply

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

Please leave these two fields as-is: