Tkinterでオブジェクトを複数、変数に依存して作る(覚え)


環境

・macOS High Sierra 10.13.6
・Python 3.8.8
・tkinter 8.6.10
・エディタ Atom
 ・AtomはデフォルトでPythonの実行をサポートしていないので、必要なパッケージをダウンロードする必要がある

はじめに

tkinterでインターフェイスを作るときに、似たようなオブジェクトを複数作りたいときがある。
とりあえず良さそうな方法が見つかったのでちょっと覚書きする。

GUIの基本

まずはHeloo world!に相当するコードを書く。以下の通り。

main.py
from tkinter import *
from tkinter import ttk

root = Tk()
root.title('My App')

#ウィジェットの作成
label_1 = ttk.Label(root,text='Hello World!')

#レイアウト
label_1.pack()

# ウィンドウの表示開始
root.mainloop()

実行すると次のようなウィンドウが表示される

さて、表示したいラベルが複数ある場合、たとえば

main.py
from tkinter import *
from tkinter import ttk

root = Tk()
root.title('My App')

#ウィジェットの作成
label_1 = ttk.Label(root,text='Hello World!')
label_2 = ttk.Label(root,text='Hello World!')
label_3 = ttk.Label(root,text='Hello World!')
label_4 = ttk.Label(root,text='Hello World!')
label_5 = ttk.Label(root,text='Hello World!')

#レイアウト
label_1.pack()
label_2.pack()
label_3.pack()
label_4.pack()
label_5.pack()

# ウィンドウの表示開始
root.mainloop()

表示は以下のようになる。

以上のようにするのが手っ取り早いのは直感的にわかるが、このコードでは、表示したい行の数が変わったときにコードの大部分を修正する必要があるし、表示させたいオブジェクトが大量にあるときには役に立たないので別の方法を考える。

オブジェクトの作成数を変数依存化する

例として、ビートルズのメンバーのリストを与え、それをラベルで表示するGUIを考える

main.py
from tkinter import *
from tkinter import ttk

root = Tk()
root.title('The Beatles')

member = ['John Lennon','Paul McCartney','George Harrison','Ringo Starr']

#ウィジェットの作成
labels = [ttk.Label(root,text=x) for x in member]

#レイアウト
[labels[i].pack() for i in range(len(labels))]

# ウィンドウの表示開始
root.mainloop()

メンバーのリストはmemberで与えている
まず、リスト内包表記で、memberの中身を一つずつ取り出したものをに一度格納し、それをtext属性の値としてttk.Labelオブジェクトを作る。
labelsは、ttk.Labelオブジェクトがメンバーの数と同じ長さを持ったオブジェクトである。

labels = [ttk.Label(root,text=x) for x in member]

つぎに、同じくリスト内包表記を使って、表示すべきlabelsの長さと同じ連番を持つrangeオブジェクトから順次値を取り出し、それに対応するlabels[i]を順次表示させる。

[labels[i].pack() for i in range(len(labels))]

何をやっているのかリスト内包表記にいなれていないとわかりにくいかもしれないが、for文で考えると、その中でやっていることはラベルを表示することだけで、値がオブジェクトが何かに代入されているわけではない。

for i in range(len(labels)):
    labels[i].pack()

表示は以下のようになる。

これで、冗長なコードを書く必要性はなくなった。