Pythonのお勉強:PySimpleGUIを使ってPythonのGUIプログラムを作ってみた

PySimpleGUI

PySimpleGUIモジュールを使用すると、Tkinterを使用するよりも簡単にPythonのGUIプログラムを作成することが出来るようなので、実際にPySimpleGUIモジュールインストールして、以前の記事「Pythonのお勉強:OpenPyXLでPDFファイルのリスト(EXCEL)を作成する」で作成したプログラムをGUIで実行できるようにしてみました。

PySimpleGUIのインストール

PySimpleGUIモジュールは、以下のpipコマンドで簡単にインストールできました。

% pip install PySimpleGUI
Collecting PySimpleGUI
:
Successfully installed PySimpleGUI-4.60.4

PySimpleGUIのテンプレートプログラム

PySimpleGUIのイベントによる動作を確認するために、PySimpleGUIモジュールを使用したPythonのGUIプログラムのテンプレートプログラムを作成しました。

  • 「PySimpleGUI_Template.py」
    import PySimpleGUI as sg
    import sys
    
    def event_Submit(root_dir):
        #
        # PDFリストのEXCELファイルを作成する処理を書く
        #
        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()
    
    

    テンプレートプログラムから得られた知見

    • PySimpleGUIモジュールをインポートする際には、以下のように「sg」という名前を付けてインポートすることが推奨されている。
      import PySimpleGUI as sg
      
    • Windowsオブジェクトの生成は、以下のように「sg.Window()」にタイトル名とウィジットのリスト(layout)を指定して行う。
          window = sg.Window('PDFリストのEXCELファイル作成', layout=layout)
      
    • ウィジットのリスト(layout)は、以下のように実際の画面レイアウトに合わせてウィジットを配置して作成する。

          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")]]
      
    • 「sg.InputText() 」と 「sg.FolderBrowse()」 以下のように横に並べて記載すると、フォルダ選択用のGUIを作成することが出来る。
            [sg.Input(default_text='', size=(50,2)),sg.FolderBrowse()],
      

      「sg.FolderBrowse()」を「sg.​FileBrowse()」に変更するとファイル選択用のGUIを作成することが出来る。

    • イベントで発生する値は、「while True:」の無限ループでwindow.read()のイベント発生を待ち、イベントが発生したらタプル形式(key, value)でイベントを受け取る。
      while True:
      	event, value = window.read()
      
      
    • イベント(Key)の文字列をif文で判定して処理を分岐する。
      if event is None:
      	break
      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
      
    • ウィンドウ画面の「閉じる(X)」ボタンがクリックされると、イベント(Key)として「None」が返ってくるので、「break」してプログラム終了をする。
      	if event is None:
      		break
      
    • value[0]には、sg.Input()の文字列(root_dir)が格納される。value[0]に格納された文字列が「空白・NULL」の場合は、「sg.popup()」で注意メッセージを表示する。
      	if not value[0]:
      		sg.popup('最初にPDFのルートフォルダを選択してください.')
      
    • value[0]に格納されたroot_dirの文字列が「空白・NULL」以外の場合は、変数「root_dir」にvalue[0]の値を代入し、「root_dir」を引数にしてevent_Submit()関数を呼び出す。
      	else:
      		root_dir=value[0]
      		event_Submit(root_dir)
      
    • 「Cancel」ボタンがクリックされると、イベント(Key)として指定した「btn_Cancel」が返ってくるので、「break」してプログラム終了をする。
      	elif event == "btn_Cancel":
      		break
      

    ディレクトリを再帰的に探索するGUIサンプルプログラム(「PSG_Pdf_DirList.py」)

    以前の記事「Pythonのお勉強:OpenPyXLでPDFファイルのリスト(EXCEL)を作成する」で作成したプログラムをGUIで実行できるようにしたサンプルプログラムを以下に記載します。

    • 「PSG_Pdf_DirList.py」
      on"]
      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()
      

    サンプルプログラム(「PSG_Pdf_DirList.py」)のGUI動作概要

    最後に、サンプルプログラムのGUI動作概要を以下に記載します。

    • VSCodeでデバック無しで実行すると以下のウィンドウが表示されます。
    • 「[1] PDFのルートフォルダを選択」横の「Brows」ボタンをクリックすると、システムの「フォルダ選択ダイアログ」が表示されます。選択したルートフォルダのPATHが「sg.Input()の値」として設定されます。
    • 「[2] PDFリストのEXCELファイルを作成」横の「Submit」ボタンをクリックすると、カレントフォルダに「Pdf_DirList.xlsx」が作成されます。
  • Pdf_DirList.xlsx」が作成されると、以下のような<「<YES/NO>確認ダイアログ」が表示されます。 【ソースコード】
    yes_no_ans = sg.popup_yes_no('ルートフォルダ \n[ ' + root_dir + ' ]'+'\n 以下にあるPDFファイルのリスト(EXCEL)を作成しました。\n\nプログラムを終了しますか?\n',title='&lt;YES/NO&gt;確認ダイアログ')
    
  • ルートフォルダのPATH「sg.Input()の値」が「空白・NULL」の状態で「Submit」ボタンをクリックすると、以下のような「ルートフォルダ選択を促す注意メッセージ」が表示されます。 【ソースコード】
    sg.popup('最初にPDFのルートフォルダを選択してください.')
    

実際に動作するサンプルプログラムを作成できたので、なんとなく「PySimpleGUI」の使い方が判ったような気がします。

管理人がPythonの勉強のために購入した本

コメント