GUI

Python Tkinter Windows/Dialogs (3) ダイアログ

ダイアログボックスは、アプリケーションにおいて、ユーザーからの情報取得、イベント発生時の通知、アクションの確認などに使用されるウィンドウの一種。ダイアログボックスの外観や使い方は、通常、プラットフォームのスタイルガイドにかなり具体的に記述されている。Tk には、一般的なタスクのためにいくつかのダイアログボックスが組み込まれている。これらは、プラットフォーム固有のスタイル・ガイドラインに適合させるのに役立つ。

ファイルやディレクトリの選択

Tkは、ユーザーがファイルやディレクトリを選択するためのダイアログをいくつか提供している。Windows と macOS では、これらのダイアログは基本的なOSのダイアログを直接呼び出す。ダイアログの「開く」バージョンは、ユーザに既存のファイルを選択させたい場合(「ファイル|開く」メニューコマンドのように)に使用し、「保存」バージョンは、保存するファイルを選択する場合(通常「ファイル|別名で保存」メニューコマンドで使用します)に使用する。

from tkinter import filedialog
filename = filedialog.askopenfilename()
filename = filedialog.asksaveasfilename()
dirname = filedialog.askdirectory()

これらのコマンドはすべてモーダルダイアログを生成する。これは、ユーザーがダイアログを送信するまで、コマンドが完了しないことを意味する。これらのコマンドは、ユーザーが選択したファイルまたはディレクトリのフルパス名を返すか、ユーザーがダイアログをキャンセルした場合は空文字列を返す。

これらのダイアログには様々なオプションを渡すことができ、使用可能なファイルタイプ、初期ディレクトリ、デフォルトのファイル名などを設定することができる。これらの詳細は、getOpenFile (getSaveFileを含む) と chooseDirectoryのリファレンスマニュアルページを参照すること。

色の選択

ユーザーが色を選択させるためのモーダルダイアログ。これは、例えば #ff62b0 のような色の値を返す。このダイアログでは、オプションでinitialcolorを指定し、既存の色(例では#ff0000)、つまりユーザーが置き換えたいと思う色を指定できる。より詳しい情報は、chooseColorのリファレンスマニュアルのページを参照すること。

from tkinter import colorchooser
colorchooser.askcolor(initialcolor='#ff0000')

フォントの選択

Tk 8.6 では、もうひとつのシステムダイアログであるフォントチューザーをサポートした。ファイルダイアログやカラーチューザは、ダイアログを閉じるまでブロックして結果を返すモーダルダイアログだったが、フォントチューザはそのように動作しない。

Windowsなど一部のプラットフォームでは、システムフォントダイアログがモーダルになっているが、どこでもそうだというわけではない。macOS では、システムフォント選択ツールは、描画プログラムのフローティングツールパレットのように動作し、メインアプリケーションウィンドウで選択されているテキストのフォントを変更するために利用可能なままになっている。Tk のフォントダイアログ API は、両方のモデルに対応しなければならない。そのために、コールバック(および仮想イベント)を使用して、フォントの変更をアプリケーションに通知する。詳細は fontchooser のリファレンスマニュアルのページを参照すること。

フォントダイアログを使用するには、まず、初期フォントと、フォントが選択されたときに呼び出されるコールバックを提供する。ここでは、ラベルのフォントを変更するコールバックを用意する。

l = ttk.Label(root, text="Hello World", font="helvetica 24")
l.grid(padx=10, pady=10)

def font_changed(font):
    l['font'] = font

root.tk.call('tk', 'fontchooser', 'configure', '-font', 'helvetica 24', '-command', root.register(font_changed))
root.tk.call('tk', 'fontchooser', 'show')

