【Python / pywebview】画面上の操作でアプリを閉じる
画面上のボタンでアプリケーションを終了する
pywebview
で実行しているアプリケーションを終了するには、ウィンドウの✕ボタンで画面を閉じるのが簡単です。しかしアプリケーションの使途によっては、異なる方法でも終了できる機能を実装したいこともあるでしょう。
本記事では、真理値を使った単純な方法を一つ紹介します。
公式の情報
引用
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
は画面にApi
クラスを作ります。
destroy()
は
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):
...
しかし今回の引数はwindow
とqFlag
との二つになっています。
def destroy(window: webview.Window, qFlag: QuitFlag):
...
このように引数が複数ある場合は、リスト[window, qFlag]
にして纏めます。
# 複数の引数は[]で囲む
webview.start(destroy, [window, qFlag])
跋
本記事の方法よりも効率的、合理的な手があるかもしれません。とは言え終了すればよいのであれば、とりあえずこれでもよいでしょう。
Discussion
コメント失礼します。私も丁度
pywebview
で同じケースに遭遇したので共有します。webview
モジュールのactive_window()
関数またはwindows
属性を用いることで対象のウインドウオブジェクトを取得することが出来ます。したがって、JS側にAPIとして以下のようなものを渡せばJS側からapiを実行するだけでウィンドウが閉じれます。
以下のページが参考になりました。