LoginSignup
1
3

More than 1 year has passed since last update.

PySimpleGUI と PyInstaller で 整数リストを並び替えて出力するGUIアプリケーションを作ってみた

Last updated at Posted at 2022-12-27

0.発端

子供(小学2年生)の冬休みの宿題として
掛け算九九の各段について、ランダムに並び替えた数字の順で間違えないように暗唱する
というものがあり、その「ランダムな数字の順」を考えるのが面倒なので、Pythonにやらせてみようと思ったのが事の発端です。
(Qiita様と投稿者の皆々様のエントリには常日頃お世話になっており、何かひとつ投稿してみたいと考え、当エントリを作成しました)

1.整数リストをランダムに入れ替えるスクリプト

最初に作ったのは「1から9までのリスト」をランダムに並び替える関数でした。
作っているうちに欲が出て「リストを違うパターンで並び替えて出力する」仕様も追加しました。

RandomList.py
import sys
import random
import copy

def random_list(repeat=1, num=10):
    # 1からnumまでのリスト
    numbers = list(range(1,num))

    # 繰り返し
    numbers_list = []
    i = 0
    while i < repeat:
        # ランダマイズ
        random.shuffle(numbers)
        numbers_list.append(copy.deepcopy(numbers))
        # インクリメント
        i+=1

    return numbers_list

# コマンドライン呼び出し
if __name__ == "__main__":
    args = sys.argv # パラメータ引数
    repeat = 1      # 繰り返し出力数
    num = 10        # 配列の要素数
    if(len(args) > 1) :
        repeat = int(args[1])
    if(len(args) > 2) :
        num = int(args[2])
    
    numbers_list = random_list(repeat, num)

    for numbers in numbers_list:
        print(numbers)

全行バラバラになるはずなのに

行ごとに並びが変わる事を期待し、以下のフロー(抜粋)で実装しました。

numbers = list(range(1,num))      # 1~9までの整数リスト
while i < repeat:
    random.shuffle(numbers)       # 整数リストをランダムに並び替える
    numbers_list.append(numbers)  # リストのリストに追加

が、予想に反し、すべての行が同じ並びで出力される事に。
原因は最後の1行で、numbers_list.append(numbers)でリストを直接appendしても、IDが参照で渡されているだけなので、追加後にnumbersの順番が再抽選されるとnumbers_listのすべての行が同様に並び替わった状態になっていました。

解決策としてnumbersを参照渡しではなくcopy.deepcopy(numbers)で複製してappendすることで期待通りの結果が得られました。

RandomList.pyの出力結果
> Python3 .\RandomList.py 10
[8, 2, 5, 6, 9, 7, 3, 4, 1]
[4, 3, 9, 6, 2, 7, 1, 5, 8]
[8, 1, 2, 4, 9, 5, 3, 6, 7]
[5, 3, 6, 8, 2, 9, 4, 7, 1]
[2, 3, 4, 5, 8, 1, 9, 7, 6]
[1, 8, 4, 3, 6, 7, 9, 2, 5]
[1, 4, 5, 7, 9, 6, 2, 3, 8]
[9, 7, 1, 6, 5, 8, 3, 4, 2]
[7, 4, 6, 1, 5, 3, 8, 9, 2]
[4, 6, 7, 5, 2, 9, 8, 3, 1]

当問題の解決に際し、こちらのエントリを参考にさせていただきました。

2.PySimpleGUIでアプリケーション化

コマンドラインで直接呼び出して数値が出るのも、子供ウケとしては悪くはありませんが、どうせならGUIアプリケーション化するほうが子供も使いやすいかもしれない。
これは学習の好機と考え、「PySimpleGUI」を用いたGUIアプリケーション化を行いました。

Python_GuiRandomList.png

GuiRandomList.py
import PySimpleGUI as sg
import RandomList as rl

# GUIウインドウテーマ
sg.theme('Python')

# 入力フレーム
frame1 = sg.Frame('入力',
  [
    [
      sg.Text('繰り返し回数'),
      sg.InputText(key='-INPUTTEXT-', default_text='10', size='3'),
      sg.Text('')
    ],
    [
      sg.Submit(button_text='生成', key='button_create')
    ]
  ]
)

# 出力フレーム
frame2 = sg.Frame('出力',
  [
    [
      sg.MLine(size=(18,20), key='-OUTPUT-', disabled=True)
    ]
  ]
)

# レイアウト
layout = [
  [
    frame1
  ],
  [
    frame2
  ]
]

# Window生成
window = sg.Window('ランダム数字リスト生成アプリ', layout, resizable=True)

