兎の真似をする烏

全力で"楽"である為に・人生が"面白く"ある為に

wxPythonでダイアログ生成をするには

やりたいこと

wxPythonにてダイアログを生成したい。
画面作成にはwxGladeを利用する。

親画面作成

ダイアログを呼び出すボタンと、ダイアログに入力された値を受け取るテキストエリアを設ける。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 0.9.9pre on Wed Oct 21 16:37:29 2020
#

import wx

# begin wxGlade: dependencies
# end wxGlade

# begin wxGlade: extracode
import main_dialog
# end wxGlade


class MainPanel(wx.Panel):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MainPanel.__init__
        kwds["style"] = kwds.get("style", 0)
        wx.Panel.__init__(self, *args, **kwds)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(sizer_1, 1, wx.EXPAND, 0)
        
        self.show_dialog_button = wx.Button(self, wx.ID_ANY, u"ダイアログ表示")
        self.show_dialog_button.SetFont(wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0, ""))
        sizer_1.Add(self.show_dialog_button, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(sizer_2, 1, wx.EXPAND, 0)
        
        text = wx.StaticText(self, wx.ID_ANY, u"結果", style=wx.ALIGN_CENTER)
        text.SetFont(wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0, ""))
        sizer_2.Add(text, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        
        self.result_text = wx.StaticText(self, wx.ID_ANY, "")
        self.result_text.SetFont(wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0, ""))
        sizer_2.Add(self.result_text, 5, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        
        self.SetSizer(sizer)
        
        self.Layout()

        self.Bind(wx.EVT_BUTTON, self.show_dialog, self.show_dialog_button)
        # end wxGlade

    def show_dialog(self, event):  # wxGlade: MainPanel.<event_handler>
        dialog = main_dialog.MainDialog(self, wx.ID_ANY, u'サンプル')
        result = dialog.ShowModal()
        if result == wx.ID_OK:
            self.result_text.SetLabel('入力内容:{}'.format(dialog.main_text.GetValue()))
        dialog.Destroy()

# end of class MainPanel

class MainFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MainFrame.__init__
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((800, 300))
        self.SetTitle(u"ダイアログテスト")
        
        self.main_panel = MainPanel(self, wx.ID_ANY)
        self.Layout()
        # end wxGlade

# end of class MainFrame

class MyApp(wx.App):
    def OnInit(self):
        self.main_frame = MainFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.main_frame)
        self.main_frame.Show()
        return True

# end of class MyApp

if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

ダイアログの表示と後処理を実行しているのは以下の部分。

    def show_dialog(self, event):  # wxGlade: MainPanel.<event_handler>
        dialog = main_dialog.MainDialog(self, wx.ID_ANY, u'サンプル')
        result = dialog.ShowModal()
        if result == wx.ID_OK:
            self.result_text.SetLabel('入力内容:{}'.format(dialog.main_text.GetValue()))
        dialog.Destroy()

dialog.ShowModal()をすることでダイアログを表示している。
また、ダイアログからの戻り値(wx.ID_OKやwx.ID_CANCEL)を受け取り、後処理(テキストエリアに結果を書き込む)を行う。

実際の画面イメージは以下の通り。

f:id:crowrabbit1212:20201021184613p:plain

子画面作成

任意の文字を入力できるようにする。
「OK」ボタンを押下することで、入力した任意の文字を親画面に反映する。
「CANCEL」ボタンを押下すると何も反映しない。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 0.9.9pre on Wed Oct 21 16:32:11 2020
#

import wx

# begin wxGlade: dependencies
# end wxGlade

# begin wxGlade: extracode
# end wxGlade


class MainDialog(wx.Dialog):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MainDialog.__init__
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_DIALOG_STYLE
        wx.Dialog.__init__(self, *args, **kwds)
        self.SetTitle(u"サンプル")
        
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
        
        self.main_text = wx.TextCtrl(self, wx.ID_ANY, "")
        self.main_text.SetFont(wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0, ""))
        sizer_2.Add(self.main_text, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_1.Add(sizer_3, 1, wx.EXPAND, 0)
        
        self.ok_button = wx.Button(self, wx.ID_OK, "OK")
        self.ok_button.SetFont(wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0, ""))
        sizer_3.Add(self.ok_button, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        
        self.cancel_button = wx.Button(self, wx.ID_CANCEL, "CANCEL")
        self.cancel_button.SetFont(wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0, ""))
        sizer_3.Add(self.cancel_button, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        
        self.Layout()
        # end wxGlade

# end of class MainDialog

class MyApp(wx.App):
    def OnInit(self):
        self.dialog = MainDialog(None, wx.ID_ANY, "")
        self.SetTopWindow(self.dialog)
        self.dialog.ShowModal()
        self.dialog.Destroy()
        return True

# end of class MyApp

if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

注意点としては、「OK」ボタンのIDをwx.ID_OKにして、「CANCEL」ボタンのIDをwx.ID_CANCELにすること。
このIDをwx.ID_ANYにするとダイアログは閉じない。

上記ソースにて、各ボタンの定義は以下のように記載している。

        self.ok_button = wx.Button(self, wx.ID_OK, "OK")
        self.cancel_button = wx.Button(self, wx.ID_CANCEL, "CANCEL")

実際の画面イメージは以下の通り。

f:id:crowrabbit1212:20201021184737p:plain

注意点

ダイアログが閉じられた際の戻り値は各ボタンで設定したwx.ID_OK(5100)やwx.ID_CANCEL(5101)が格納される。
このとき、ダイアログを「×」ボタンで閉じた場合は戻り値として何が返却されるか?

常識的に考えればwx.ID_CANCELと同様に 5101 が返却されると考えるが、想定通りの動きとなるのか?

「OK」ボタンと「CANCEL」ボタンがそれぞれ存在する場合

上記で示した例で実践してもらえれば確認できる。
この場合では想定通りの戻り値を得ることができることが分かる。

「OK」ボタンだけが存在する場合

ダイアログに「OK」ボタンだけが存在する場合はどのような動作になるかを確認する。
具体的には子画面のソースが以下のような例で考える。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 0.9.9pre on Wed Oct 21 18:37:50 2020
#

import wx

# begin wxGlade: dependencies
# end wxGlade

# begin wxGlade: extracode
# end wxGlade


class MainDialog(wx.Dialog):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MainDialog.__init__
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_DIALOG_STYLE
        wx.Dialog.__init__(self, *args, **kwds)
        self.SetTitle(u"サンプル")
        
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
        
        self.main_text = wx.TextCtrl(self, wx.ID_ANY, "")
        self.main_text.SetFont(wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0, ""))
        sizer_2.Add(self.main_text, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_1.Add(sizer_3, 1, wx.EXPAND, 0)
        
        self.ok_button = wx.Button(self, wx.ID_OK, "OK")
        self.ok_button.SetFont(wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, 0, ""))
        sizer_3.Add(self.ok_button, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10)
        
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        
        self.Layout()
        # end wxGlade

# end of class MainDialog

class MyApp(wx.App):
    def OnInit(self):
        self.dialog = MainDialog(None, wx.ID_ANY, "")
        self.SetTopWindow(self.dialog)
        self.dialog.ShowModal()
        self.dialog.Destroy()
        return True

# end of class MyApp

if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

実画面のイメージは以下の通り。

f:id:crowrabbit1212:20201021184752p:plain

この状態でダイアログを「×」ボタンで閉じた場合は戻り値としてwx.ID_OKと同じ5100を受け取る。
明確にキャンセルの処理を含めたいのであれば、明示的に「CANCEL」ボタンを作成する必要がある。