Categories: wxWidgets

Сделайте мне красиво – Часть 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 <wx/wx.h>
#include <wx/textctrl.h>
#include <wx/aui/aui.h>
#include <wx/aui/tabmdi.h>

#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 <wx/aboutdlg.h>

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;
  }
 }
}
&#91;/sourcecode&#93;

<b>AUIDocViewApp.h</b>
[sourcecode language="cpp"]
#ifndef _AUI_DOCVIEW_APP_H
#define _AUI_DOCVIEW_APP_H

#include <wx/wx.h>

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

DECLARE_APP(AUIDocViewApp);

#endif

AUIDocViewApp.cpp

#include "AUIDocViewApp.h"
#include "AUIDocViewMainFrame.h"
#include <wx/image.h>

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;
}


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

AUIDocViewChildFrame.h

#ifndef _AUI_DOCVIEW_CHILDFRAME_H
#define _AUI_DOCVIEW_CHILDFRAME_H

#include <wx/wx.h>
#include <wx/toolbar.h>
#include <wx/aui/tabmdi.h>

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().
Вот так будет выглядеть наше приложение после внесения всех изменений.

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

Но это еще не все. Существует интересная возможность смены интерфейса закладок в 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 <wx/aboutdlg.h>

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, необходимые для того, чтобы маркер активного скина корректно отображался в меню.
После всего сделанного, мы должны получить вот приблизительно такой результат.

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

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

AUIDocViewChildFrame.h

#ifndef _AUI_DOCVIEW_CHILDFRAME_H
#define _AUI_DOCVIEW_CHILDFRAME_H

#include <wx/wx.h>
#include <wx/toolbar.h>
#include <wx/treectrl.h>
#include <wx/aui/tabmdi.h>

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);
...
}

Теперь у нас должно получиться что-то типа этого:

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

Исходный код примеров:
Пример 1 (VS 2005)
Пример 2 (VS 2005 – Windows|Eclipse – Linux)

T-Rex

View Comments

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

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

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

Share
Published by
T-Rex

Recent Posts

Разработка кроссплатформенных модульных приложений на C++ с библиотекой wxWidgets

Введение Уже долгое время не пишу статьи о разработке, хотя сам процесс написания мне очень…

10 years ago

wxWidgets App With Plugins (Windows/Linux/Mac) – Sample Source Code

I can see that there is still a lot of topics at wxWidgets forums related…

11 years ago

wxToolBox is Now Open-Source!

I've just published the source code of wxToolBox component and a couple of sample apps at…

11 years ago

Microsoft Kinect Helper Library and Sample for wxWidgets

Microsoft released their Kinect SDK several days ago. So, for those wxWidgets developers who are…

13 years ago

wxJSON 1.1.0 Released

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to…

14 years ago

wxRuby. Оно даже работает!

Вдохновленнный читаемой нынче книгой My Job Went to India: 52 Ways to Save Your Job…

15 years ago