ブログ

Armadillo-640:デザイナツールを使用してwxPythonアプリケーション画面を作成する(wxFormBuilder)

at_takuma.fukuda
2020年11月2日 19時34分

Armadillo-640のLCD画面を使用するアプリケーションの構築手法として、wxPythonを何度かご紹介しています。 Armadillo640へのwxPython Phoenix(Python3に対応したwxPython)のインストール
Armadillo640へのwxPython Phoenixのインストール(eMMC使用)
Armadillo-640でwxWidgetsを使ってグラフを描画する(Python編)

この記事では、wxPythonコードを生成するデザイナツールを活用して、
さらに容易かつ効率的にアプリケーション画面を構築する方法をご紹介します。

デザイナツールの紹介

wxPythonに対応したデザイナツールは複数ありますが、
その中でもwxFormBuilderwxGladeは比較的知名度が高いようで、
webで情報収集がしやすいように見受けられます。

この記事ではwxFormBuilderを利用してアプリケーション画面を構築してみました。
wxFormBuilderではデザイナで直感的に画面を構築し、wxWidgetsのコードを生成することが出来ます。

wxFormBuilderのインストール

下記から各OS向けのインストーラをダウンロードできます。
GitHub:wxFormBuilder / wxFormBuilder
2020/11/9時点では、Windows 10、バージョン 1909、64bitにてインストール、動作可能でした。

wxFormBuilderによる画面構築

ウインドウの作成

wxFormBuilderを起動すると以下のような画面が表示されます。

「name」「file」は自由に設定できますが、生成されるファイル名やライブラリ名となるので、
シンプルかつ分かりやすいものを設定しましょう。

「code_generation」はこのデザイナで作成した画面から構築するコードの言語を選択することが出来ます。
デフォルト設定では「C++」となっていますので、「Python」と入力して下さい。
*このとき、先頭のPを大文字にしないと入力が受け付けられないので注意してください。

次に画面の基礎となるFrameを設置します。
Formsタブを選択して、表示されたアイコンからFrameを選択すると、Frameが追加されます。
ここで画面サイズの入力が可能となるので、「size」欄に「横;縦」のサイズを入力して下さい
ここまででウインドウの基礎が出来上がります。

画面部品の配置

ここから、ウインドウ上に部品を配置していきます。
今回は、下記のようにボタン操作とタイマによってCPU使用率とメモリ使用率を表示するアプリケーションを構築したいと思います。

wxFormBuilderでウインドウ上に部品を配置する際には、
Sizerを使って画面を区切り、その上に配置する部品の数を設定します。
今回は左端にボタンを3つ、その右にテキストを2つ配置するので、
まずLayoutタブを選択してFlexGridSizerをFrameの上に設置して列数を2に設定します。

さらにBoxSizerを2つFlexSizerの上に設置します。

Commonタブを選択して、一つ目のBoxSizerの上にButtonを設置します。
この時、"label"にボタン上に表示して欲しい文字列を入力します。

Eventsタブを選択して、"OnButtonClick"にボタンクリック時に実行する関数名(任意)を入力します。
関数の内容定義は後で行うため、ここでは任意の関数名を入力するだけで問題ありません。

さらにButtonを2つ追加し、labelやOnButtonClickを設定します。

もう一つのBoxSizerにStaticTextを2つ設置してください。

Additionalタブを選択して、Frame直上にTimerを設置してください。

"period"にms単位で実行間隔を入力して下さい。また、今回は起動直後からタイマを作動させたいので、
"enabled"にチェックを入れてください

Eventsタブを選択して、"OnTimer"にタイマーで実行させたい関数の関数名を入力して下さい。

ここまでで画面構成の設定は完了です。

wxPythonコードの生成

"Generate Code"アイコンをクリックしてください。
プロジェクト全体のクラスを定義したpythonファイルが作成されます。

メニューの"Tools"→"Generate Inherited Class"を選択してください。

作成したFrameにチェックを入れて、OKを選択してください。

