0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kivyで学ぶPythonによるクロスプラットフォームGUIアプリケーション開発ガイド

Posted at

はじめに

Kivyは、Pythonで使用できるオープンソースのクロスプラットフォームGUIフレームワークです。デスクトップアプリケーションやモバイルアプリケーションの開発に適しており、タッチスクリーンデバイスにも対応しています。この記事では、Kivyの基本から応用まで、15章に分けて詳しく解説します。各章では、概念の説明と実際のコード例を交えながら、Kivyの魅力と可能性を探っていきます。

第1章: Kivyの基本

Kivyは、Pythonプログラマーがマルチタッチアプリケーションを簡単に作成できるようにするためのフレームワークです。OpenGLを使用して高速なグラフィックスを実現し、独自のウィジェットシステムを持っています。

まずは、基本的なKivyアプリケーションの構造を見てみましょう。

from kivy.app import App
from kivy.uix.label import Label

class MyFirstApp(App):
    def build(self):
        return Label(text='こんにちは、Kivy!')

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

このコードは、「こんにちは、Kivy!」というテキストを表示する最小限のKivyアプリケーションです。Appクラスを継承し、buildメソッドでUIを定義します。run()メソッドを呼び出すことで、アプリケーションが起動します。

第2章: ウィジェットの基本

Kivyのウィジェットは、ユーザーインターフェースの基本的な構成要素です。ボタン、ラベル、テキスト入力フィールドなど、様々な種類があります。

以下は、ボタンとラベルを使用した簡単な例です:

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

class WidgetExample(App):
    def build(self):
        layout = BoxLayout(orientation='vertical')
        self.label = Label(text='ボタンを押してください')
        button = Button(text='押してね')
        button.bind(on_press=self.on_button_press)
        layout.add_widget(self.label)
        layout.add_widget(button)
        return layout

    def on_button_press(self, instance):
        self.label.text = 'ボタンが押されました!'

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

このコードでは、垂直方向のBoxLayoutにラベルとボタンを配置しています。ボタンが押されると、ラベルのテキストが変更されます。

第3章: レイアウト

Kivyのレイアウトは、ウィジェットを画面上に配置する方法を定義します。主なレイアウトには、BoxLayout、GridLayout、FloatLayoutなどがあります。

以下は、GridLayoutを使用した例です:

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button

class GridLayoutExample(App):
    def build(self):
        layout = GridLayout(cols=3, rows=3)
        for i in range(9):
            btn = Button(text=str(i+1))
            layout.add_widget(btn)
        return layout

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

このコードは、3x3のグリッドに9つのボタンを配置します。GridLayoutのcolsrowsパラメータで、列数と行数を指定しています。

第4章: イベントとプロパティ

Kivyでは、イベントとプロパティを使用して、アプリケーションの動的な振る舞いを定義します。イベントは特定のアクションに反応し、プロパティは値の変更を追跡します。

以下は、カスタムプロパティとイベントを使用した例です:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.properties import NumericProperty

class CounterWidget(BoxLayout):
    count = NumericProperty(0)

    def __init__(self, **kwargs):
        super(CounterWidget, self).__init__(**kwargs)
        self.orientation = 'vertical'
        self.label = Label(text=str(self.count))
        self.btn = Button(text='カウントアップ')
        self.btn.bind(on_press=self.increment)
        self.add_widget(self.label)
        self.add_widget(self.btn)

    def increment(self, instance):
        self.count += 1
        self.label.text = str(self.count)

class CounterApp(App):
    def build(self):
        return CounterWidget()

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

このコードでは、NumericPropertyを使用してカウンターの値を管理し、ボタンのプレスイベントにincrementメソッドをバインドしています。

第5章: Kivy言語(KV言語)

KV言語は、Kivyアプリケーションのユーザーインターフェースを宣言的に定義するための特別な言語です。Pythonコードからユーザーインターフェースの定義を分離することができます。

以下は、KV言語を使用した例です:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout

class CounterWidget(BoxLayout):
    def increment(self):
        self.ids.counter_label.text = str(int(self.ids.counter_label.text) + 1)

class CounterApp(App):
    def build(self):
        return CounterWidget()

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

そして、以下のKVファイル(counter.kv)を作成します:

<CounterWidget>:
    orientation: 'vertical'
    Label:
        id: counter_label
        text: '0'
    Button:
        text: 'カウントアップ'
        on_press: root.increment()

KV言語を使用することで、UIの構造とスタイルをより直感的に定義できます。

第6章: グラフィックスとアニメーション

Kivyは、OpenGLを使用して高度なグラフィックスとアニメーションを実現します。Canvasを使用して図形を描画し、Animationクラスでアニメーションを作成できます。

以下は、簡単なアニメーションの例です:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle, Color
from kivy.animation import Animation

