wx.SplitterWindowをネストさせてみる

wx.SplitterWindowをどんどんネストして分割するクラスが欲しかったので書いてみた。
途中sizerがちゃんと使えてなくて頓挫寸前だった。
BoxSizerの場合

sizer.Add(client, 1, wx.Expand)

を基本として

sizer.Add(client, 0, wx.Expand)

と使い分けるべし。
sizerは便利でよろしいのだが、ちょっとした間違いがあってうまくいかない場合(SetSizerし忘れているとか、wx.Expandの指定がよろしくない)に、はまるポイントがあるような気がする。

# -*- coding: utf-8 -*-
# 入れ子になったsplitter
import wx


class NestSplitter(wx.Panel):
  """
  コンテキストメニュー
  """
  def __init__(self, parent, client, *args, **key):
    super(NestSplitter, self).__init__(parent, *args, **key)

    sizer = wx.BoxSizer(wx.VERTICAL)
    self.SetSizer(sizer)

    self.__init_popup_menu()
    self.Bind(wx.EVT_CONTEXT_MENU, self.__on_context_menu)

    self.client_class=client
    self.__client=self.client_class(self)
    sizer.Add(self.__client, 1, wx.EXPAND)

    self.splitter=None

  def __init_popup_menu(self):
    """
    split
      vertical
      horizontal
    """
    self.__popupIDSplit = wx.NewId()
    self.__popupIDSplitVertical = wx.NewId()
    self.__popupIDSplitHorizontal= wx.NewId()

    self.Bind(wx.EVT_MENU, self.__on_split, id=self.__popupIDSplitVertical)
    self.Bind(wx.EVT_MENU, self.__on_split, id=self.__popupIDSplitHorizontal)

  def __on_context_menu(self, event):
    if self.splitter:
      event.Skip()
      return

    menu = wx.Menu()

    # make a submenu
    sm = wx.Menu()
    sm.Append(self.__popupIDSplitVertical, "vertical")
    sm.Append(self.__popupIDSplitHorizontal, "horizontal")
    menu.AppendMenu(self.__popupIDSplit, "split", sm)

    self.PopupMenu(menu)
    menu.Destroy()

  def __on_split(self, event):
    self.__client.Destroy()


    splitter=wx.SplitterWindow(self)
    p1=self.__class__(splitter, self.client_class)
    p2=self.__class__(splitter, self.client_class)
    if event.GetId()==self.__popupIDSplitVertical:
      splitter.SplitVertically(p1, p2)
    else:
      splitter.SplitHorizontally(p1, p2)


    self.Bind(wx.EVT_SPLITTER_UNSPLIT, self.__on_unsplit)

    sizer=self.GetSizer()
    sizer.Add(splitter, 1, wx.EXPAND)
    self.SetSizer(sizer)

    # splitterのサイズを再計算する
    self.Layout()

    self.splitter=splitter

  def __on_unsplit(self, event):
    window=self.__get_leaf_window(self.splitter)
    self.client_class=window.client_class
    self.splitter.Destroy()
    self.splitter=None
    self.__client=self.client_class(self)
    self.GetSizer().Add(self.__client, 1, wx.EXPAND)
    self.Layout()

  def __get_leaf_window(self, splitter):
    window=splitter.GetWindow1()
    child_splitter=window.splitter
    if child_splitter:
      return self.__get_leaf_window(child_splitter)
    else:
      return window


class MyFrame(wx.Frame):
  def __init__(self, parent):
    super(MyFrame, self).__init__(parent)
    sizer=wx.BoxSizer(wx.VERTICAL)
    self.splitter=NestSplitter(self, client=wx.Panel)
    sizer.Add(self.splitter, 1, wx.EXPAND)
    self.SetSizer(sizer)


if __name__ == '__main__': 
  app = wx.PySimpleApp()
  frame = MyFrame(None)
  frame.Show()
  app.MainLoop()