【Python】サブ画面を開く方法②:subprocess モジュールを使う_run()編【PySimpleGUI】

やりたいこと

  • Home画面を起動し、「Open」ボタンを押すと、別窓でサブ画面が開く
  • サブ画面が開いている間は、Home画面の操作をできなくする(サブ画面を閉じると再び操作できるようになる)

 ※OSはWindowsで、 GUIの構築にPySimpleGUIを使用

イメージ

Home画面を起動し、「Open」ボタンを押すと

f:id:tsukune_dora_dora:20200630131551p:plain

別窓でサブ画面が開く

サブ画面が開いている間は、Home画面は操作できない

f:id:tsukune_dora_dora:20200630125037p:plain

サブ画面を閉じると、再びHome画面を操作できるようになる

f:id:tsukune_dora_dora:20200630131551p:plain

解説

subprocess モジュールとは

名前の通り「サブプロセスを管理するために使われるモジュール」ですここではHome画面をメインプロセスとし、サブプロセスとしてサブ画面を起動します。Home画面もサブ画面も、それぞれ独立した画面(=それぞれ単独で動かすことができる画面)として実装しており、言わばHome画面にとってサブ画面は「外部プロセス」です。

subprocess モジュールでは、Pythonアプリケーションから「外部プロセス」を実行するために、run()Popen()が用意されてます。

※run()は関数で、Popen()はクラスらしいです

subprocess.run()

外部プロセスを実行する。外部プロセスの完了を待つ

subprocess.Popen()

外部プロセスを実行する。外部プロセスの完了を待たず後続処理を実行できる

どっちを使うの?

今回やりたいことは冒頭で書いた通り

  • サブ画面が開いている間は、Home画面の操作をできなくする(サブ画面を閉じると再び操作できるようになる)

です。つまり、「サブ画面を起動する」というプロセスを実行したら、そのプロセスが終了するまでHome画面は待機する、ということなので、ここではsubprocess.run()を使います。

 

そうではなくて、『サブ画面が開いている間も、Home画面は操作可能にする(=「Open」ボタンを何度も押せる=サブ画面を複数開ける)』という実装にしたい場合は・・・

「サブ画面を起動する」というプロセスを実行した後も、引き続きHome画面のプロセスを実行する、ということなので、subprocess.Popen()を使いましょう。

subprocess.Popen()の使い方は↓記事にまとめました。

tsukune-dora-dora.hatenablog.com

 

以下に実装方法とその解説をのせます。

実装方法

開発環境

OS:Windows 10(64ビット版)

Pythonのバージョン:Python 3.8.2

ファイル構成

Sample

 ├ home.py              # Home画面

 ├ sub_page.py        # サブ画面

ソースコード(※Windows限定のやり方です!)

home.py(Home画面)
import PySimpleGUI as sg
import subprocess

#-------------------------
#-- 背景色を設定 --
#-------------------------
sg.theme('LightBrown11')

#-------------------------
#-- 画面レイアウトを設定 --
#-------------------------
layout = [
    [sg.Text('サブ画面を開いてみよう', font=("Helvetica", 20))],
    [sg.Button('Open', font=("Helvetica", 10), size=(15,0), key='open_sub_page_btn')]
]

#-------------------------
#-- ウィンドウの生成 --
#-------------------------
window = sg.Window('Home画面', layout, size=(400,100))

#-------------------------
#-- イベントループ --
#-------------------------
while True:
    event, values = window.read()

    #--【×】ボタン押下
    if event == None:
        break #画面を閉じる

    #--【Open】ボタン押下
    elif event == 'open_sub_page_btn':

        #『サブ画面』を起動
        proc = subprocess.run(r'.\sub_page.py',shell=True)

window.close()
sub_page.py(サブ画面)
import PySimpleGUI as sg
import subprocess

#-------------------------
#-- 背景色を設定 --
#-------------------------
sg.theme('LightBrown11')

#-------------------------
#-- 画面レイアウトを設定 --
#-------------------------

