🔚

【Python / pywebview】画面上の操作でアプリを閉じる

に公開1

画面上のボタンでアプリケーションを終了する

pywebviewで実行しているアプリケーションを終了するには、ウィンドウの✕ボタンで画面を閉じるのが簡単です。しかしアプリケーションの使途によっては、異なる方法でも終了できる機能を実装したいこともあるでしょう。

本記事では、真理値を使った単純な方法を一つ紹介します。

公式の情報

https://pywebview.flowrl.com/examples/destroy_window.html

引用
import time

import webview

def destroy(window):
    # show the window for a few seconds before destroying it:
    time.sleep(5)
    print('Destroying window..')
    window.destroy()
    print('Destroyed!')

if __name__ == '__main__':
    window = webview.create_window('Destroy Window Example', 'https://pywebview.flowrl.com/hello')
    webview.start(destroy, window)
    print('Window is destroyed')

公式の情報を見ると、時限式で勝手に終了するものが紹介されています。要点は次。

1. 終了用関数を作る

destroy()という関数を作り、その中でwindow.destroy()を実行しています。

def destroy(window):
    ...
    window.destroy()
    ...

2. 画面のオブジェクトを保持しておく

webview.create_window()から画面のオブジェクトを取得しておきます。

window = webview.create_window('Destroy Window Example', 'https://pywebview.flowrl.com/hello')

3. start()に終了用関数とオブジェクトとを引き渡す

アプリケーションを始動するwebview.start()に、先の二つを引き渡します。これにより、関数destroy()に引数windowが与えられます。

webview.start(destroy, window)

本題

時限式で終わられても困るので、画面のボタンを押すことで終了するようにします。

プログラムと実行例

実行例
実行例

import time
import webview

# 終了用のフラグ
class QuitFlag:
    def __init__(self):
        self._flag = True

    # getter
    @property
    def flag(self):
        return self._flag

    # setter
    @flag.setter
    def flag(self, flag):
        self._flag = flag

# JavaScript用API
class Api():
    def __init__(self, qFlag: QuitFlag):
        # フラグオブジェクトを参照する
        self._qFlag = qFlag

    # フラグをFalseにする
    def exit(self):
        self._qFlag.flag = False

    # getter
    # setterは定義していないため、変更されにくくなる
    @property
    def qFlag(self):
        return self._qFlag

# 初期化
qFlag = QuitFlag()
api = Api(qFlag)

# 終了用関数
def destroy(window: webview.Window, qFlag: QuitFlag):
    # フラグがTrueの間ループし続ける
    while qFlag.flag:
        # print(f'flag: {qFlag.flag} ({qFlag})')
        time.sleep(2) # 2秒待機

    # フラグがFalseになるとループを抜け、終了処理に移行する
    window.destroy()

# 画面オブジェクト
window = webview.create_window(
    "Close Test",
    # JavaScriptからは「pywebview.api.exit()」で呼び出す
    html = "<button onclick='pywebview.api.exit()'>Click to close</button>",
    js_api = api
)
# 複数の引数は[]で囲む
webview.start(destroy, [window, qFlag])

0. Apiクラスについて

pywebviewは画面にWeb技術を使っているため、画面上の処理はPythonではなく、JavaScriptを使うのが簡単です。従って、表層のJavaScriptから内奥のPythonを呼び出す手段として、Apiクラスを作ります。

JavaScriptから使える機能は、このクラスに実装されたものが全てです。例えば、終了用関数destroy()JavaScriptから使うことができません。

1. 終了用フラグ:QuitFlag

画面のボタンを押すことで終了するために、本記事では単純なフラグを使います。変数一つよりクラスの方が安心感があったのでクラスにしています。

class QuitFlag:
    def __init__(self):
        self._flag = True

    # getter
    @property
    def flag(self):
        return self._flag

    # setter
    @flag.setter
    def flag(self, flag):
        self._flag = flag

Apiクラスでこれを参照し、画面から干渉できるようにしています。

class Api():
    ...

    # フラグをFalseにする
    def exit(self):
        self._qFlag.flag = False

    ...

ボタンのクリックにこれを対応付けます。これにより、ボタンを押すことでフラグがFalseに変わるようになりました。

<button onclick='pywebview.api.exit()'>Click to close</button>

2. 終了用関数:destroy

画面のボタンが押されるまでの間、単純なループで待機します。ボタンが押されるとフラグがFalseになるため、ループを抜け、window.destroy()でアプリケーションが終了します。

def destroy(window: webview.Window, qFlag: QuitFlag):
    # フラグがTrueの間ループし続ける
    while qFlag.flag:
        # print(f'flag: {qFlag.flag} ({qFlag})')
        time.sleep(2) # 2秒待機

    # フラグがFalseになるとループを抜け、終了処理に移行する
    window.destroy()

3. 始動と複数の引数

公式のものでは関数destroy()の引数がwindow一つでした。

def destroy(window):
    ...

しかし今回の引数はwindowqFlagとの二つになっています。

def destroy(window: webview.Window, qFlag: QuitFlag):
    ...

このように引数が複数ある場合は、リスト[window, qFlag]にして纏めます。

# 複数の引数は[]で囲む
webview.start(destroy, [window, qFlag])

本記事の方法よりも効率的、合理的な手があるかもしれません。とは言え終了すればよいのであれば、とりあえずこれでもよいでしょう。

Discussion

ハルミハルミ

コメント失礼します。私も丁度pywebviewで同じケースに遭遇したので共有します。

webviewモジュールのactive_window()関数またはwindows属性を用いることで対象のウインドウオブジェクトを取得することが出来ます。

したがって、JS側にAPIとして以下のようなものを渡せばJS側からapiを実行するだけでウィンドウが閉じれます。

class API():
    def onClosing():
        window = webview.active_window()
        window.destroy()

以下のページが参考になりました。
https://pywebview.flowrl.com/guide/usage.html#basics