Сегодня я хочу рассказать о таком полезном явлении в wxWidgets, как плавающие окна (Docking Windows). Со временем, каждого из нас посещает желание, так или иначе, сделать интерфейс своих программных продуктов более привлекательным и более удобным. Одним из способов достичь этого являются плавающие окна. Использование плавающих панелей инструментов, информационных и прочих панелей в приложении, позволяет настроить внешний вид программного продукта, которым вы пользуетесь очень часто, как говорится «под себя» и тем самым сделать работу с ним более комфортной. Эта возможность используется во многих современных приложениях и многие пользователи, сами того не замечая, уже давно привыкли к ней.
Итак, начнем наше знакомство…
Создадим простейшее приложение wxWidgets.
В настройках Application Type необходимо указать Windows Application, а в Additional Properties выставить флаг Empty Project
Добавим заголовочные файлы и файлы исходного кода в наше приложение
Всё, теперь можно писать код:
MainFrame.h
#ifndef _DOCKING_WINDOWS_SAMPLE_MAINFRAME_H #define _DOCKING_WINDOWS_SAMPLE_MAINFRAME_H #include <wx/wx.h> #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 <wx/wx.h> class DockingWindowsSampleApp : public wxApp { public: virtual bool OnInit(); }; DECLARE_APP(DockingWindowsSampleApp) #endif
App.cpp
#include "DockingWindowsSampleApp.h" #include "DockingWindowsSampleMainFrame.h" #include <wx/image.h> 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 <wx/wx.h> #include <wx/treectrl.h> #include <wx/aui/aui.h> #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.
Теперь наше приложение выглядит подобным образом.
Панели инструментов и плавающее дерево можно размещать в слева, справа, сверху или снизу от центральной панели (на которой находится wxAuiNotebook
). Центральная панель – это основная рабочая область приложения и она не может и не должна быть отстыкована от формы, ассоциированной с менеджером плавающих окон.
При перемещении плавающей панели с помощью мышки над областью, где возможна стыковка панели с главным окном, отображается полупрозрачный прямоугольник, показывающий область возможной стыковки.
Страницы нашего wxAuiNotebook
можно перетаскивать и размещать рядом друг с другм по горизонтали илм по вертикали
У каждой плавающей панели есть свойство, разрешающее или запрещающее отстыковку от главной формы. Отстыкованные панели (а также неотстыкованные, при условии установленного флага HasCloseButton()
) имеют кнопку закрытия, которая позволяет скрыть плавающую панель. При нажатии на кнопку закрытия, панель и связанный с ней компонент не удаляются, а становятся невидимыми (если не установлен флаг IsDestroyOnClose()
, который обеспечивает удаление панели и связанного с ней компонента при закрытии панели).
В нашем примере существует возможность скрытия плавающей панели с деревом, но нет возможности заново отобразить скрытую панель. Давайте исправим эту ситуацию. Добавим новый пункт меню и обработчик к нему, а также изменим свойства уже существующих пунктов меню 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
.
Из такого вида формы
вот такой
Существует также возможность задания позиции панели на форме (положение в ряду и номер ряда).
Номер позиции в ряду задается методом 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 <wx/filedlg.h> #include <wx/wfstream.h> ... 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 файл использовать нельзя.
Ну вот, для первого раза достаточно. В следующий раз расскажу о поддержке скинов библиотекой wxAUI и о возможностях настройки внешнего вида плавающих панелей.