# GUI表示実行部分
while True:
  # ウインドウ表示
  event, values = window.read()

  # クローズボタン
  if event is None:
    print('exit')
    break

  # ボタンが押された場合
  if event == 'button_create':
    repeat = int(values['-INPUTTEXT-'])
    numbers_list = rl.random_list(repeat)
    output = ''
    if len(numbers_list) > 0:
      for numbers in numbers_list:
        for number in numbers:
          output += str(number) + ' '
        output += '\n'
    window['-OUTPUT-'].Update(output)

window.close()

概要としては
sg.InputTextsg.Submitsg.MLineそれぞれにkeyをつけて参照可能にした上で、
InputText の値の数だけリストを繰り返し生成しランダムに並び替え、
outputに文字列として整形した上で MLine に出力するという処理を行っています。

PySimpleGUIの使用に際し、以下のエントリを参考にさせて頂きました。

3.PyInstallerでスクリプトのexe化

GUIアプリケーションとしての体裁が整ったところで、今度は単独で動かせるようにexe化を試みました。
PyInstallerを用いることでexe化が可能だと知り、導入しようとしたのですが…

PyInstallerが実行できない?

Windows10のPower Shell上でpipを用いてPyInstallerをインストール。

console
pip install PyInstaller

他のエントリでも書かれているように、以下のコマンドを実行してもpyinstallerが見つからない。

console
pyinstaller GuiRandomList.py   # pyinstaller.exe が Not Found

PATHを通せばよいのかもとも思ったのですが、ネットの海を漁ってみると
PyInstallerは仮想環境で実行してexe化する
という情報にたどり着きました。

なぜ仮想環境上でexe化するほうがいいの?

PyInstallerは、自身を実行した環境にインストールされているすべてのモジュールを内包した状態でexe化するらしく、通常の環境のままだと不必要なモジュールを内包した状態でexeを作成するため、exeが肥大化するそうです。
なので、仮想環境で必要最低限のモジュールをインストールした状態でexe化する方が良いそうで。

仮想環境の構築とモジュールのインストール

pythonのvenvコマンドで、PyInstaller用の仮想環境GuiRandomListEnvを作成。

console
python -m venv GuiRandomListEnv

作成された仮想環境を起動。

console
.\GuiRandomListEnv\Scripts\activate

pipを最新化し、今回使用しているモジュールPySimpleGUIPyInstallerをインストール。

console(仮想環境)
pip install -U pip        # pipの最新化
pip install PySimpleGUI
pip install PyInstaller

PyInstaller実行によるexe化

仮にスクリプトGuiRandomList.pyc:\example\scripts\に配置されているとして、以下の手順でexe化します。

console(仮想環境)
cd c:\example\scripts\
pyinstaller GuiRandomList.py

上記コマンド実行後、GuiRandomList.pyと同じフォルダ内に、以下のフォルダ・ファイルが生成されます。

c:\example\scripts\
build\              # ビルド時の一時ファイルの格納フォルダ
dist\               # 生成された実行ファイルの格納フォルダ
GuiRandomList.spec  # ビルド中間ファイル

オプションを設定しなければ、dist\配下にGuiRandomList.exeと共に、実行に必要なファイルが吐き出されます。
下記オプションで出力内容を変える事も可能です。

pyinstaller実行オプション
--onefile (-Fでも可)   # 出力ファイルを1つにまとめる
--onedir  (-Dでも可)   # 出力フォルダを1つにまとめる
--noconsole (-wでも可) # 実行時にコンソール画面を表示しない

個人的には「exeファイルひとつ」が「コンソールが開くことなく」実行できて欲しいので、下記オプションで出力しました。短縮版はハイフンの後に複数続けて書く事も可能です。

pyinstaller実行オプションサンプル
pyinstaller -wF GuiRandomList.py

実行結果として、dist\フォルダ下に、以下の実行ファイルが生成されました。
無事起動を確認し「整数リストを並び替えて出力するGUIアプリケーションのexe」が完成しました。
GuiRandomList.exe.png

3'. PyInstallerによるMac向けアプリ化

Pythonの仮想環境上でPySimpleGUIとPyInstallerをinstallしてpyinstallerすればいいだけなら、Macでも同様の手順でアプリケーションが作れるのでは?
と思い、GitHub経由でリソースをMacに持ってきて、アプリケーション化を試みました。

仮想環境の構築手順は変わらず。

console
python -m venv GuiRandomListEnv

仮想環境に入る際のコマンドやフォルダ構成がWindowsのPower Shellとは違いました。

console
source GuiRandomListEnv¥bin¥activate

入ってしまえばあとは変わらず。

console(仮想環境上)
pip -U install pip
pip install PySimpleGUI
pip install PyInstaller
console(仮想環境上)
pyinstaller -wF GuiRandomList.py

これで、Windows同様dist¥フォルダ下にアプリケーションGuiRandomListが生成されました。
ダブルクリックで起動も確認出来ました。
スクリーンショット 2022-12-28 21.39.38.png

1
3
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
1
3