これで必要な2ファイルが生成されました。
例えばプロジェクト名が"MyProject1"、"file"が"Test"、Frarmeの名前が"MyFrame1"であれば、
Test.pyとMyProject1MyFrame1.pyが生成されます。

生成されたpythonファイルを使ってアプリケーションを完成させます。

実行ファイルの作成

作成したFrameを呼び出して表示する実行ファイルを作成します。
ファイル名はmain.pyとします。

import wx
from MyProject1MyFrame1 import MyProject1MyFrame1
 
if __name__ == '__main__':
    app = wx.App(False)
    frame = MyProject1MyFrame1(None)
    frame.Show(True)
    app.MainLoop()

Armadillo上での表示確認

Test.py、MyProject1MyFrame1.py、main.pyの3つのファイルを、Armadillo-640の同じディレクトリにコピーします。
wxPython Phoenixインストール済みであれば、以下のコマンドでアプリケーション画面が表示されます。

[armadillo ~]# DISPLAY=:0 python3 main.py

画面は表示されますが関数の定義がまだされていないので、ただボタンとテキストが表示されるだけです。

関数の実装

関数の定義は、Frameのファイル(MyProject1MyFrame1.py)にて行います。
このファイルを開くと、以下の様な個所があります。

""Subclass of MyFrame1, which is generated by wxFormBuilder."""
(中略)
    # Handlers for MyFrame1 events.
    def text1labelchange( self, event ):
        # TODO: Implement text1labelchange
        pass
 
    def text2labelchange( self, event ):
        # TODO: Implement text2labelchange
        pass
 
    def StartStop( self, event ):
        # TODO: Implement StartStop
        pass
 
    def paint( self, event ):
        # TODO: Implement paint
        pass

生成された段階では、各関数の内部処理はpassとだけ定義されています。
passを削除して必要な処理を記述します。
CPUとメモリの使用率を取得には、psutilライブラリを使用します。
それぞれ必要な処理を記入すると以下のようになります。

"""Subclass of MyFrame1, which is generated by wxFormBuilder."""
 
import wx
import Test
import psutil
 
# Implementing MyFrame1
class MyProject1MyFrame1( Test.MyFrame1 ):
        def __init__( self, parent ):
                Test.MyFrame1.__init__( self, parent )
 
        # Handlers for MyFrame1 events.
#CPUの使用率を取得してstaticText1のlabelに反映する処理
        def text1labelchange( self, event ):
                # TODO: Implement text1labelchange
#CPU使用率取得
                cpu=psutil.cpu_percent()
#浮動小数を文字列へ変換
                label=str(cpu)
#SetLabel関数を使用してlabelへ反映
                self.m_staticText1.SetLabel(label)
 
#メモリーの使用率を取得してstaticText2のlabelに反映する処理(上と同じ部分は解説割愛)
        def text2labelchange( self, event ):
                # TODO: Implement text2labelchange
#メモリ使用率取得
                mem=psutil.virtual_memory()
                label=str(mem.percent)
                self.m_staticText2.SetLabel(label)
#startボタン(stopボタン)を押した際の、タイマーのスタートストップとボタンのlabel変更処理
        def StartStop( self, event ):
                # TODO: Implement StartStop
#タイマが動作しているとき
                if self.m_timer1.IsRunning():
#タイマを止める
                        self.m_timer1.Stop()
#タイマのlabelをStartに変更
                        self.m_button13.SetLabel('Start')
#タイマが動作していないとき
                else:
#タイマを動かす
                        self.m_timer1.Start(500)
#タイマのlabelをStopに変更
                        self.m_button13.SetLabel('Stop')
#タイマー処理で一定間隔ごとにCPU使用率、メモリ使用率を取得してテキストのlabelに反映する
#ボタン押下時の処理と同じなので解説は割愛
        def paint( self, event ):
                # TODO: Implement paint
                cpu=psutil.cpu_percent()
                label=str(cpu)
                self.m_staticText1.SetLabel(label)
                mem=psutil.virtual_memory()
                label=str(mem.percent)
                self.m_staticText2.SetLabel(label)

以上のように変更した上で、再度main.pyを実行すると、タイマー処理やボタン操作が可能となります。