2018/03/05

wxPython & XRC でパネルを動的追加する方法 with Two Stage Creation

先日書いた [wxPython でパネルを動的追加する方法 | 穀風](https://kokufu.blogspot.com/2018/03/wxpython.html) を Two Stage Creation を使って実装し直しました。

> Two Stage Creation については、以下を参考にしてください
>
> - [wxPython Project Phoenix Migration Guide — wxPython Phoenix 4.0.1 documentation](https://docs.wxpython.org/MigrationGuide.html#phase-create)
> - [XRC and two stage creation in Phoenix - Google グループ](https://groups.google.com/forum/#!topic/wxpython-users/KNCAAYJKpQU)
> - [Phoenix compatibility in pywxrc by acolomb · Pull Request #726 · wxWidgets/Phoenix](https://github.com/wxWidgets/Phoenix/pull/726/files)
> - [wxPython & XRC で Custom Frame を作る方法3種 | 穀風](https://kokufu.blogspot.com/2018/03/wxpython-xrc-custom-frame-3.html)

作成したサンプルは、前回と同様、ラベルとボタンが一つずつあるだけのシンプルなもので、ボタンをクリックすると自パネルの背景が変わるというお遊びつきです全く役に立たない!
以下が XRC ファイルです。1つの XRC ファイルの中に複数のトップレベルウィンドウを定義しているところがポイントです。
```xml `title: "gui.xml"; highlight: [3, 21]; <?xml version="1.0" ?> <resource>   <object class="wxFrame" name="myFrame">     <object class="wxBoxSizer">       <orient>wxVERTICAL</orient>       <object class="sizeritem">         <object class="wxBoxSizer">           <object class="sizeritem">             <object class="wxButton" name="button">               <label>Add Panel</label>             </object>             <flag>wxALIGN_CENTRE_VERTICAL</flag>           </object>           <orient>wxHORIZONTAL</orient>         </object>         <option>1</option>         <flag>wxALIGN_CENTRE_HORIZONTAL</flag>       </object>     </object>   </object> <object class="wxPanel" name="myPanel"> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <object class="wxBoxSizer"> <object class="sizeritem"> <object class="wxStaticText" name="text"/> </object> <object class="sizeritem"> <object class="wxButton" name="button2"> <label>Click me!</label> </object> </object> <orient>wxHORIZONTAL</orient> </object> <option>1</option> <flag>wxALIGN_CENTRE_HORIZONTAL</flag> </object> </object> </object> </resource> ``` Python コードでは、各トップレベル Window を実装します。 `__res` を global に置き、1度 `gui.xrc` を読みこむだけで、2つのクラスのリソースが使えるようになっている点に注意してください。 このように、XRC ファイルと Python ファイルを1対1対応にし、1つのファイル内に複数のクラスを持たせるのが wxPython の方針公式の XRC エディタ xrced でサンプルコードを生成すると、こういう実装になりますのようです多分、 Python ぽくもある。 また、`Add()` でパネルを追加した後、`Layout()` を読んで再描画する必要がある点にも注意してください。 これを行わないと、ウィンドウサイズが変わるなどの再描画イベントが走るまで表示が崩れてしまいます。 > Two Stage Creation を XRC で使用する方法は以下を参考にしてください > > [wxPython & XRC で Custom Frame を作る方法3種 | 穀風](https://kokufu.blogspot.com/2018/03/wxpython-xrc-custom-frame-3.html) ```python `title: "gui.py"; highlight: 48; # -*- coding: UTF-8 -*- from random import randrange import wx import wx.xrc as xrc __res = None def get_resources(): global __res if __res is None: __init_resources() return __res def __init_resources(): global __res __res = xrc.XmlResource() __res.Load("gui.xrc") class MyFrame(wx.Frame): def pre_create(self): """ クラスの初期化時に呼ばれる関数 window の生成前に呼ぶべきカスタムセットアップを記述してください。 SetWindowStyle() や SetExtraStyle() 等。 """ pass def __init__(self, parent): wx.Frame.__init__(self) self.pre_create() get_resources().LoadFrame(self, parent, "myFrame") self.panels = [] button = xrc.XRCCTRL(self, "button") button.Bind(wx.EVT_BUTTON, self.on_click) def on_click(self, event): panel = MyPanel(self) panel.set_value(len(self.panels)) sizer = self.GetSizer() sizer.Add(panel, 1, wx.EXPAND) sizer.Layout() self.Fit() self.panels.append(panel) class MyPanel(wx.Panel): def pre_create(self): pass def __init__(self, parent=None): wx.Panel.__init__(self) self.pre_create() get_resources().LoadPanel(self, parent, "myPanel") self.text = xrc.XRCCTRL(self, "text") button = xrc.XRCCTRL(self, 'button2') button.Bind(wx.EVT_BUTTON, self.on_click) def set_value(self, value): self.text.SetLabel(str(value)) def on_click(self, event): # ボタンクリックで背景をランダムに変えるお遊び r = randrange(256) g = randrange(256) b = randrange(256) self.SetBackgroundColour([r, g, b]) ``` 実行例 ```python `title: "main.py"; #!/usr/bin/env python3 # -*- coding: UTF-8 -*- import wx from gui import MyFrame if __name__ == "__main__": app = wx.App(False) frame = MyFrame(None) frame.Show() app.MainLoop() ```

0 件のコメント: