PythonでGUIアプリの作成【kivy編】

はじめに

今回はPythonでGUIアプリの作成ということで、Python GUIフレームワークkivyをつかってデスクトップアプリを作っていこうと思います。

kivyとは?

kivyとはクロスプラットフォームなタッチ操作に対応したGUIアプリケーションを作成することのできるPythonフレームワークです。
特徴としては、kivyにはkv言語という独自言語とPythonを組み合わせることで、UIの見た目部分をkv言語で、動作部分をPythonで作成し、UIと動作ロジックを分けてアプリケーションを作成することができるという特徴を持っています。
kivyの基本的な使い方としてはkv言語を記載したkvファイルとPythonを組み合わせてアプリケーションを作成するのが基本ですが、kv言語をPython内に記述して作成することもできますし、Pythonのみで作成することも可能です。

サンプルコードのご紹介

今回はkv言語をPython内に記述(インライン)でのサンプルコードのご紹介をします。

以下、サンプル動画

上記の動画では、ボタンAを押すと、ボタンBの数値に1加算され、反対にボタンBを押すとボタンAの数値に2加算されるアプリのサンプルについて紹介しました。ボタンA、Bの値をリセットしたいは「ポップを開く」ボタンでポップアップを開き「リセット」ボタンを押すことで値がリセットされる仕組みになっています。

以下、pythonコード

# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.properties import NumericProperty, ListProperty
from kivy.lang import Builder
import japanize_kivy  # 日本語フォントを簡単に

KV = """
<MainWidget>:
    # 3つの角丸ボタンをFloatLayout上に配置
    RoundedButton:
        text: 'ポップを開く'
        size_hint: .3, .2
        pos_hint: {'x': .35, 'y': .2}
        on_press: root.open_popup()

    RoundedButton:
        id: btn_a
        text: 'A: 0'
        count: 0
        size_hint: .3, .2
        pos_hint: {'x': .1, 'y': .6}
        on_press: root.button_a_pressed()

    RoundedButton:
        id: btn_b
        text: 'B: 0'
        count: 0
        size_hint: .3, .2
        pos_hint: {'x': .6, 'y': .6}
        on_press: root.button_b_pressed()

<RoundedButton>:
    background_normal: ''
    background_down: ''
    background_color: 0, 0, 0, 0
    color: 1, 1, 1, 1
    font_size: self.height * 0.3
    canvas.before:
        Color:
            rgba: self.bg_color
        RoundedRectangle:
            pos: self.pos
            size: self.size
            radius: [12, 12, 12, 12]
"""

class RoundedButton(Button):
    count = NumericProperty(0)
    # デフォルト色(青)
    bg_color = ListProperty([91/255, 148/255, 228/255, 1])

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.bind(on_press=self.on_button_press)
        self.bind(on_release=self.on_button_release)

    def on_button_press(self, *args):
        # 押した瞬間:薄い水色
        self.bg_color = (0.6, 0.8, 1, 1)

    def on_button_release(self, *args):
        # 離したら元の青色に戻す
        self.bg_color = (91/255, 148/255, 228/255, 1)

class MainWidget(FloatLayout):
    def button_a_pressed(self):
        btn_b = self.ids.btn_b
        btn_b.count += 1
        btn_b.text = f'B: {btn_b.count}'

    def button_b_pressed(self):
        btn_a = self.ids.btn_a
        btn_a.count += 2
        btn_a.text = f'A: {btn_a.count}'

    def reset_counts(self, popup):
        self.ids.btn_a.count = 0
        self.ids.btn_a.text = "A: 0"
        self.ids.btn_b.count = 0
        self.ids.btn_b.text = "B: 0"
        popup.dismiss()

    def open_popup(self):
        content = FloatLayout()
        popup = Popup(
            title='リセットポップアップ',
            content=content,
            size_hint=(0.6, 0.4),
            auto_dismiss=False
        )

        reset_btn = RoundedButton(
            text='リセット',
            size_hint=(0.5, 0.3),
            pos_hint={'center_x': 0.5, 'center_y': 0.6}
        )
        reset_btn.bind(on_press=lambda *a: self.reset_counts(popup))
        content.add_widget(reset_btn)

        close_btn = RoundedButton(
            text='閉じる',
            size_hint=(0.5, 0.3),
            pos_hint={'center_x': 0.5, 'center_y': 0.2}
        )
        close_btn.bind(on_press=lambda *a: popup.dismiss())
        content.add_widget(close_btn)

        popup.open()

class MainApp(App):
    def build(self):
        Builder.load_string(KV)
        return MainWidget()

if __name__ == '__main__':
    MainApp().run()

簡単にソースの解説をしていきます。

まず、KVという変数に格納している文字列部分がkv言語になります。KVで指定した<MainWidget>や<RoundedButton>等のウィジェット(ボタンやラベル、レイアウトなどパーツのこと)はその下に記述しているPythonコードのクラスとリンクしており、KVで指定した見た目が反映されています。Pythonコードの方にはそのウィジェットで動かしたい処理を記載し、KVのon_pressやon_releaseなどのボタン押下検知イベントに記載することで動作します。また、もう一つの方法として、Pythonコードで押下検知イベントをbind(バインド)させてそこに動作させたい処理を記載した関数を渡す方法やkivyが提供しているButtonウィジェット等で定義されているon_pressやon_releaseをオーバライドして、ボタンを押したときの処理、離したときの処理を上書きする方法もあります。
今回のコードのメインの処理であるAボタンを押したときにBボタンの値を書き換える動作に関しては、各ボタンクラスのインスタンスに対してidを振っており、ボタンが押されたときに値を書き換えたいボタンのidを取得し、その中のtextパラメータを書き換えることで作成しています。

まとめ

以上、PythonでGUIアプリ作成【kivy編】でした。
GUIのアプリを作る方法としては様々な方法があると思いますが、タッチ操作にも対応したアプリケーションを作るとなると選択肢はかなり絞り込まれてくると思います。そうした中で、一つの選択肢として、Pythonを使ったGUI作成ツールとして、kivyを採用してみるというのはどうでしょうか?
Python自体、統計やAI、グラフの作成や組み込みなどにもよく使用される言語であることから、kivyを使いこなせばさらに応用のきいたGUIアプリを作成することもできるかもしれません。ぜひ挑戦してみて下さい。

よかったらシェアしてね!