Tkinterはまだこの新しいダイアログを便利に使う方法を追加していないため、このサンプルコードではTcl APIを直接使用している。適切な Python API に向けた最新の作業と、コードのダウンロードは [Issue#28694] で確認できる。

次に、show メソッドでダイアログを画面上に表示する。フォントダイアログがモーダルなプラットフォームでは、プログラムはダイアログが消えるまでこの時点でブロックされる。他のプラットフォームでは、showはすぐに戻り、ダイアログは画面上に残り、プログラムは続行される。この時点では、フォントはまだ選択されていいない。この時点では、フォントは選択されていない。また、画面から取り除くためのhideメソッドもある。(フォントダイアログがモーダルな場合は、あまり役に立たない)。

root.tk.call('tk', 'fontchooser', 'show')
root.tk.call('tk', 'fontchooser', 'hide')

フォントダイアログがモーダルで、ユーザーがフォントを選択した場合、ダイアログはコールバックを呼び出し、フォント仕様を渡したはずだ。ユーザがダイアログをキャンセルした場合、コールバックは発生しない。ダイアログがモーダルでなく、ユーザがフォントを選択した場合、あなたのコールバックが起動される。<<TkFontchooserFontChanged>> 仮想イベントも生成され、ダイアログのフォント設定オプションで現在のフォントを取得できる。フォントダイアログが閉じられると、<<TkFontchooserVisibility>> 仮想イベントが生成される。フォントダイアログが現在画面上に表示されているかどうかは、visible 設定オプションで確認することもできる(変更はエラーになるため、代わりに show と hide メソッドを使用する)。

アラート・ダイアログと確認ダイアログ

多くのアプリケーションでは、ユーザーにイベントを通知したり、アクションの確認を求めたり、ボタンをクリックして同様の選択をするために、さまざまなシンプルなモーダル警告やダイアログを使用する。Tk は、これらの異なるタイプのダイアログをすべてカプセル化する、多目的な「メッセージボックス」を提供する。

from tkinter import messagebox
messagebox.showinfo(message='いってらっしゃい')
messagebox.askyesno(
	   message='本当に「アプリ名」をインストールしますか?'
	   icon='question' title='インストール')

これまで見てきたダイアログと同様に、これらはモーダルで、ユーザーのアクションの結果を呼び出し元に返す。正確な戻り値は、ここに示すように、コマンドに渡されたtypeオプションに依存する。

ok (default)ok
okcancelok or cancel
yesnoyes or no
yesnocancelyes, no or cancel
retrycancelretry or cancel
abortretryignoreabort, retry or ignore

Tkinterでは、タイプオプションを使用するのではなく、ダイアログのタイプごとに異なるメソッド名を使用する。戻り値はメソッドによって異なる。

showinfo“ok”
showwarning“ok”
showerror“ok”
askokcancelTrue (on ok) or False (on cancel)
askyesnoTrue (on yes) or False (on no)
askretrycancelTrue (on retry) or False (on cancel)
askquestion“yes” or “no”
askyesnocancelTrue (on yes), False (on no), or None (on cancel)

可能なオプションの全リストは、ここに示す。

Type上記の通り
messageアラート内に表示されるメインメッセージ
detail副次的なメッセージ(必要な場合)
titleタイトル。ダイアログウィンドウのタイトル。macOSでは使用されない。
iconinfo(デフォルト)、error、question、warningのいずれか1つ。
defaultデフォルト。デフォルトのボタン、例えばokcancelダイアログのokまたはcancel。
parentこのダイアログが表示されているアプリケーションのウィンドウ。

その他の詳細については、リファレンスマニュアルを参照すること。

自分でロールバックする

モーダルダイアログを自作する必要がある場合、いくつか気をつけなければならないことがあります。例えば、ウィンドウスタイルの設定、ウィンドウの位置決めなど、そのほとんどをこの章の前半で説明した。

まず、ユーザーがダイアログとしか対話できないようにする必要がある。これを行うには、grab_set を使用する。

ダイアログ関数がアプリケーションをブロックするようにしたい場合(すなわち、ダイアログを作成するための呼び出しは、ダイアログが却下されるまで戻ってはならない)、これも可能。通常のイベントループを実行しながら、コールバックやイベントバインディングなどに応答し、ダイアログを破棄して次のステップに進むことができるため。

このやや不可解な例には、モーダルダイアログを作成するために必要な主な手順が含まれている。

ttk.Entry(root).grid()
def dismiss ():
    dlg.grab_release()
    dlg.destroy()

dlg = Toplevel(root)
ttk.Button(dlg, text="Done", command=dismiss).grid()
dlg.protocol("WM_DELETE_WINDOW", dismiss) # クローズボタンをインターセプト
dlg.transient(root) # ダイアログウィンドウをmainに関連付け
dlg.wait_visibility() # ウィンドウが表示されるまで待つ
dlg.grab_set() # すべての入力を私たちのウィンドウへ設定
dlg.wait_window() # ウィンドウが破壊されるまでブロック

Tkinterの標準ライブラリにはsimpledialogモジュールが含まれており、独自のダイアログを構築するのに役立つ。このモジュールは、新しいテーマのウィジェットではなく、古典的なTkウィジェットを使用しているため、直接使用することはお勧めしない。しかし、先ほど説明したダイアログを動作させるためのテクニックのいくつかを使用する方法を説明している。