2018/03/05

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

先日書いた wxPython でパネルを動的追加する方法 | 穀風 を Two Stage Creation を使って実装し直しました。

Two Stage Creation については、以下を参考にしてください

作成したサンプルは、前回と同様、ラベルとボタンが一つずつあるだけのシンプルなもので、ボタンをクリックすると自パネルの背景が変わるというお遊びつきです1

以下が XRC ファイルです。1つの XRC ファイルの中に複数のトップレベルウィンドウを定義しているところがポイントです。

gui.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?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 の方針2のようです3

また、Add() でパネルを追加した後、Layout() を読んで再描画する必要がある点にも注意してください。 これを行わないと、ウィンドウサイズが変わるなどの再描画イベントが走るまで表示が崩れてしまいます。

Two Stage Creation を XRC で使用する方法は以下を参考にしてください

wxPython & XRC で Custom Frame を作る方法3種 | 穀風

gui.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# -*- 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])

実行例

main.py
1
2
3
4
5
6
7
8
9
10
11
12
#!/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()
  1. 全く役に立たない! 
  2. 公式の XRC エディタ xrced でサンプルコードを生成すると、こういう実装になります 
  3. 多分、 Python ぽくもある 
?

0 件のコメント: