このチュートリアルでは、Pythonでデスクトップアプリケーション用のグラフィカルユーザーインターフェイス(GUI)を開発するためのwxPythonライブラリの使用方法を学びます。GUIは、ユーザーがコマンドを入力することなくアプリケーションと対話できるようにするアプリケーションの部分であり、マウスをクリックするだけでほとんどすべてのことを行うことができます。
GUIを開発するためのPythonの代替ソフトにはTkinterやpyqtなどがありますが、このチュートリアルではwxPythonについて学びます。
先に進む前に、このチュートリアルにはいくつかの前提条件があります。Pythonの構文の基本的な理解、および/または、他の言語で少なくとも初級レベルのプログラミングをしたことがあることです。これらの条件を満たしていなくても、このチュートリアルに従うことはできますが、いくつかの部分が少し複雑であると感じるかもしれません。そのような場合は、コメントで説明を求めてください。
インストール
wxPythonのインストール方法は、使用するシステムによって多少異なりますが、かなり簡単です。
MacおよびWindows
WxPythonはpipパッケージマネージャを使ってMacとWindowsに簡単にインストールできます。pipがインストールされている場合、以下のコマンドを実行して、wxPythonをダウンロードし、インストールします。
$ pip install wxpython
Linux
Linuxの場合、インストールが必要な前提ライブラリが多いため、手順が少し面倒になる可能性があります。以下の2つのコマンドを順番に実行してみることをお勧めします。
# Command 1
$ sudo apt-get install dpkg-dev build-essential python2.7-dev python3.5-dev python3.6-dev libgstreamer-plugins-base1.0-dev libnotify-dev libwebkitgtk-3.0-dev libwebkit-dev libwebkitgtk-dev libjpeg-dev libtiff-dev libgtk2.0-dev libsdl1.2-dev libgstreamer-plugins-base0.10-dev freeglut3 freeglut3-dev
# Command 2
$ pip install --upgrade --pre -f https://wxpython.org/Phoenix/snapshot-builds/ wxPython
WxPythonのGithubリポジトリの “Prerequisites “セクションにライブラリのリストがありますので、手動でインストールしてください。
wxPythonでGUIを作成する例
このセクションでは、wxPythonで手を動かし、単語数のカウント、各単語の頻度の表示、最も繰り返される単語など、いくつかの基本的な機能を持つ基本的な文字列操作のアプリケーションを作成します。
先に進む前に、非常に簡単なスケルトン・アプリケーションを作成し、これを出発点として、次の例でより高度なGUI機能を実装していきます。
さて、さっそく始めましょう。以下は、wxPythonを使って作られたGUIアプリケーションの基本的なスケルトン(構造)です。次の節で、さらに機能を追加するために、オブジェクト指向になるように変更します。
import wx
# Creates an App object which runs a loop to display the
# GUI on the screen
myapp = wx.App()
# Initialises a frame that the user would be able to
# interact with
init_frame = wx.Frame(parent=None, title='Word Play')
# Display the initialised frame on screen
init_frame.Show()
# Run a loop on the app object
myapp.MainLoop()
もしループが実行されなかった場合(つまり app.MainLoop()
の呼び出し)、フレームは一瞬だけ画面に表示され、見ることができるようになる前に消えてしまうでしょう。この関数は、ユーザーがプログラムを終了するまで、フレームがスクリーン上に表示されたままであることを保証し、ループ内でフレームを実行することによってそれを実現します。
注:Macで実行する場合、ターミナルで python filename.py
コマンドを使用してコードを実行すると、次のエラーが発生します。
This program needs access to the screen. Please run with a Framework build of python, and only when you are logged in on the main display of your Mac.
これを取り除くには、上記のコマンドで python
の代わりに pythonw
を使用すればよいのです。
プログラムが実行されると、画面上に以下のような空白のウィンドウが表示されるはずです。
オブジェクト指向のコード
コードに機能を追加する前に、まず、クラスや関数を作ってモジュール化しましょう。そうすれば、見た目がすっきりして、拡張もしやすくなります。以下のコードの機能は以前と同じですが、オブジェクト指向プログラミングの概念を実装するためにリファクタリングされています。
import wx
import operator
# We make a class for frame, so that each time we
# create a new frame, we can simply create a new
# object for it
class WordPlay(wx.Frame):
def __init__(self, parent, title):
super(WordPlay, self).__init__(parent, title=title)
self.Show()
def main():
myapp = wx.App()
WordPlay(None, title='Word Play')
myapp.MainLoop()
main()
上のスクリプトでは、wxFrame
クラスを継承した WordPlay
クラスを作成しています。WordPlayクラスのコンストラクタは、2つのパラメータを受け取ります。parent
と title
です。子コンストラクタの内部では、wxPython
クラスの親クラスコンストラクタが呼び出され、parent
と title
属性が渡されます。最後に show
メソッドが呼び出され、フレームが表示されます。main()メソッドでは
WordPlay` クラスのオブジェクトを生成しています。
このように、コードはより構造化され、すっきりとしたものになりました。理解もしやすく、上記のコードにシームレスに機能を追加することができます。
機能追加
どの機能に対してどのコードパーツを追加するかという混乱を避けるために、一度に1つずつ機能を追加していきます。基本的なアプリケーションでは、テキストを追加できるテキストボックスと、テキストに含まれる単語の数、各単語の頻度などを計算し、その出力をアプリの画面に表示するためのいくつかのボタンが必要です。
まず、アプリにテキストボックスを追加して、テキストを追加してみましょう。
# Some of the code will be the same as the one above,
# so make sure that you understand that before moving
# to this part
import wx
import operator
# We make a class for frame, so that each time we create a new frame,
# we can simply create a new object for it
class WordPlay(wx.Frame):
def __init__(self, parent, title):
super(WordPlay, self).__init__(parent, title=title)
self.widgets()
self.Show()
# Declare a function to add new buttons, icons, etc. to our app
def widgets(self):
text_box = wx.BoxSizer(wx.VERTICAL) # Vertical orientation
self.textbox = wx.TextCtrl(self, style=wx.TE_RIGHT)
text_box.Add(self.textbox, flag=wx.EXPAND | wx.TOP | wx.BOTTOM, border=5)
grid = wx.GridSizer(5, 5, 10, 10) # Rows, columns, vertical gap, horizontal gap
text_box.Add(grid, proportion=2, flag=wx.EXPAND)
self.SetSizer(text_box)
def main():
myapp = wx.App()
WordPlay(None, title='Word Play')
myapp.MainLoop()
main()
ご覧のように、上記で widgets()
という名前の新しい関数を追加し、WordPlay
クラスのコンストラクタで呼び出しています。この関数の目的は、画面に新しいウィジェットを追加することです。しかし、私たちの場合は、1つのウィジェット、つまり、テキストを追加できるテキストボックスだけを追加することに興味があります。
この widgets()
関数の内部で起こっているいくつかの重要なことを理解しましょう。BoxSizer()メソッドは、その名前が示すように、ウィジェットのサイズとその位置(相対または絶対)を制御します。wx.VERTICAL
は、このウィジェットのオリエンテーションを垂直にすることを指定します。TextCtrlは基本的に、ユーザがテキストを入力するための小さなテキストボックスを現在の画面に追加します。GridSizer()
メソッドは、ウィンドウにテーブルのような構造を作成するために使用します。
さて、私たちのアプリケーションがどのように見えるか見てみましょう。
アプリケーションのウィンドウにテキストボックスが表示されました。
1つはテキストの単語数をカウントするボタン、もう1つは最も繰り返された単語を表示するボタンです。まず、2つのボタンを追加し、次に、ユーザーがどのボタンをクリックしたか、またテキストボックスに入力されたテキストを、入力に対して特定のアクションを実行できるようにするイベントハンドラをプログラムに追加します。
ボタンを追加するのはとても簡単で、「widgets」関数にいくつかのコードを追加するだけです。以下のコードブロックでは、更新されたwidgets関数を表示するだけで、他のコードは同じままです。
# Adding buttons to our main window
def widgets(self):
text_box = wx.BoxSizer(wx.VERTICAL)
self.textbox = wx.TextCtrl(self, style=wx.TE_RIGHT)
text_box.Add(self.textbox, flag=wx.EXPAND | wx.TOP | wx.BOTTOM, border=5)
grid = wx.GridSizer(2, 5, 5) # Values have changed to make adjustments to button positions
button_list = ['Count Words', 'Most Repeated Word'] # List of button labels
for lab in button_list:
button = wx.Button(self, -1, lab) # Initialise a button object
grid.Add(button, 0, wx.EXPAND) # Add a new button to the grid with the label from button_list
text_box.Add(grid, proportion=2, flag=wx.EXPAND)
self.SetSizer(text_box)
このように、メイン・ウィンドウに2つの新しいボタンが追加されました。
イベントハンドラの追加
あとは、ボタンがクリックされたときに特定のアクションを実行するためのイベントハンドラを追加するだけです。そのためには、新しい関数を作成し、ウィジェット関数に一行追加する必要があります。まずは、この関数を書いてみましょう。
# Declare an event handler function
def event_handler(self, event):
# Get label of the button clicked
btn_label = event.GetEventObject().GetLabel()
# Get the text entered by user
text_entered = self.textbox.GetValue()
# Split the sentence into words
words_list = text_entered.split()
# Perform different actions based on different button clicks
if btn_label == "Count Words":
result = len(words_list)
elif btn_label == "Most Repeated Word":
# Declare an empty dictionary to store all words and
# the number of times they occur in the text
word_dict = {}
for word in words_list:
# Track count of each word in our dict
if word in word_dict:
word_dict[word] += 1
else:
word_dict[word] = 1
# Sort the dict in descending order so that the
# most repeated word is at the top
sorted_dict = sorted(word_dict.items(),
key=operator.itemgetter(1),
reverse=True)
# First value in the dict would be the most repeated word
result = sorted_dict[0]
# Set the value of the text box as the result of our computation
self.textbox.SetValue(str(result))
最もよく繰り返される単語」機能のロジックは、まずすべての単語のリストから単語を繰り返し処理するループを実行します。そして、その単語がすでに辞書に存在するかどうかをチェックします。存在する場合は、その単語が繰り返されていることを意味し、その単語が再び現れるたびに値が1ずつ増加します。そうでない場合、その単語が辞書に存在しなければ、その単語が文中に初めて出現したことを意味し、その「出現」値は1に設定されるはずである。最後に、辞書を降順にソートして(Pythonのリストソートに似ています)、最も高い値(頻度)を持つ単語が上位に来るようにし、表示できるようにします。
さて、特定のボタンがクリックされたときに実行する必要のある計算とアクションを書いたので、そのアクションを特定のボタンに「バインド」してみましょう。そのためには、widgets
関数を少し修正する必要があります。
# Only one line needs to be added in the "for loop" of
# our widgets function, so that's all we're showing
for lab in button_list:
button = wx.Button(self, -1, lab)
self.Bind(wx.EVT_BUTTON, self.event_handler, button)
grid.Add(button, 0, wx.EXPAND)
上記のコードでは、self.Bind
の呼び出しがバインドを行う場所です。これは、特定のアクションを特定のボタンにリンクし、そのボタンをクリックすると、そのボタンにリンクされた特定のアクションが実行されるようにするものです。この場合、イベントハンドラ関数は一つしかなく、実行時に ‘label’ プロパティを通じてどのボタンがクリックされたかをチェックし、リンクされたアクションを実行することで、両方のアクションを処理します。そのため、self.Bind
の呼び出しで、すべてのボタンを単一の ‘event_handler’ 関数にバインドしています。
さて、これでコードは完成です。では、両方の機能を試して、期待通りに動くかどうか見てみましょう。
最初のステップでは、以下のように、テキストボックスに文字列を入力します。
次に、「Count Words」ボタンをクリックすると、文字列の中に7つの単語があるので、テキストボックスに「7」と表示されます。
ここまでは順調ですね。
では、次の図のように、テキストボックスに別の文字列を書き込んでみましょう。
ここで、「最も繰り返される単語」ボタンをクリックすると、下図のように、テキストボックス内に最も繰り返される単語とその出現頻度が表示されます。
これで完璧です。
今回は2つの機能しか追加していませんが、これらのコンポーネントがどのようにつながっているかをお見せすることが目的でしたので、必要な機能を追加していくことができます。さらに、このチュートリアルは見た目の美しさにはあまりこだわっていません。wxPythonには、ツールキットの基本的な知識を理解した上で、あなたのプログラムを美しくするための多くのウィジェットがあります。
結論
まとめとして、wxPythonはPythonでGUIベースのデスクトップアプリケーションを開発するためによく使われていること、そしてPythonには他にもいくつかのクールな代替手段があることを学びました。wxPythonをダウンロードし、すべての一般的なオペレーティングシステムにインストールするためのコマンドを学びました。最後に、このチュートリアルでは、基本的なスケルトンアプリをベースに、段階的に機能を追加していくことで、簡単に拡張できるwxPythonを使ったモジュール化されたアプリケーションを作る方法を学びました。