TkinterによるPython GUI開発。第3回

PythonでTkinterを使ってGUIを開発する複数回連載の第3回目です。

このシリーズの他の部分については、以下のリンクをチェックしてください。

  • TkinterによるPythonのGUI開発
  • Tkinterを使ったPythonのGUI開発。パート2
  • TkinterによるPython GUI開発。パート3

TkinterはPythonでGUIを構築するためのデファクトスタンダードパッケージです。

StackAbuseのTkinterチュートリアルの第1部と第2部では、基本的なGUIビルディングブロックを使って簡単なインターフェースを作成する方法を学びました。

チュートリアルの最後のパートでは、複雑で非常に便利な機能を楽に提供するためにTkinterが提供するいくつかのショートカットについて見ていきます。

また、Python Mega Widgetsについて学びます。

これは、Tkinterをベースにしたツールキットで、複雑なインターフェースの構築をより速くすることができます。

ファイルダイアログ

ユーザが自分のマシン上のファイルを選択できるようにすることは、明らかにグラフィカルインターフェイスの非常に一般的な機能です。

ファイルダイアログは通常かなり複雑で、少なくとも複数のボタン(開く、キャンセル、新しいフォルダの作成など)と、環境のディレクトリ構造を表示するフレームが組み合わされています。

これまでのチュートリアルから、Tkinterを使ってこのような複雑な機能を作成するのは非常に難しいと思われるかもしれません。

しかし、実際はそうではありません。

次の例を見てください。

import tkinter
import tkinter.filedialog


root = tkinter.Tk()


def print_path():
    f = tkinter.filedialog.askopenfilename(
        parent=root, initialdir='C:/Tutorial',
        title='Choose file',
        filetypes=[('png images', '.png'),
                   ('gif images', '.gif')]
        )


print(f)


b1 = tkinter.Button(root, text='Print path', command=print_path)
b1.pack(fill='x')


root.mainloop()


出力

上記のコードだけで、素敵で便利なファイルダイアログを表示することができます。

2 行目では filedialog クラスの内容をインポートしています。

そして、4行目で root ウィンドウを作成した後、6行目で新しい関数を定義しています (これは17行目で作成し、18行目でパックしたボタンで実行されることになっています)。

ここでは、print_path()関数の定義を見てみましょう。

7行目で askopenfilename 関数を実行していますが、この関数にはいくつかの引数があります。

最初の引数は、もちろんダイアログの親ウィジェットです(この場合はルートウィンドウです)。

そして、 initialdir 引数には、ファイルダイアログが開かれたときに表示される場所を指定します。

title` は、ダイアログのタイトルバーの内容をコントロールします。

そして、 filetypes 引数は、ファイルダイアログで表示されるファイルの種類を指定します。

ファイルの種類を絞り込むことで、目的のファイルをより速く検索できるようになり、また、どの種類のファイルが受け入れられるかをユーザーに知らせることができます。

filetypes` の引数は2つの要素からなるタプルのリストです。

各タプルの最初の要素は文字列で、各ファイルタイプに設定したい任意の説明です。

2 番目の要素は、各ファイルタイプに関連するファイル拡張子を指定またはリストアップします (拡張子が 1 つだけの場合は文字列、それ以外はタプルです)。

上の出力スクリーンショットでわかるように、ユーザーはダイアログの右下隅にあるドロップダウンリストから表示されたファイルタイプを選択することができます。

maskopenfilename()メソッドは、ユーザが選択したファイルのパスを文字列で返します。

もし、ユーザーがキャンセルを選んだ場合は、空の文字列が返されます。

7行目でパスを変数f` に返し、15行目(ファイルダイアログが閉じた後にのみ実行されます)でパスをコンソールに出力しています。

Tkinterによる画像表示

もう一つ、多くの人がGUIに適用して便利だと思うかもしれない興味深いことに、画像の表示があります。

先ほどの例を少し修正してみましょう。

import tkinter
import tkinter.filedialog


root = tkinter.Tk()


def display_image():
    f = tkinter.filedialog.askopenfilename(
        parent=root, initialdir='C:/Tutorial',
        title='Choose file',
        filetypes=[('png images', '.png'),
                   ('gif images', '.gif')]
        )


new_window = tkinter.Toplevel(root)


image = tkinter.PhotoImage(file=f)
    l1 = tkinter.Label(new_window, image=image)
    l1.image = image
    l1.pack()


b1 = tkinter.Button(root, text='Display image', command=display_image)
b1.pack(fill='x')


root.mainloop()


出力します。

ボタンで実行される関数が display_image に変更され、内部で何が変わったか見てみましょう。

ファイルダイアログを表示し、以前と同じ基準でファイルを選択し、返されたパスを変数 f に格納します。

しかし、ファイルパスを取得した後、それをコンソールに表示することはしません。

そこで、14行目でトップレベルのウィンドウを作成しています。

そして、16行目で PhotoImage クラスのオブジェクトをインスタンス化し、ユーザが選択した .png ファイルを読み込ませています。

このオブジェクトは image 変数に格納され、ライン 17 で Label ウィジェットを作成するための引数として渡されます。

18 行目では、Python のガベージコレクタによって消去されないように、 image オブジェクトへの参照を保持するようにしています。

そして、19行目でラベル(今回はテキストではなく画像を表示)を new_window の中に詰め込みます。

カラーチューザー

もうひとつの一般的な機能、特にグラフィックに焦点を当てたソフトウェアでは、ユーザがパレットから色を選択することができます。

この場合、Tkinterは色選択機能に関する私たちのニーズのほとんどを満たす、素晴らしい、すぐに使えるソリューションを提供します。

import tkinter
import tkinter.colorchooser


root = tkinter.Tk()


def color_button():
    color = tkinter.colorchooser.askcolor(parent=root)
    print(color)
    b1.configure(bg=color[1])


b1 = tkinter.Button(root, text='Select Color', command=color_button)
b1.pack(fill='x')


root.mainloop()


出力

上の例の2行目では、colorchooserというクラスをインポートしています。

7行目では、その askcolor() メソッドを使用しています。

このメソッドは、askopenfilename()と同様に、素敵で複雑なダイアログ(この場合はカラーチューザー)を開き、ユーザーの選択に応じたデータを返す役割を担っています。

この場合、ユーザーがパレットから色を選び、その選択を受け入れた後、変数 color に返されるオブジェクトは、2つの要素を含むタプルになります。

最初の要素は、選択された色の赤、緑、青の各チャンネルの値を格納するタプルである。

タプルの2番目の要素は、16進数で指定された同じ色です。

8行目の print() のおかげで、タプルの中身をコンソールで見ることができます。

maskcolorが返すタプルを変数colorに格納したら、9行目でその変数を使用してb1ボタンを設定します。

すでにご存知のように、bg引数はボタンの背景色を制御する役割を担っています。

ここでは、colorタプルの最初の要素 (16進数で表現した色) を渡しています。

その結果、b1` ボタンを押した後、ユーザーは素敵なカラーチューザーを使ってその背景色を変更することができます。

メッセージボックス

Tkinter から Python Mega Widgets に移る前に、GUI のプログラミングを少し速くする Tkinter モジュールのもう一つの機能について触れておくとよいでしょう。

Tkinterはいわゆるメッセージボックスと呼ばれる、シンプルでありながら広く使われている標準的なダイアログのセットを提供します。

これらのメッセージボックスは、簡単なメッセージや警告を表示したり、ユーザに単純なイエス/ノーの判断をさせるときに使用することができます。

次の例は、Tkinterが提供するすべてのメッセージボックスのデモです。

import tkinter
import tkinter.messagebox


root = tkinter.Tk()


def display_and_print():
    tkinter.messagebox.showinfo("Info","Just so you know")
    tkinter.messagebox.showwarning("Warning","Better be careful")
    tkinter.messagebox.showerror("Error","Something went wrong")


okcancel = tkinter.messagebox.askokcancel("What do you think?","Should we go ahead?")
    print(okcancel)


yesno = tkinter.messagebox.askyesno("What do you think?","Please decide")
    print(yesno)


retrycancel = tkinter.messagebox.askretrycancel("What do you think?","Should we try again?")
    print(retrycancel)


answer = tkinter.messagebox.askquestion("What do you think?","What's your answer?")
    print(answer)


b1 = tkinter.Button(root, text='Display dialogs', command=display_and_print)
b1.pack(fill='x')


top.mainloop()


出力

今回は、b1ボタンが関数 display_and_print() を実行します。

この関数により、7つのメッセージボックスが順番にポップアップ表示されます。

11行目から21行目で定義されているダイアログは、利用可能な2つのオプションのうち1つを選択するようユーザーに要求するダイアログです。

それぞれの場合において、ダイアログを定義する際に2つの引数を渡すことができます。

1つ目は常にダイアログのタイトルで、2つ目はそのメインメッセージの内容を含んでいます。

それでは、一番上から見ていきましょう。

7行目では、シンプルな showinfo ダイアログを定義しています。

このダイアログは、中立的なアイコン、メッセージ、そしてそれを閉じるための OK ボタンを表示するだけのものです。

8 行目と 9 行目では、同じようなシンプルなタイプのメッセージボックスがありますが、そのアイコンはユーザーからの注意が必要なこと (showwarning) やエラーが発生したこと (showerror) を示しています。

3 つのケースで、ダイアログが表示されたときにそれぞれ異なる音が鳴ることに注意してください。

先に述べたように、11 行目から 21 行目までは、ユーザーの決定を得るためのダイアログを表示するためのコードです。

askokcancel (行 11) は、ユーザーが OK をクリックした場合は True を、キャンセルをクリックした場合は False を返します。

askyesno (ライン14) はユーザーが Yes をクリックすると True を、No をクリックすると False を返します。

askretrycancel (ライン17) はユーザーが再試行をクリックすると True を、Cancel をクリックすると False を返します。

askquestionaskyesno と非常によく似ていますが、ユーザーが Yes をクリックした場合は 'yes' を、No をクリックした場合は 'no' を返します。

ファイルダイアログ、カラーチューザー、そしてすべてのメッセージボックスの正確な外観は、コードが実行されるオペレーティングシステムとシステム言語に依存することに留意してください。

プログレスバー

高度な GUI のもう一つの便利な要素はプログレスバーです。

次の例では、Tkinterを使用してこの機能を簡単に実装しています。

import tkinter
import time
from tkinter import ttk


root = tkinter.Tk()


def start():
    for k in range(1, 11):
        progress_var.set(k)
        print("STEP", k)
        k += 1
        time.sleep(1)
        root.update_idletasks()


b1 = tkinter.Button(root, text="START", command=start)
b1.pack(side="left")


progress_var = tkinter.IntVar()


pb = ttk.Progressbar(root, orient="horizontal",
                     length=200, maximum=10,
                     mode="determinate",
                     var=progress_var)
pb.pack(side="left")


pb["value"] = 0


root.mainloop()


出力

上の例は Progressbar の実装を表しています。

これは tkinter.ttk モジュールの一部であり、Tk 8.5 で導入された Tk テーマのウィジェットセットへのアクセスを提供します。

このため、3行目で ttk モジュールを追加でインポートする必要があります。

プログレスバーの状態は、時間によって制御されます。

バーは、1秒間隔で実行される10ステップで進行します。

このため、2行目で time モジュールをインポートしています。

20 行目で Progressbar を定義しています。

親ウィジェット (root) を定義し、オリエンテーションを “horizontal” にして、長さを 200 ピクセルに設定します。

これは、引数 var を使ってプログレスバーに割り当てられた変数(ここでは progress_var 変数)の値で、プログレスバーが完全に埋め尽くされることを意味しています。

モードを "determinate "に設定します。

これは、コードがprogress_var`の値に基づいて正確に定義されたポイントにインジケータの長さを移動させることを意味します。

バーの進捗を制御する整数型変数 progress_var は18行目で定義されています。

26行目では、辞書のような代入を使って、プログレスバーの初期値を0に設定しています。

15行目では、バーの進行を制御する時計をスタートさせるための Button を作成し、7行目と13行目の間に定義された start() 関数を実行させています。

ここでは、1から10までの値を繰り返し処理する、シンプルな for ループを用意しています。

各反復ごとに progress_var の値が更新され、1ずつ増えていきます。

進行状況を明確に観察するために、各反復の間に1秒間待機します(12行目)。

そして 13 行目でルートウィンドウの update_idletasks() メソッドを使用して、プログラムがプログレスバーの外観を更新するようにしています。

これは、まだ for ループを実行しているにもかかわらず (つまり、技術的にはまだ mainloop() 1 回の繰り返し)、プログラムがプログレスバーの外観を更新するようにしています。

Python Mega Widgets

もしあなたがプロジェクトで Tkinter を広範囲に使っているなら、あなたのコードに Python Mega Widgets を取り入れることを検討するのは良い考えだと思います。

Python Mega Widgets は Tkinter をベースにしたツールキットで、メガウィジェットのセットを提供します:複雑で機能的で比較的美的に優れたウィジェットで、よりシンプルな Tkinter ウィジェットから作られています。

このパッケージの素晴らしいところは、ウィジェットの定義と配置に関する一般的な哲学がTkinterの場合と同じであり、あなたのコードに両方のライブラリを混ぜることができることです。

このチュートリアルの最後に、この強力なツールキットの表面を削ってみましょう。

EntryField Widget

Pmw パッケージの最も便利なウィジェットのひとつに EntryField があります。

以下の例で、それがどのような機能を持つか分析してみましょう。

import tkinter
import Pmw


root = tkinter.Tk()


def color_entry_label():
    color = entry_color.get()
    entry_number.configure(label_bg=color)


entry_color = Pmw.EntryField(root, labelpos="w",
                                 label_text="First name:",
                                 entry_bg="white",
                                 entry_width=15,
                                 validate="alphabetic")


entry_number = Pmw.EntryField(root, labelpos="w",
                                 label_text="Integer:",
                                 entry_bg="white",
                                 entry_width=15,
                                 validate="integer")


ok_button = tkinter.Button(root, text="OK", command=color_entry_label)


entry_color.pack(anchor="e")
entry_number.pack(anchor="e")
ok_button.pack(fill="x")


root.mainloop()


出力

今回は、tkinter をインポートするだけでなく、インストールしたばかりの Pmw パッケージもインポートする必要があります (行 2)。

いつものように、ルートウィンドウを起動するために Tk クラスを使用します。

10-14行目と16-20行目では、2つの Pmw.EntryField ウィジェットを定義しています。

EntryFieldは Tkinter のLabelEntryを機能的にミックスしたもので、便利な機能がいくつか追加されています。

ウィジェットの初期化のための最初の引数は、もちろん親ウィジェットです。

label_text、entry_bgentry_width は、ウィジェットの外観をコントロールするためのものです。

この例で最も興味深いのは、おそらく validate 引数でしょう。

ここでは、ユーザーがフィールドにどのようなデータを入れることができるかを決めることができます。

entry_colorフィールドでは、文字列を想定しているので、validateを "alphabetic" に設定します。

Entry_number ウィジェットでは、整数を想定しているので、 validate 引数の値をそれに設定します。

この方法では、前者の中に数字を、後者の中に文字を入れようとすると、シンボルがウィジェットに表示されず、何か間違ったことをしようとしていることを知らせるシステムサウンドが再生されるだけです。

また、ウィジェットがある種のデータを期待していて、その内容が初期化された瞬間にこの条件に抵触すると、EntryFieldが赤くハイライトされます。

この例でわかるように、ウィンドウを表示した直後は、最初のエントリーフィールドは白く、2番目のエントリーフィールドは赤く表示されています。

これは、空の文字列(エントリーのデフォルトの内容)は「アルファベット」の実体のカテゴリーに入りますが、間違いなく整数ではないからです。

26行目で定義されたボタンは、6行目と8行目の間に定義された color_entry_label() コマンドを実行します。

この関数の目的は、 entry_number ウィジェットのラベルの背景を、 entry_color ウィジェットの内容に従ってペイントすることです。

7 行目では、 get() メソッドを使用して entry_color EntryField の内容を取り出しています。

そして当然ながら、entry_number ウィジェットの外観を変更するために configure() メソッドが使用されます。

いくつかの単純なウィジェットから構成される Pmw ウィジェットの特性を変更するには、どのサブウィジェットを設定するかを指定する必要があることに注意してください (このケースではラベルです。

これが、例えば entryfield_bg ではなく label_bg を設定した理由です)。

EntryField` ウィジェットは視覚的にあまり印象的ではないかもしれません。

しかし、このシンプルな例でさえ、メガウィジェットの可能性を示しています。

このような自己検証型のインターフェースをより複雑に構築するには、プレーンなTkinterを使って同じ効果を実現しようとすると、はるかに多くのコードが必要になります。

ツールキットのドキュメントで説明されている他の強力なメガウィジェットもぜひ試してみてください。

結論

TkinterはPythonのGUIライブラリの一つですが、その大きな利点はPythonの標準と考えられており、今でもすべてのPythonディストリビューションでデフォルトで配布されていることです。

この小さなチュートリアルを楽しんで、コマンドライン操作のソフトウェアに怖気づくかもしれないユーザーのためのインターフェイスを構築することをよく理解していただけたと思います。

$(document).ready(function() {)
$(‘pre code’).each(function(i, block) {)
hljs.lineNumbersBlock(ブロック);
});
});

タイトルとURLをコピーしました