🥝

Kivy入門(1) 画像・文字・ボタンで構成された画面を作成する

2024/10/03に公開

はじめに

このシリーズは、Kivyでしっかりしたアプリケーションを作る前に、簡単なツールを作って、Kivyの設計感覚をつかむことを目的としています。今回は、文字表示、画像表示、ボタン表示をおこないます。

Kivyではアプリケーション・文字・画像・ボタンなどをウィジェット(Widget)と呼び、配置するウィジェットのモジュールをimportする必要があります。アプリを作成する際に、アプリケーションのウィジェットは必ず必要です。

今回は用いませんが、アプリケーション内に複数のスクリーンを作りたい時(たとえば「スタート画面」と「メイン画面」などを分けたい時)は、スクリーンウィジェットと、スクリーンマネージャーをimportすることで実装できます。スクリーンウィジェットは名前の通りスクリーンを構築するために必要で、スクリーンマネージャーは複数のスクリーンの切り替えに使います。

実装の前の下準備

今回はアプリで画像を表示をします。何でもいいので、画像を一枚用意してください。もし手元に手ごろな画像がないよという場合は、以下の画像をダウンロードしてご使用ください。

ファイル名は「image.png」とし、pythonファイルと同じフォルダに保存します。

日本語化ライブラリのインストール

Kivyは日本語をサポートしていないので、日本語を正しく表示するために専用のライブラリが必要です。japanize-kivy は もみじあめ様が開発されたKivy日本語化のためのライブラリです。 pip からインストール可能です。

pip install japanize-kivy

あとは日本語を使うプログラムにインポートすればOKです。

さっそく実装!

それでは、お気に入りのエディタを起動し、以下のコードをコピペしてください。ファイルの名前は simple.py とします(他の名前でも問題ありません)。

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.image import Image
import japanize_kivy

class SimpleApp(App):
    def build(self):
        # 縦方向のレイアウトを作成
        layout = BoxLayout(orientation='vertical', padding=10, spacing=10)
        
        # テキストラベルの作成
        label = Label(text="Kivyでアプリだよ!", font_size='20sp')
        
        # 画像の作成 (image.pngを配置)
        image = Image(source='image.png')
        
        # ボタンの作成
        button = Button(text="終了", size_hint=(1, 0.2), font_size='20sp')
        
        # ボタンを押すとアプリを終了する動作を設定
        button.bind(on_press=self.stop_app)
        
        # レイアウトにウィジェットを追加
        layout.add_widget(label)
        layout.add_widget(image)
        layout.add_widget(button)
        
        return layout

    def stop_app(self, instance):
        # アプリを終了する
        App.get_running_app().stop()

# アプリの実行
if __name__ == '__main__':
    SimpleApp().run()

pyファイルの保存は出来たら、さっそく実行してみましょう。
コマンドプロンプトから以下のようにコマンドします。simple.pyの部分はご自分で命名したファイルの名称に変更してください。

python simple.py

正しく実行できましたか?

Kivyが正しく動作すると、以下のような画面が表示されます。

「終了」と書かれたボタンを押すと、アプリが終了します。

違う画像を用意して「image.png」の部分を修正してみたり、表示するテキストを変えてみたりして、動作を確認してみてください。

コードの解説

それでは今回のコードについて解説します。

まずは次の一連のライブラリのインポート部分です。
これらは全てKivyライブラリの各モジュールを使うために必要です。

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.image import Image

上から順番に
app モジュールから App クラスをインポート → アプリケーションを作成(必須)
uix.boxlayout モジュールから BoxLayout クラスをインポート → 画面レイアウトをBoxLayoutにする
uix.label モジュールから Label クラスをインポート  → ラベルを作成する
uix.button モジュールから Button クラスをインポート → ボタンを作成する
uix.image モジュールから Image クラスをインポート  → 画像を作成する

Label, Button, Imageというのはわかりやすいですが、レイアウトのライブラリって何を担当するのか、ピンと来ずらいかもしれません。

レイアウトに関してはまた別の記事を投稿する予定ですが、画面の表示向き(縦向き、横向き)や、画面にウィジェットをどのように配置するかを管理しています。今回使用したBoxLayoutは上から順番に、ウィジェットを追加していくスタイルです。

さて、このプログラムが実行されるとまず最初に以下の部分が実行されます。

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

if name == 'main': というのは、このプログラムが直接呼び出された時に、SimpleApp()を実行(run)する、ということを表しています。

SimpleApp().run()が実行されると、 class SimpleAppが呼び出されます。これは from kivy.app import App でimportした App のクラスです。

class SimpleApp(App):
    def build(self):
        # 縦方向のレイアウトを作成
        layout = BoxLayout(orientation='vertical', padding=10, spacing=10)
        
        # テキストラベルの作成
        label = Label(text="Kivyでアプリだよ!", font_size='20sp')
        
        # 画像の作成 (image.pngを配置)
        image = Image(source='image.png')
        
        # ボタンの作成
        button = Button(text="終了", size_hint=(1, 0.2), font_size='20sp')
        
        # ボタンを押すとアプリを終了する動作を設定
        button.bind(on_press=self.stop_app)
        
        # レイアウトにウィジェットを追加
        layout.add_widget(label)
        layout.add_widget(image)
        layout.add_widget(button)
        
        return layout

    def stop_app(self, instance):
        # アプリを終了する
        App.get_running_app().stop()

App クラスは、Kivyアプリケーションの基本的な構造を提供し、アプリケーション全体の管理やライフサイクル(アプリの開始や終了など)を担当します。

Kivyでアプリを作成するときは、通常この App クラスを継承したクラスを作成し、アプリの動作をカスタマイズします。具体的には、App クラスの build() メソッドをオーバーライドして、アプリのUI(ユーザーインターフェース)を定義します。

この App クラスは以下のような役割を果たします:

  • アプリケーションの開始と終了:
    アプリが開始される際に run() メソッドを呼び出し、アプリのウィンドウを表示し、イベントループを管理します。終了時には stop() メソッドが呼び出され、アプリを安全に終了させます。
  • UIの構築:
    build() メソッドを通じて、アプリのUIを定義します。このメソッドがアプリのウィジェットツリーを返します。

それでは、build()内を具体的に確認します。

 # 縦方向のレイアウトを作成
layout = BoxLayout(orientation='vertical', padding=10, spacing=10)

# テキストラベルの作成
label = Label(text="Kivyでアプリだよ!", font_size='20sp')

# 画像の作成 (image.pngを配置)
image = Image(source='image.png')

# ボタンの作成
button = Button(text="終了", size_hint=(1, 0.2), font_size='20sp')

# ボタンを押すとアプリを終了する動作を設定
button.bind(on_press=self.stop_app)

# レイアウトにウィジェットを追加
layout.add_widget(label)
layout.add_widget(image)
layout.add_widget(button)

return layout

まずは画面のレイアウトを設定する次のコードです。
layout = BoxLayout(orientation='vertical', padding=10, spacing=10)

Kivyでは画面を構成する際に、基底となるウィジェットが必要です。これをルートウィジェットといいます。今回はこの layout が担当し、layoutの上に label や image 、 button といった他のウィジェットを配置しています。ルートウィジェットの上に配置されるこれらのウィジェットたちを子ウィジェットと呼びます。

向き(orientation)を垂直(vertical)に、
padding は、レイアウト全体とその内側に配置された子ウィジェットとの間の余白、
spacing は、子ウィジェット同士の間の間隔を指します。

これらの設定で作成した BoxLayout のインスタンス変数が、layout です。

子ウィジェットたちの設定はこちらです。

label = Label(text="Kivyでアプリだよ!", font_size='20sp')
image = Image(source='image.png')
button = Button(text="終了", size_hint=(1, 0.2), font_size='20sp')

基本的に
インスタンス変数 = importしたクラス名(オプション1=設定値, オプション2=設定値, ...)
という書き方をします。これはBoxLayoutも一緒でした。

text(ウィジェットに表示する文字列)やfont_size(フォントの大きさ)など、
クラスによって共通するオプションもあれば、Imageクラスの source(表示する画像ファイル)など、
クラス独自の項目もあります。

今回は最低限のオプションを設定したのみですが、クラスごとにカスタマイズできるので、
機会があればクラスごとのオプションをご紹介します。

ボタンを押した際のイベントを設定するときは、bindメソッドを使います。

button.bind(on_press=self.stop_app)

ここでは、 on_press(ボタンを押した)時に self.stop_app を呼び出すと定義しています。
self.というのは、自身のクラス(ここでは SimpleApp)内にある要素であることを意味しています。

ボタンを押すと、SimpleApp内で定義したメソッド stop_appが呼び出されます。

def stop_app(self, instance):
    # アプリを終了する
    App.get_running_app().stop()

App.get_running_app().stop() で、アプリが停止します。

アプリの UI 配置が終了したら、定義した子ウィジェットをルートウィジェットに登録します。
それが次の部分です。

layout.add_widget(label)
layout.add_widget(image)
layout.add_widget(button)

return layout

ラベル(label)、画像(image)、ボタン(button)の各インスタンス変数が、画面レイアウトのインスタンス変数上に配置されました。

まとめ

次回は今回のプログラムを使って、ボタンを押すと画像やラベルの文字列が変わるような処理を実装します。

また、今回のアプリは各ウィジェットの配置が全体的にまとまりがなく不格好でした。ボタンの大きさを適切にしたり、ラベルの上下幅をテキストの量に応じて変えられたらいいですよね。今後はそのような方法についてもご紹介する予定です。

Kivyのアプリ作成の雰囲気は伝わったでしょうか?不明点やわかりずらい点があったら気軽にコメントいただけたら幸いです!

Discussion