class AnimatedWidget(Widget):
    def __init__(self, **kwargs):
        super(AnimatedWidget, self).__init__(**kwargs)
        with self.canvas:
            Color(1, 0, 0, 1)  # 赤色
            self.rect = Rectangle(pos=self.pos, size=self.size)
        self.bind(pos=self.update_rect, size=self.update_rect)
        self.animate()

    def update_rect(self, *args):
        self.rect.pos = self.pos
        self.rect.size = self.size

    def animate(self):
        anim = Animation(pos=(100, 100), t='out_bounce', duration=1) + \
               Animation(size=(200, 200), t='out_bounce', duration=1)
        anim.start(self)

class AnimationApp(App):
    def build(self):
        return AnimatedWidget()

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

このコードは、赤い四角形を描画し、位置とサイズをアニメーションさせます。

第7章: 入力処理

Kivyは、マウス、キーボード、タッチスクリーンなど、様々な入力デバイスをサポートしています。以下は、タッチイベントを処理する例です:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse

class DrawingWidget(Widget):
    def on_touch_down(self, touch):
        with self.canvas:
            Color(1, 0, 0)  # 赤色
            d = 30.
            Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))

    def on_touch_move(self, touch):
        self.on_touch_down(touch)

class DrawingApp(App):
    def build(self):
        return DrawingWidget()

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

このアプリケーションでは、画面上をタッチまたはドラッグすると赤い点が描画されます。

第8章: スクリーンとスクリーンマネージャー

複数の画面を持つアプリケーションを作成する場合、ScreenとScreenManagerを使用します。以下は、2つの画面を切り替える例です:

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button

class FirstScreen(Screen):
    def __init__(self, **kwargs):
        super(FirstScreen, self).__init__(**kwargs)
        btn = Button(text='次の画面へ')
        btn.bind(on_press=self.change_screen)
        self.add_widget(btn)

    def change_screen(self, instance):
        self.manager.current = 'second'

class SecondScreen(Screen):
    def __init__(self, **kwargs):
        super(SecondScreen, self).__init__(**kwargs)
        btn = Button(text='前の画面へ')
        btn.bind(on_press=self.change_screen)
        self.add_widget(btn)

    def change_screen(self, instance):
        self.manager.current = 'first'

class ScreenManagerApp(App):
    def build(self):
        sm = ScreenManager()
        sm.add_widget(FirstScreen(name='first'))
        sm.add_widget(SecondScreen(name='second'))
        return sm

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

このアプリケーションでは、2つの画面を切り替えることができます。

第9章: データバインディング

Kivyのデータバインディングを使用すると、プロパティの値を自動的に更新できます。以下は、データバインディングの例です:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label

class BindingExample(BoxLayout):
    text_property = StringProperty('初期テキスト')

    def __init__(self, **kwargs):
        super(BindingExample, self).__init__(**kwargs)
        self.orientation = 'vertical'
        self.text_input = TextInput()
        self.label = Label(text=self.text_property)
        self.add_widget(self.text_input)
        self.add_widget(self.label)
        self.text_input.bind(text=self.on_text_change)

    def on_text_change(self, instance, value):
        self.text_property = value

class BindingApp(App):
    def build(self):
        return BindingExample()

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

このアプリケーションでは、テキスト入力フィールドの内容が自動的にラベルに反映されます。

第10章: ファイル入出力

Kivyアプリケーションでファイル入出力を行う方法を見てみましょう。以下は、テキストファイルを読み書きする例です:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button

class FileIOExample(BoxLayout):
    def __init__(self, **kwargs):
        super(FileIOExample, self).__init__(**kwargs)
        self.orientation = 'vertical'
        self.text_input = TextInput(text='ここにテキストを入力')
        self.save_button = Button(text='保存')
        self.load_button = Button(text='読み込み')
        self.add_widget(self.text_input)
        self.add_widget(self.save_button)
        self.add_widget(self.load_button)
        self.save_button.bind(on_press=self.save_text)
        self.load_button.bind(on_press=self.load_text)

    def save_text(self, instance):
        with open('saved_text.txt', 'w') as f:
            f.write(self.text_input.text)

    def load_text(self, instance):
        try:
            with open('saved_text.txt', 'r') as f:
                self.text_input.text = f.read()
        except FileNotFoundError:
            self.text_input.text = 'ファイルが見つかりません'

class FileIOApp(App):
    def build(self):
        return FileIOExample()

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

このアプリケーションでは、テキストを入力し、ファイルに保存したり、ファイルから読み込んだりすることができます。

第11章: ネットワーク通信

Kivyアプリケーションでネットワーク通信を行う方法を見てみましょう。以下は、簡単なHTTPリクエストを行う例です:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.network.urlrequest import UrlRequest

class NetworkExample(BoxLayout):
    def __init__(self, **kwargs):
        super(NetworkExample, self).__init__(**kwargs)
        self.orientation = 'vertical'
        self.button = Button(text='データを取得')
        self.label = Label(text='ここにデータが表示されます')
        self.add_widget(self.button)
        self.add_widget(self.label)
        self.button.bind(on_press=self.fetch_data)

    def fetch_data(self, instance):
        url = 'https://api.ipify.org?format=json'
        request = UrlRequest(url, on_success=self.got_json)

    def got_json(self, req, result):
        ip = result['ip']
        self.label.text = f'あなたのIPアドレス: {ip}'

