2018/03/01

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

2018/3/5 追記
より使い勝手の良い方法があったので、そちらの方法で実装しなおしたバージョンを作りました。
[wxPython &XRC でパネルを動的追加する方法 with Two Stage Creation | 穀風](https://kokufu.blogspot.com/2018/03/wxpython-with-two-stage-creation.html)

Add Panel ボタンをクリックすると動的に MyPanel を追加するサンプルを作りました。

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

なお、MyPanelwxPython & XRC で Custom Frame を作る方法2種+α | 穀風 で紹介した方法で XRC から生成しています2

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

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
from random import randrange
 
import wx
import wx.xrc as xrc
 
 
class MyFrame(wx.Frame):
    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)
 
        self.panels = []
 
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self.sizer)
 
        # Add Panel ボタン
        button = wx.Button(self, label="Add Panel")
        button.Bind(wx.EVT_BUTTON, self.on_click)
        self.sizer.Add(button)
 
    def on_click(self, event):
        panel = MyPanel(self)
        panel.set_value(len(self.panels))
        self.sizer.Add(panel, 1, wx.EXPAND)
        self.sizer.Layout()
        self.panels.append(panel)
 
 
class MyPanel(wx.Panel):
    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)
 
        this_panel = self
 
        class MyPanelXmlHandler(xrc.XmlResourceHandler):
            def CanHandle(self, node):
                return self.IsOfClass(node, "wxPanel") and node.GetAttribute('name') == 'top'
 
            def DoCreateResource(self):
                self.CreateChildren(this_panel)
                return this_panel
 
        res = xrc.XmlResource('MyPanel.xrc')
        res.InsertHandler(MyPanelXmlHandler())
        res.LoadPanel(None, "top")
 
        self.text = xrc.XRCCTRL(self, 'text')
 
        self.button = xrc.XRCCTRL(self, 'button')
        self.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])
 
 
def main():
    app = wx.App(False)
 
    frame = MyFrame(None)
    frame.Show()
 
    app.MainLoop()
 
 
if __name__ == '__main__':
    main()
MyPanel.xrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" ?>
<resource>
  <object class="wxPanel" name="top">
    <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="button">
              <label>Click me!</label>
            </object>
          </object>
          <orient>wxHORIZONTAL</orient>
        </object>
        <option>1</option>
        <flag>wxALIGN_CENTRE_HORIZONTAL</flag>
      </object>
    </object>
  </object>
</resource>
  1. 全く役に立たない! 
  2. Frame も XRC から作れますが、今回は Panel が主役なのであえてコードで生成 
  3. むしろそれだけ 
?

0 件のコメント: