Pythonでデスクトップアプリを簡単に作る方法

Fed4c6cfec7502b771e12f08f8d5ec6d?s=47 Jun okazaki
February 29, 2020

 Pythonでデスクトップアプリを簡単に作る方法

PyCon mini Shizuoka で発表する内容のスライドです。
PythonのGUIライブラリPySimpleGUIを使用してデスクトップアプリを作成する方法を紹介します

https://shizuoka.pycon.jp/session/dario_okazaki/

code: https://github.com/okajun35/for_pycon_shizu

Fed4c6cfec7502b771e12f08f8d5ec6d?s=128

Jun okazaki

February 29, 2020
Tweet

Transcript

  1. 3.

    自己紹介 • オカザキ(@dario_okazaki) • 所属:(株)スカラコミュニケーション ズ • 職業:サーバーサイドエンジニア • PyconJP2017

    トーク「Kivyによるアプ リケーション開発のすすめ」 • 長野Python会 with NSEG(2018/7/28) 「PythonのGUI@2018」 3
  2. 11.

    PythonのGUIについて(1/3) • ライブラリの数は多いが決定的なものはない 11 • Tkinter • wxPython • PyQt5

    ※QT系 • PySide2 ※QT系 • pySimplelGUI • PyGTK • PyFLTK • Kivy • Eel • flexx • REMI • Electron + Python※2 • React Native + Transcrypt(altJS)※2 • Pygame • Toga ※Qt系はそれぞれ開発元とライセンスが違います ※2はライブラリではなくて手法です
  3. 13.

    PythonのGUIについて(3/3) • その他(Android端末で動くもの) • QPython ※Andoridで動くIDE • Pydroid3 ※Andoridで動くIDE •

    LINE MessageAPI※Lineアプリ上で動くもの • IOSだとPythonistaというアプリがある 13
  4. 20.

    tkinterについて(3/3) パーソナルコンピュータの基本ソフトウェアとウィンドウ環境としては Windows, macOS, Linux/X-Window など複数のものが使われており、それぞれにウィンドウ の 描画などは異なった方法で行われます。これらの OS/ウィンドウ環境の差異を 吸収

    し、共通に使える GUI 用のフレームワークとして Tcl/Tk があります。 tkinter はこの Tcl/Tk を Python から利用できるようにしたパッケージです 20 ~ 京都大学 プログラミング演習 Python 2019 Version2020_02_13_01.pdf から引用 ~
  5. 21.

    GUIの基本 GUI 型のアプリケーションでは、メニューやボタンなどによるさ まざまな操作を ユーザ自身が選択して利用します。そして、操作 に対してコンピュータが適切に応 答することを期待します。 このようなユーザの操作を「イベント」と呼びます。多くの GUI 型のアプリケーションは

    GUI 用の「フレームワーク」を利用しま す。 フレームワークはマウスやキーボードの操作を監視してイベントを 検出し、プロ グラマーによって設定されたイベント処理用のプロ グラムを呼び出します。 フレームワークを用いた GUI 型のアプリ ケーションではプログラマーは主として 以下のような部分のプロ グラミングを担います。 イベントが発生した際に行う処理の定義 このようなプログラミン グをイベントに対する応答を主に記述することからイベン ト駆動 型 (event-driven) プログラミングと呼びます。 21 ~ 京都大学 プログラミング演習 Python 2019 Version2020_02_13_01.pdf から引用 ~
  6. 22.

    tkinterの基本 import tkinter from tkinter import messagebox #ボタンがクリックされたら実行 def button_click():

    input_value = input_box.get() messagebox.showinfo("クリックイベント",input_value + "が入力されまし た。") #ウインドウの作成 root = tkinter.Tk() root.title("Python GUI") root.geometry("360x240") #入力欄の作成 input_box = tkinter.Entry(width=40) input_box.place(x=10, y=100) #ラベルの作成 input_label = tkinter.Label(text="ラベル") input_label.place(x=10, y=70) #ボタンの作成 button = tkinter.Button(text="実行ボタン",command=button_click) button.place(x=10, y=130) #ウインドウの描画 root.mainloop() 22
  7. 23.

    tkinterの問題点(1/2) import tkinter from tkinter import messagebox ~~~省略~ #ウインドウの作成 root

    = tkinter.Tk() root.title("Python GUI") root.geometry("360x120") # 名前 input_name_label = tkinter.Label(text="名前") input_name_label.grid(row=1, column=1, padx=10,) # 入力欄の作成 input_name = tkinter.Entry(width=40) input_name.grid(row=1, column=2) # 住所 input_address_label = tkinter.Label(text="住所") input_address_label.grid(row=2, column=1, padx=10,) # 住所入力欄の作成 input_address = tkinter.Entry(width=40) input_address.grid(row=2, column=2) # 電話番号 input_phone_label = tkinter.Label(text="名前") input_phone_label.grid(row=3, column=1, padx=10,) # 電話番号入力欄の作成 input_phone = tkinter.Entry(width=40) input_phone.grid(row=3, column=2) 23
  8. 24.

    tkinterの問題点(2/2) • 書き方がPython的でない→忘れ る • レイアウトが縦、横のグリッド で指定するのでよくわからない root.geometry("360x240") # 入力欄の作成

    input_name = tkinter.Entry(width=40) input_name.grid(row=1, column=2) # 住所 input_address_label = tkinter.Label(text="住所") input_address_label.grid(row=2, column=1, padx=10,) # 住所入力欄の作成 input_address = tkinter.Entry(width=40) input_address.grid(row=2, column=2) # 電話番号 input_phone_label = tkinter.Label(text="名前") input_phone_label.grid(row=3, column=1, padx=10,) # 電話番号入力欄の作成 input_phone = tkinter.Entry(width=40) input_phone.grid(row=3, column=2) 24
  9. 26.
  10. 28.

    基本の形 (1/8) import PySimpleGUI as sg # セクション1 - オプションの設定と標準レイアウト

    sg.theme('Dark Blue 3') layout = [ [sg.Text('Python GUI')], [sg.Text('名前', size=(15, 1)), sg.InputText('◦◦〇×××')], [sg.Text('住所', size=(15, 1)), sg.InputText('△△△△村')], [sg.Text('電話番号', size=(15, 1)), sg.InputText('xxx-xxx-xxx')], [sg.Submit(button_text='実行ボタン')] ] # セクション 2 - ウィンドウの生成 window = sg.Window('住所を入力', layout) # セクション 3 - イベントループ while True: event, values = window.read() if event is None: print('exit') break if event == '実行ボタン': show_message = "名前:" + values[0] + 'が入力されました。¥n' show_message += "住所:" + values[1] + 'が入力されました。¥n' show_message += "電話番号:" + values[2] + "が入力されました。" print(show_message) # ポップアップ sg.popup(show_message) # セクション 4 - ウィンドウの破棄と終了 window.close() 28
  11. 31.

    基本の形(レイアウト) (4/8) • レイアウトはリストで記載できる layout = [ [sg.Text('Python GUI')], [sg.Text('名前',

    size=(15, 1)), sg.InputText('◦◦〇×××')], [sg.Text('住所', size=(15, 1)), sg.InputText('△△△△村')], [sg.Text('電話番号', size=(15, 1)), sg.InputText('xxx-xxx-xxx')], [sg.Submit(button_text='実行ボタン')] ] 31
  12. 32.

    基本の形(レイアウト)(5/8) • リストを入れ子にして作ることも可能 • 見やすい frame1 = sg.Frame('住所', [[sg.Text('郵便番号', size=(15,

    1))], [sg.InputText(key='-POST-NUM-')], [sg.Text('都道府県', size=(15, 1), )], [sg.InputText(key='-PREFECTURES-')], [sg.Text('住所', size=(15, 1))], [sg.InputText(key='-ADDRESS-')], ], relief=sg.RELIEF_SUNKEN, tooltip='住所をいれてね!') layout = [ [sg.Text('Python GUI')], [sg.Text('名前', size=(15, 1)), sg.InputText( default_text='◦◦〇×××', key='-USER-NAME-')], [sg.Text('住所を入れてね', size=(15, 1)), frame1], # frame1のレイアウトを入れ 子にして入れている [sg.Text('電話番号', size=(15, 1)), sg.InputText( default_text='xxx-xxx-xxx', key='-PHONE-NUM-')], [sg.Submit('実行ボタン')] ] 32
  13. 33.

    基本の形(ウィンドウの設定)(6/8) # セクション 2 - ウィンドウの生成 window = sg.Window('住所を入力', layout)

    • ウィンドウ、フォントなどのサイズを指定しなくても 自動でサイズを調整してくれる • サイズを指定して変更も可能 • ウィンドウは透明度の設定も可能 # セクション 2 - ウィンドウの生成 window = sg.Window('住所を入力', size=(300, 200)) 33
  14. 34.

    基本の形(イベント)(7/8) • ボタンのタイトルをイベント名として取得できる • 各項目(widget※)の値はリストで取得可能 ※: GUI を構成するボタンなどの部品 layout =

    [ [sg.Text('Python GUI')], [sg.Text('名前', size=(15, 1)), sg.InputText('◦◦〇×××')], [sg.Text('住所', size=(15, 1)), sg.InputText('△△△△村')], [sg.Text('電話番号', size=(15, 1)), sg.InputText('xxx-xxx-xxx')], [sg.Submit(button_text='実行ボタン')] ] # セクション 3 - イベントループ while True: event, values = window.read() if event == '実行ボタン': show_message = "名前:" + values[0] + 'が入力されました。¥n' show_message += "住所:" + values[1] + 'が入力されました。¥n' show_message += "電話番号:" + values[2] + "が入力されました。" print(show_message) # ポップアップ sg.popup(show_message) 34
  15. 35.

    基本の形(イベント)(8/8) • 各パーツにKeyを設定して、 Keyを指定して値を取得する ことも可能 frame1 = sg.Frame('住所', [[sg.Text('郵便番号', size=(15,

    1))], [sg.InputText(key='-POST-NUM-')], [sg.Text('都道府県', size=(15, 1), )], [sg.InputText(key='-PREFECTURES-')], [sg.Text('住所', size=(15, 1))], [sg.InputText(key='-ADDRESS-')], ], relief=sg.RELIEF_SUNKEN, tooltip='住所をいれてね!') layout = [ [sg.Text('Python GUI')], [sg.Text('名前', size=(15, 1)), sg.InputText( default_text='◦◦〇×××', key='-USER-NAME-')], [sg.Text('住所を入れてね', size=(15, 1)), frame1], [sg.Text('電話番号', size=(15, 1)), sg.InputText( default_text='xxx-xxx-xxx', key='-PHONE-NUM-')], [sg.Submit('実行ボタン')] ] # セクション 3 - イベントループ while True: event, values = window.read() if event == '実行ボタン': print(values) show_message = "名前:" + values['-USER-NAME-'] + 'が入力されました。¥n' show_message += "郵便番号:" + values['-POST-NUM-'] + 'が入力されました。¥n' show_message += "都道府県:" + values['-PREFECTURES-'] + 'が入力されました。¥n' show_message += "住所:" + values['-ADDRESS-'] + 'が入力されました。¥n' show_message += "電話番号:" + values['-PHONE-NUM-'] + "が入力されました。" 35 valuesの中身 { '-USER-NAME-': '◦◦〇×××’, '-POST-NUM-': '210’, '-PREFECTURES-': '東京都’, '-ADDRESS-': '渋谷区’, '-PHONE-NUM-': 'xxx-xxx-xxx’ }
  16. 37.

    exe化(1/2) • PyInstllerを使用する • 以下のエラーが出た場合は、--hidden-import tkinter をオプション に加える • PyInstllerを使用したEXE化はオプションがあって色々難しい

    • Onefileにはしない • 3rd Party Libraly(PiPでインストールするライブラリー)は最初はアプリに使用し ない(importしない)→標準ライブラリのみでアプリを作ってみる pip install PyInstaller pyinstaller -wF my_program.py ValueError: script '.......¥src¥tkinter' not found 37
  17. 52.

    参考:英語のドキュメントの読み方(3/3) • 難しい単語は辞書を引く • 参考:Chrome拡張の高速な英語辞書ツールをつ くりました(Mouse Dictionary) • https://qiita.com/wtetsu/items/c43232c6c44918e9 77c9

    • IT用語など決まった用語には注意する • 例:「 separation of concerns」→「関心の分離 ( SoC )」※機械翻訳だと「懸念の分離」や「関心 事の分離」と訳されることがある 52