class NetworkApp(App):
    def build(self):
        return NetworkExample()

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

このアプリケーションでは、ボタンを押すとWebAPIからIPアドレスを取得し、画面に表示します。UrlRequestを使用して非同期にHTTPリクエストを行っています。

第12章: マルチタッチとジェスチャー

Kivyは、マルチタッチデバイスに対応しており、複雑なジェスチャーを処理することができます。以下は、ピンチズームを実装する例です:

from kivy.app import App
from kivy.uix.scatter import Scatter
from kivy.uix.image import Image

class ZoomableImage(Scatter):
    def __init__(self, **kwargs):
        super(ZoomableImage, self).__init__(**kwargs)
        self.scale = 1
        self.do_rotation = False
        self.image = Image(source='path/to/your/image.jpg')
        self.add_widget(self.image)

    def on_touch_down(self, touch):
        if touch.is_mouse_scrolling:
            if touch.button == 'scrolldown':
                if self.scale < 10:
                    self.scale = self.scale * 1.1
            elif touch.button == 'scrollup':
                if self.scale > 0.5:
                    self.scale = self.scale * 0.9
        return super(ZoomableImage, self).on_touch_down(touch)

class ZoomApp(App):
    def build(self):
        return ZoomableImage()

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

このアプリケーションでは、画像をピンチジェスチャーでズームインやズームアウトできます。また、マウスのスクロールホイールでもズームが可能です。

第13章: カスタムウィジェットの作成

Kivyでは、既存のウィジェットを組み合わせたり、新しいウィジェットを作成したりすることができます。以下は、カスタムウィジェットの例です:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.properties import NumericProperty

class CounterWidget(BoxLayout):
    count = NumericProperty(0)

    def __init__(self, **kwargs):
        super(CounterWidget, self).__init__(**kwargs)
        self.orientation = 'vertical'
        self.label = Label(text=str(self.count))
        self.increment_button = Button(text='増加', on_press=self.increment)
        self.decrement_button = Button(text='減少', on_press=self.decrement)
        self.add_widget(self.label)
        self.add_widget(self.increment_button)
        self.add_widget(self.decrement_button)

    def increment(self, instance):
        self.count += 1
        self.update_label()

    def decrement(self, instance):
        self.count -= 1
        self.update_label()

    def update_label(self):
        self.label.text = str(self.count)

class CounterApp(App):
    def build(self):
        return CounterWidget()

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

このカスタムウィジェットは、カウンターの機能を持つ再利用可能なコンポーネントです。

第14章: テーマとスタイリング

Kivyでは、アプリケーションの外観をカスタマイズするためのテーマとスタイリングシステムがあります。以下は、カスタムテーマを適用する例です:

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.core.text import LabelBase
from kivy.core.window import Window

# フォントの登録
LabelBase.register(name='Roboto', 
                   fn_regular='path/to/Roboto-Regular.ttf',
                   fn_bold='path/to/Roboto-Bold.ttf')

class ThemedApp(App):
    def build(self):
        # ウィンドウの背景色を設定
        Window.clearcolor = (0.9, 0.9, 0.9, 1)

        layout = BoxLayout(orientation='vertical', padding=20, spacing=10)
        btn1 = Button(text='ボタン1', background_color=(0.2, 0.7, 0.3, 1), color=(1, 1, 1, 1))
        btn2 = Button(text='ボタン2', background_color=(0.7, 0.2, 0.3, 1), color=(1, 1, 1, 1))
        layout.add_widget(btn1)
        layout.add_widget(btn2)
        return layout

    def on_start(self):
        # アプリケーション全体のフォントを設定
        from kivy.base import EventLoop
        EventLoop.window.font_name = 'Roboto'

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

このアプリケーションでは、カスタムフォントを登録し、ウィンドウの背景色を設定し、ボタンにカスタムスタイルを適用しています。

第15章: デプロイメントとパッケージング

最後に、Kivyアプリケーションをデプロイしパッケージ化する方法を見てみましょう。以下は、PyInstaller

を使用してKivyアプリケーションをパッケージ化する手順です:

  1. PyInstallerをインストールします:
pip install pyinstaller
  1. 以下の内容のmyapp.specファイルを作成します:
from kivy_deps import sdl2, glew

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(['main.py'],
             pathex=['/path/to/your/app'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='myapp',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
               strip=False,
               upx=True,
               upx_exclude=[],
               name='myapp')
  1. 以下のコマンドを実行してアプリケーションをビルドします:
pyinstaller myapp.spec

これにより、distフォルダ内に実行可能なアプリケーションが生成されます。

以上で、Kivyの基本から応用まで、15章にわたって詳しく解説しました。Kivyを使用することで、クロスプラットフォームで動作する魅力的なGUIアプリケーションを作成することができます。実際にコードを書いて試してみることで、より深くKivyを理解し、活用できるようになるでしょう。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?