PlateButtonを試してみる

ボタン上に、画像と文字列を同時に表示させる方法を検討する。
画像か文字列のどちらか一方を表示させるのは、これまでの方法(http://d.hatena.ne.jp/Megumi221/20100211)で可能であることが分かった。でも同時に表示させている例はすぐには見当たらない。

起動するとこのような画面が開く(昔作った)コード(の一部)をベースに今回の改良を行う。以下はソース。

import wx

class MyApp(wx.PySimpleApp):
    def OnInit(self):
        width, height = 250, 150
        self.Frm = wx.Frame(None, -1, "wxPython", size=wx.Size(width, height))
        VSizer = wx.BoxSizer(wx.VERTICAL)
        
        self.TxtCtl1 = wx.TextCtrl(self.Frm, -1, "", size=(235,-1),
                                   style=wx.TE_RIGHT)
        
        self.Btn = wx.Button(self.Frm, -1, "check")
        self.Btn.Bind(wx.EVT_BUTTON, self.Decision)        
        VSizer.Add(self.TxtCtl1, 0, wx.ALL, 2)        
        VSizer.Add(self.Btn, 0, wx.ALL, 2)
        self.Frm.SetSizer(VSizer)
        self.Frm.Show()
        return True
        
    def Decision(self, event):
        print "pushed !"
        
app = MyApp()
app.MainLoop()

wxPythonデモの中から、画像と文字を同時に表示させているサンプルを探す。唯一、PlateButtonDemo.pyでやっているのを見つける。デモコードの説明文は以下の通り。

Editra Control Library: PlateButton
The PlateButton is a custom owner drawn flat button, that in many ways emulates the buttons found the bookmark bar of the Safari browser. It can be used as a drop in replacement for wx.Button/wx.BitmapButton under most circumstances. It also offers a wide range of options for customizing its appearance, a description of each of the main style settings is listed below.

あまりよく分からないが、普通のボタンよりきれいに表示できるのだな、きっと。
基本的にはwxButtonをコメントアウトして、代わりにPlateButtonとする。修正は簡単だ。下記のコードの通り修正した。適当なPNG画像を用意しておく。

import wx
import wx.lib.platebtn as platebtn

class MyApp(wx.PySimpleApp):
    def OnInit(self):
        width, height = 250, 150
        self.Frm = wx.Frame(None, -1, "wxPython", size=wx.Size(width, height))
        VSizer = wx.BoxSizer(wx.VERTICAL)
        
        self.TxtCtl1 = wx.TextCtrl(self.Frm, -1, "", size=(235,-1),
                                   style=wx.TE_RIGHT)
        # Button styles
        default = platebtn.PB_STYLE_DEFAULT
        gradient = platebtn.PB_STYLE_GRADIENT

        # plate button
        bImage = wx.Bitmap('test.png')
        self.Btn = platebtn.PlateButton(self.Frm, -1, "check", bImage, style=gradient)
        
        #self.Btn = wx.Button(self.Frm, -1, "check")
        self.Btn.Bind(wx.EVT_BUTTON, self.Decision)     #このままでは何も起こらず。   
        VSizer.Add(self.TxtCtl1, 0, wx.ALL, 2)        
        VSizer.Add(self.Btn, 0, wx.ALL, 2)
        self.Frm.SetSizer(VSizer)
        self.Frm.Show()
        return True
        
    def Decision(self, event):
        print "pushed !"
        
app = MyApp()
app.MainLoop()

起動すると、下のように表示される。背景の色を付けないとボタンかどうか判別できない状態だが、ちゃんと表示されている。

だが、なぜかボタンを押したときに何も起こらない。wxButtonのときにように、

self.Btn.Bind(wx.EVT_BUTTON, self.Decision)

としてはダメなようだ。こうではなく、

self.Bind(wx.EVT_BUTTON, self.Decision)  # これだと動作する。

とすると、ちゃんとイベントがself.Decisionに結び付くようだ。
ボタンが一つだけの場合には単純にこうすれば問題ないが、ボタンが複数あってそれぞれのイベントに伴い実行される処理が異なるときはちょっと面倒なことになる(自分が今までやってきた方法では、ボタン毎にBindを定義していたので)。どのボタンを押してもこの場合だとDecisionに飛ぶので、そこでどのボタンが押されたのかを判別して(ちゃんとボタンのIDを決めておけば、event.GetId()で判断できる)から場合分けをして、それぞれの処理を実行するようにする方法が考えられる。処理が2段階になってしまうが、しょうがないか。でもこの方がスマートかとも思う。デバッグがしやすいかな?