layout = [
    [sg.Text('成功!', font=("Helvetica", 20))]
]

#-------------------------
#-- ウィンドウの生成 --
#-------------------------
window = sg.Window('サブ画面', layout, size=(400,100))

#-------------------------
#-- イベントループ --
#-------------------------
while True:
    event, values = window.read()

    #--【×】ボタン押下
    if event == None:
        break #画面を閉じる

window.close()

ソースコードの解説

subprocess モジュールを使うために、まずはライブラリをインポートします。

home.py(Home画面)

import subprocess

 

subprocess.run()を呼び出し、引数を渡します。

home.py(Home画面)

        #『サブ画面』を起動
        proc = subprocess.run(r'.\sub_page.py',shell=True)

 

第1引数には、実行したいコマンド(ここではサブ画面の起動を命令するコマンド)を指定します。第2引数の「shell=True」は何かと言いますと...これがないと以下のエラーが発生します。

OSError: [WinError 193] %1 は有効な Win32 アプリケーションではありません。

 subprocess.run()は「Linuxコマンドを実行する」ものらしいので、Windowsコマンドは理解できないようです。「shell=True」を指定することで、コマンドプロンプト cmd.exe が呼び出され、その上でコマンドが実行されるらしいです(以下の記事を参考にしました)。

qiita.com

 

以上です。

【Python】サブ画面を開く方法①:subprocess モジュールを使う_Popen()編【PySimpleGUI】

やりたいこと

  • Home画面を起動し、「Open」ボタンを押すと、別窓でサブ画面が開く
  • サブ画面が開いている間も、Home画面は操作可能にする(=「Open」ボタンを何度も押せる=サブ画面を複数開ける)

 ※OSはWindowsで、GUIの構築にPySimpleGUIを使用

<イメージ>

Home画面を起動し、「Open」ボタンを押すと

f:id:tsukune_dora_dora:20200630131551p:plain

別窓でサブ画面が開く

f:id:tsukune_dora_dora:20200629102909p:plain

 ↓

サブ画面が開いている間も、Home画面は操作可能

=「Open」ボタンを何度も押せる

=サブ画面を複数開ける

f:id:tsukune_dora_dora:20200629103003p:plain

解説

subprocess モジュールとは

名前の通り「サブプロセスを管理するために使われるモジュール」ですここではHome画面をメインプロセスとし、サブプロセスとしてサブ画面を起動します。Home画面もサブ画面も、それぞれ独立した画面(=それぞれ単独で動かすことができる画面)として実装しており、言わばHome画面にとってサブ画面は「外部プロセス」です。

subprocess モジュールでは、Pythonアプリケーションから「外部プロセス」を実行するために、run()Popen()が用意されてます。

※run()は関数で、Popen()はクラスらしいです

subprocess.run()

外部プロセスを実行する。外部プロセスの完了を待つ

subprocess.Popen()

外部プロセスを実行する。外部プロセスの完了を待たず後続処理を実行できる。 

どっちを使うの?

今回やりたいことは冒頭で書いた通り

  • サブ画面が開いている間も、Home画面は操作可能にする(=「Open」ボタンを何度も押せる=サブ画面を複数開ける)

です。つまり、「サブ画面を起動する」というプロセスを実行した後も、引き続きHome画面のプロセスを実行する、ということなので、ここではsubprocess.Popen()を使います。

 

そうではなくて、『サブ画面が開いている間は、Home画面の操作をできなくする(サブ画面を閉じると再び操作できるようになる)』

という実装にしたい!という場合は・・・

「サブ画面を起動する」というプロセスを実行したら、そのプロセスが終了するまでHome画面は待機する、ということなので、subprocess.run()を使いましょう。

subprocess.run()の使い方は↓の記事にまとめました。

tsukune-dora-dora.hatenablog.com

 

以下に実装方法とその解説をのせます。

実装方法

開発環境

OS:Windows 10(64ビット版)

Pythonのバージョン:Python 3.8.2

