「cx_Freeze」を使用するとPythonのGUIプログラムをWindowsのexeファイルへ変換して、スタンドアロンのWindowsアプリとして使用することが出来るようになります。前の記事「Pythonのお勉強:PySimpleGUIを使ってPythonのGUIプログラムを作ってみた」で作成したGUIサンプルプログラム「PSG_Pdf_DirList.py」をSakura.Oh!Happy.JPの記事「VsCodeでPython 3.11の開発環境をつくる(Windows10)」で作製した環境で、cx_Freezeeを使用してスタンドアロンのWindowsアプリにしてみました。
cx_Freezeeのインストール
cx_Freezeは、Windows10のPowerShellを使用して、以下のpipコマンドで簡単にインストールできました。
> pip install --upgrade cx_Freeze : Successfully installed cx-Logging-3.1.0 cx_Freeze-6.14.0 lief-0.12.3
セットアップファイルの作成
Windows10のPowerShellで「cxfreeze-quickstart」コマンドを実行すると、セットアップファイル作成用のスクリプトが起動します。スクリプトの質問に答えていくとカレントフォルダに、セットアップファイル「setup.py」が作成されます。以下に「PSG_Pdf_DirList.py」用のセットアップファイルを作成した際のログを記載します。「Project name:」「Python file to make executable from:」「(C)onsole application, (G)UI application, or (S)ervice [C]:」は入力回答し、他の項目はリターンキーのみ(デフォルト値)で回答しました。
PS > cxfreeze-quickstart Project name: PSG_Pdf_DirList <- (入力) Version [1.0]: Description: Python file to make executable from: PSG_Pdf_DirList.py <- (入力) Executable file name [PSG_Pdf_DirList]: (C)onsole application, (G)UI application, or (S)ervice [C]: G <- (入力) Save setup script to [setup.py]: Setup script written to setup.py; run it as: python setup.py build Run this now [n]?
「cxfreeze-quickstart」で作成された「setup.py」
from cx_Freeze import setup, Executable # Dependencies are automatically detected, but it might need # fine tuning. build_options = {'packages': [], 'excludes': []} import sys base = 'Win32GUI' if sys.platform=='win32' else None executables = [ Executable('PSG_Pdf_DirList.py', base=base) ] setup(name='PSG_Pdf_DirList', version = '1.0', description = '', options = {'build_exe': build_options}, executables = executables)
Windowsアプリの作成と動作確認
以下の手順で「PSG_Pdf_DirList.py」のWindowsアプリを作成しました。
- 「PSG_Pdf_DirList.py」と「setup.py」を1つのフォルダ(任意)に入れました。
- PowerShellで上記のフォルダに移動して、以下のコマンドでWindowsアプリを作成しました。
> python setup.py build >
- フォルダ(任意)の下に/build/というフォルダが作成され、その直下の/exe.win-amd64-3.11/フォルダ内に「PSG_Pdf_DirList.exe」というEXEファイルが出来ていました。
/build/ └/exe.win-amd64-3.11/ ├ frozen_application_license.txt ├ PSG_Pdf_DirList.exe ├ python3.dll ├ python311.dll └─/lib/
- /exe.win-amd64-3.11/フォルダ以下のファイル(/lib/フォルダを含む)を全てUSBにコピーし、USBの「PSG_Pdf_DirList.exe」を起動して動作確認を行ったところ、問題無くWindowsアプリとして使用することが出来ました。「PSG_Pdf_DirList.exe」のディスク上のサイズは「32KB」でしたが、アプリ全体のファイルサイズは「141M」、/lib/フォルダ全体のディスク上のサイズは「130M」でした。
Windowsアプリに変換したPythonのGUIプログラム(「PSG_Pdf_DirList.py」)
上記の手順で”cx_Freeze” を使用してWindowsアプリに変換したPythonのGUIプログラムを以下に記載します。
- 「PSG_Pdf_DirList.py」
import PySimpleGUI as sg import sys import os import os.path import fnmatch import openpyxl from openpyxl.styles.alignment import Alignment from openpyxl.styles import PatternFill from openpyxl.styles import Font def event_Submit(root_dir): # 変数定義 search_dir = root_dir dirname_lst = list() # ディレクトリ名の格納用リスト pdfname_lst = list() # PDFファイル名の格納用リスト lnkname_lst = list() # HYPERLINK用ファイル名の格納用リスト maxlen_dirname = 0 # ディレクトリ名の最大バイト数格納用変数 maxlen_pdfname = 0 # PDFファイル名の最大バイト数格納用変数 maxlen_lnkname = 0 # HYPERLINK用ファイル名の最大バイト数格納用変数 # 新規ワークブックの作成 wb = openpyxl.Workbook() ws = wb.active ws.title = "pdf_list" # PDFファイル名とHYPERLINK用ファイル名をリストに格納 for dirpath, dirs, files in os.walk(search_dir): for fname in files: if fnmatch.fnmatch(fname, '*.pdf'): # ディレクトリ名をリストに格納 # print(dirpath) dirname = dirpath dirname_lst.append(dirname) if len(dirname.encode()) > maxlen_dirname: maxlen_dirname = len(dirname.encode()) # PDFファイル名をリストに格納 # print(fname) pdfname = fname pdfname_lst.append(pdfname) if len(pdfname.encode()) > maxlen_pdfname: maxlen_pdfname = len(pdfname.encode()) # HYPERLINK用ファイル名をリストに格納 # print(os.path.join(dirpath, fname)) lnkname = os.path.join(dirpath, fname) lnkname_lst.append(lnkname) if len(lnkname.encode()) > maxlen_lnkname: maxlen_lnkname = len(lnkname.encode()) start_row = 1 # EXCEL表示開始列 start_col = 1 # EXCEL表示開始行 # タイトルセルの名前を設定 ws.cell(start_col,start_row).value='ディレクトリ名' ws.cell(start_col,start_row+1).value='PDFファイル名' # タイトルセルの表示幅を変更 ws.column_dimensions['A'].width = maxlen_dirname ws.column_dimensions['B'].width = maxlen_pdfname # タイトルセル('A1':'B1')の背景色を変更 「fil_obj(水色 塗り潰し)」 fil_obj = PatternFill(fgColor='00ffff' , patternType='solid') for rows in ws['A1':'B1']: for cell in rows: cell.fill = fil_obj # セルにファイル名を書き込む for i in range(0,len(pdfname_lst)): # 現在の行(cur_col)と列(cur_row)を変数に格納 cur_col = i+start_col+1 cur_row = start_row # シート'A'列にディレクトリ名を書き込む hdir_name = dirname_lst[i] hdir_str = hdir_name ws.cell(cur_col,cur_row).value = hdir_name ws.cell(cur_col,cur_row).hyperlink = hdir_str # シート'B'列にPDFファイル名とHYPERLINKを書き込む hpdf_name = pdfname_lst[i] hlnk_name = lnkname_lst[i] hlnk_str = hlnk_name ws.cell(cur_col,cur_row+1).value = hpdf_name ws.cell(cur_col,cur_row+1).hyperlink = hlnk_str # ハイパーリンクの書式設定 fnt_obj(色:青 シングルアンダーライン) fnt_obj = Font(color='0000FF', u='single') ws.cell(cur_col,cur_row).font = fnt_obj ws.cell(cur_col,cur_row+1).font = fnt_obj # シートセル全体の水平方向を左寄せ、高さ方向を中央揃え for col in ws: for cell in col: cell.alignment = Alignment(horizontal='left',vertical='center') # シートセルの行高さ変更 for i in range(len(dirname_lst)+2): ws.row_dimensions[i].height = 21 # 作成したファイルをに名前をつけて保存 save_filename = 'Pdf_DirList.xlsx' while True: try: wb.save(filename = save_filename) except PermissionError: sg.popup_ok('Excelファイルが開いていますので閉じてください。',title='エラーメッセージ') else: break; wb.close() yes_no_ans = sg.popup_yes_no('ルートフォルダ \n[ ' + root_dir + ' ]'+'\n にあるPDFファイルのリスト(EXCEL)を作成しました。\n\nプログラムを終了しますか?\n',title='<YES/NO>確認ダイアログ') if yes_no_ans == "Yes": sys.exit() # メイン def main(): layout = [ [sg.Text('[1] PDFのルートフォルダを選択', size=(40, 1))], [sg.Input(default_text='', size=(50,2)),sg.FolderBrowse()], [sg.Text('[2] PDFリストのEXCELファイルを作成', size=(44, 2)),sg.Submit(key="btn_Submit")], [sg.Text('[3] プログラムの終了', size=(44, 2)),sg.Cancel(key="btn_Cancel")]] window = sg.Window('PDFリストのEXCELファイル作成', layout=layout) while True: event, value = window.read() if event is None: break # keyの文字列を判定してイベント処理を分岐 elif event == "btn_Submit": if not value[0]: sg.popup('最初にPDFのルートフォルダを選択してください.') else: root_dir=value[0] event_Submit(root_dir) elif event == "btn_Cancel": break else: continue window.close() if __name__ == "__main__": main()
コメント