LoginSignup
0
1

More than 1 year has passed since last update.

PySimpleGUIでデスクトップアプリ(連打くん)を自作した

Last updated at Posted at 2023-05-03

備忘録
つまづいたところやtipsだけをまとめる

インストールとか

コマンドプロンプトで以下を実行してインストール

py -m pip install pysimplegui

プログラムではsgとしてインポートしておく

test.py
import PySimpleGUI as sg

テーマ設定

sg.theme()で設定できる

sg.theme('ここにテーマの名前')

テーマの一覧を表示する

sg.theme_previewer()

theme.png

私の環境ではすべては表示されなかったのでscrollable=Trueを追加してスクロールできるようにした

sg.theme_previewer(scrollable=True)

windowの設定

keep_on_top=Trueで最前面表示、grab_anywhere=Trueでどこをつかんでも動かせるようにできる

win = sg.Window("テスト",layout,
                size=(300, 150),keep_on_top=True,grab_anywhere=True)

無限ループの実行

問題

連打くんを作るにあたって常にf9キーが押されたかどうかを判断する必要があった
ただしこちらのプログラムではtestは一回しか表示されなかった

while True:
    print("test")
    event, value = win.read()
    if event == sg.WIN_CLOSED:
        break

原因と対応

event, value = win.read()はイベントが発生するまで待つらしい
それを防止するためにtimeoutを使う

while True:#これで0.1秒ごとにtestと表示される
    print("test")
    event, value = win.read(timeout=100) #イベントが発生しなくても0.1秒で待機を抜ける
    if event == sg.WIN_CLOSED:
        break

exe化とアイコン

準備

あらかじめフォルダを作りそこにpythonのプログラムとexeのアイコンにしたいicoファイルを移動しておく
img.png

icon=でアイコン指定

win = sg.Window("テスト",layout,icon='icon.ico',size=(300, 150))

しかしこのままexe化すると常にexeファイルと同じフォルダにiconファイルをおかないとアイコンが変わらないという事態が発生するため、exeファイルへの取り込みを行うためのプログラムを追加する
importの追加

import sys
import os

関数の追加

def resource_path(relative):
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative)
    return os.path.join(os.path.abspath('.'), relative)

sg.Window部分の変更

icon_path = resource_path('icon.ico')
win = sg.Window("テスト",layout,icon=icon_path,size=(300, 150))

ファイル全体としてはこんな感じ

test.py
import PySimpleGUI as sg
import sys
import os

layout = [
    [sg.Text("Hello")]
]

def resource_path(relative):
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative)
    return os.path.join(os.path.abspath('.'), relative)

icon_path = resource_path('icon.ico')
win = sg.Window("テスト",layout,icon=icon_path,size=(300, 150))

while True:
    event, value = win.read()
    if event == sg.WIN_CLOSED:
        break

win.close()

exe化

exe化にはpyinstallerを使う
コマンドプロンプトでインストール

py -m pip install pyinstaller==5.5

後述の理由でバージョンは5.5にしている

「pythonのプログラムとexeのアイコンにしたいicoファイルを移動したフォルダ」でコマンドプロンプトを実行
--onefileでexeファイルを一つにまとめ、--noconsoleでコンソールを非表示にしている。また、エクスプローラー上のアイコンを変更するために--icon=icon.icoでアイコン指定。

pyinstaller --onefile --noconsole --icon=icon.ico test.py

できたexeファイルが重いときは--excludeを利用したり仮想環境を利用する

アイコンをexeファイルに取り込むために生成されたtest.specを開き、

a.datas += [("icon.ico", "icon.ico", "Data")]

を追加する
img2.png
できたらコマンドプロンプトでpyinstaller test.specを実行する

pyinstaller test.spec

pyinstallerのバージョンが最新だとここでKeyError: 'Data'というエラーが発生したのでバージョンは5.5にしている

蛇足

作成した連打くんのプログラムを貼っておく

renda.py
import PySimpleGUI as sg
import pyautogui
import keyboard
import sys
import os

sg.theme('black')

layout = [
    [sg.Text("連打くん",size=(30,1), justification='center', 
             font=(None, 20, 'bold'), text_color='yellow',key='txt')],
    [sg.Text("1秒間に"),
     sg.Slider(range=(10,1000),default_value =100,resolution=10,
               orientation='h',size=(11, 15),key='repeat'),
     sg.Text("")
    ],
    [sg.Text("f9で実行、f10で停止")],
    [sg.Checkbox("カーソル移動で停止",default=False,key='stop')]
]

def resource_path(relative):
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative)
    return os.path.join(os.path.abspath('.'), relative)

icon_path = resource_path('cursor.ico')
win = sg.Window("連打くん",layout,icon=icon_path,size=(300, 185),
                keep_on_top=True,grab_anywhere=True)

while True:
    event, value = win.read(timeout=100)
    if keyboard.is_pressed('f9'):
        n = int(value['repeat']/10)
        win['txt'].update("実行中",text_color='red')
        event, value = win.read(timeout=1)
        if(value['stop']):
            pos = pyautogui.position()
            while keyboard.is_pressed('f10') == False:
                pyautogui.click(button='left', clicks=n)
                if(pos != pyautogui.position()):
                    break
        else:
            while keyboard.is_pressed('f10') == False:
                pyautogui.click(button='left', clicks=n)         
        win['txt'].update("連打くん",text_color='yellow')
    if event == sg.WIN_CLOSED:
        break

win.close()
0
1
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
1