ファイル構成

Sample

 ├ home.py              # Home画面

 ├ sub_page.py        # サブ画面

ソースコード(※Windows限定のやり方です!)

home.py(Home画面)
import PySimpleGUI as sg
import subprocess

#-------------------------
#-- 背景色を設定 --
#-------------------------
sg.theme('LightBrown11')

#-------------------------
#-- 画面レイアウトを設定 --
#-------------------------
layout = [
    [sg.Text('サブ画面を開いてみよう', font=("Helvetica", 20))],
    [sg.Button('Open', font=("Helvetica", 10), size=(15,0), key='open_sub_page_btn')]
]

#-------------------------
#-- ウィンドウの生成 --
#-------------------------
window = sg.Window('Home画面', layout, size=(400,100))

#-------------------------
#-- イベントループ --
#-------------------------
while True:
    event, values = window.read()

    #--【×】ボタン押下
    if event == None:
        break #画面を閉じる

    #--【Open】ボタン押下
    elif event == 'open_sub_page_btn':

        #『サブ画面』を起動
        proc = subprocess.Popen(r'.\sub_page.py',shell=True)
        #result = proc.communicate()# サブプロセスの完了を待つ場合はコメントアウト解除

window.close()
sub_page.py(サブ画面)
import PySimpleGUI as sg
import subprocess

#-------------------------
#-- 背景色を設定 --
#-------------------------
sg.theme('LightBrown11')

#-------------------------
#-- 画面レイアウトを設定 --
#-------------------------

layout = [
    [sg.Text('成功!', font=("Helvetica", 20))]
]

#-------------------------
#-- ウィンドウの生成 --
#-------------------------
window = sg.Window('サブ画面', layout, size=(400,100))

#-------------------------
#-- イベントループ --
#-------------------------
while True:
    event, values = window.read()

    #--【×】ボタン押下
    if event == None:
        break #画面を閉じる

window.close()

ソースコードの解説

subprocess モジュールを使うために、まずはライブラリをインポートします。

home.py(Home画面)

import subprocess

 

subprocess.Popen()を呼び出し、引数を渡します。

home.py(Home画面)

        #『サブ画面』を起動
        proc = subprocess.Popen(r'.\sub_page.py',shell=True)

 

第1引数には、実行したいコマンド(ここではサブ画面の起動を命令するコマンド)を指定します。第2引数の「shell=True」は何かと言いますと...これがないと以下のエラーが発生します。

OSError: [WinError 193] %1 は有効な Win32 アプリケーションではありません。

 subprocess.Popen()は「Linuxコマンドを実行する」ものらしいので、Windowsコマンドは理解できないようです。「shell=True」を指定することで、コマンドプロンプト cmd.exe が呼び出され、その上でコマンドが実行されるらしいです(以下の記事を参考にしました)。

qiita.com

 

なおsubprocess.Popen()でも、subprocess.run()のように外部プロセスの完了を待つことはできます。以下の3行目のコメントアウト(#result=…の行です)を解除すればOKです。

home.py(Home画面)

        #『サブ画面』を起動
        proc = subprocess.Popen(r'.\sub_page.py',shell=True)
        #result = proc.communicate()# サブプロセスの完了を待つ場合はコメントアウト解除

 

サブ画面が開いている間は、Home画面の操作をできなくなります(サブ画面を閉じると再び操作できるようになる)。

 

以上です。

はじめまして

 PySimpleGUIPythonGUIを構築するためのライブラリ)を使い、趣味でレシピ検索ツールのようなデスクトップアプリを作っています。デスクトップアプリ作成を通して学んだPySimpleGUIの豆知識を、この備忘録に書き残します。

 

PySimpleGUIのサンプルコードはネット上にたくさん転がっていますが、なかなか求めている動きを再現する、痒い所に手が届くようなコードって少ないですよね…ほぼ0に近い!

 

(※PySimpleGUIに飽きたら別のプログラミング言語にも手を出すと思います)