HOME Python download 書き込む

6. Listbox を使ってお花を愛でましょう


1. 初めに

今回は、Tk.Listbox から花の画像ファイルを選んで、それを表示するプログラムを2つ作ります。 1つは、ひとつの画像ファイルを選んで、それに背景色をつけて表示するもの(図1)で、 もうひとつは複数の画像ファイルを選んで、それをまとめて表示するものです(図2)。

花の画像は素材屋ひなとん からいただきました。

まず、Tk.Listbox について説明してからプログラムを作っていきたいと思います。


図1


図2

2. Tk.Listbox

Tk.Listbox は以下のように親 widget と option を指定して作成します。
Tk.Listbox(master, **option)
option は次の通りです。
属性 説明
bg or background 背景色
bd or borderwidth 縁の幅
cursor カーソルの形
font フォント
fg or foreground 文字色
height 表示する行数。pixel ではない。
highlightbackground focus があるときの背景色
highlightcolor focus があるときの文字色
highlightthickness focus lighlight の厚さ
relief 縁の形
selectbackground 選択されたときの背景色
selectborderwidth 選択されたときの縁幅
selectforeground 選択されたときの文字色
selectmode 選択のモード。
  • Tk.BROWSE: デフォルトの設定。リストから1つしか選択できない。マウスの位置につれて選択される行も移動する。
  • Tk.SINGLE: マウスの左ボタンを押したアイテムが選択される。
  • Tk.MULTIPLE: 複数の行を選択可能。マウス左ボタンをクリックすると反転する。
  • Tk.EXTENDED: 複数の行を選択可能。マウスのドラッグ、Shift+左ボタン、Ctrl+左ボタンが使用可能。複数選択できる 時の通常の形式。
takefocus Tab キーによる widget の移動の対象にするかどうか。1: する。0: しない。
width 1行の文字数。pixel 数ではない。デフォルトは 20 文字。
xscrollcommand 横スクロークするときのコマンド。
yscrollcommand 縦スクロークするときのコマンド。

また、次に示すメソッドがあります。よく使うのは

です。

表: メソッド一覧
メソッド 説明
.activate ( index ) index で示された行を選択する。
.curselection() 選択された行番号の tuple を返す。複数選択可能なとき、値を取り出すのに使う。
.delete ( first, last=None ) first から last までを削除する。
.get ( first, last=None ) first から last までのテキストのタプルを返す。last が指定されていないときは first にある テキストを返す。
.index ( i ) i のインデックスを返す。
.insert ( index, *elements ) index の位置に *elements を挿入する。最後に挿入したときは index を Tk.END とする。
.nearest ( y ) Listbox の上辺を基準とした y 座標に最も近い index を返す。
.see ( index ) index が見えるように位置を調節する。
.selection_clear ( first, last=None ) first から last までの行を選択解除する。
.selection_includes ( index ) index が選択されていれば 1, そうでなければ 0 を返す。
.selection_set ( first, last=None ) first から last までの行を選択する。
.size() 行数を返す。
.xview() 横スクロール可能にする。
.xview_moveto ( fraction ) fraction のところまで横スクロールする。 fraction は 0.0--1.0 の実数。
.xview_scroll ( number, what ) what で示された単位に従って number だけ横スクロールする。
.yview() 縦スクロール可能にする。
.yview_moveto ( fraction ) fraction のところまで縦スクロールする。 fraction は 0.0--1.0 の実数。
.yview_scroll( number, what ) what で示された単位に従って number だけ横スクロールする。

Tkinter reference: 11. The Listbox widget および、 The Tkinter Listbox Widget も見てください。

3. 縦スクロールバー付 Listbox

縦スクロークバー付 Listbox はよく使うので、定義しておきましょう。 Listbox に Scrollbar をつける方法は、 Tkinter reference: 11.1. Scrolling a Listbox widget も見てください。 付録についている scrolled_listbox.py は次のような内容になっています。

[code 1] (scrolled_listbox.py)

01:     #! /usr/bin/env python
02:     
03:     import Tkinter as Tk
04:     
05:     class ScrolledListbox(Tk.Listbox):
06:         """ Listbox with vertical scroll bar """
07:         
08:         def __init__(self, master, **key):
09:             self.frame = Tk.Frame(master)
10:             self.yscroll = Tk.Scrollbar (self.frame, orient=Tk.VERTICAL)
11:             self.yscroll.pack(side=Tk.RIGHT, fill=Tk.Y, expand=1)
12:             key['yscrollcommand']=self.yscroll.set
13:             Tk.Listbox.__init__(self, self.frame, **key)
14:             self.pack(side=Tk.LEFT, fill=Tk.BOTH, expand=1)
15:             self.yscroll.config(command=self.yview)
16:     
17:             # Copy geometry methods of self.frame 
18:             for m in (Tk.Pack.__dict__.keys() + Tk.Grid.__dict__.keys() + Tk.Place.__dict__.keys()):
19:                 m[0] == '_' or m == 'config' or m == 'configure' or \
20:                     setattr(self, m, getattr(self.frame, m))

3.1. 簡単な説明

以下に簡単な説明を示します。カッコ内はソースコードの行番号です。

4. 花の画像と背景色を選んで表示するプログラム

花の画像と背景色を選んで表示するプログラムを書いてみましょう。 [code 2] にソースコードを示します。

[code 2] (flower_bg.py)

01:     #! /usr/bin/env python
02:     # -*- coding: shift_jis -*-
03:     """
04:     show_flowers.py 
05:     
06:     Change Background of flower
07:     
08:     June 28, 2005
09:     """
10:     
11:     
12:     import Tkinter as Tk
13:     import scrolled_listbox as SL
14:     
15:     # thanks to 素材屋ひなとん(http://www.jttk.zaq.ne.jp/bacsn908/)
16:     FLOWERS = ["suisencut4.gif", "tanpopotouka1.gif", "odamakitouka.gif", "rengetouka2.gif",              \
17:                "ajisaicatmurasaki-a.gif", "cosmos-s.gif", "fujimurasakitouka.gif", "minaesi-5.gif",       \
18:                "hotarubukuro3ko.gif", "burudejinarabi.gif", "aoaji3touka.gif", "sakurasou.gif",           \
19:                "rengetakusann.gif", "nanohana3.gif", "suzurantouka2.gif", "liradai.gif",                  \
20:                "cosmostouka-b.gif", "syunrantouka2.gif", "sakuraeda9.gif", "syoubu-s.gif",                \
21:                "suirenpink-a.gif", "yuri2.gif", "aoasagaoline.gif", "asagaoyoujiro2.gif",                 \
22:                "himawari-l.gif", "yagurumagikutouka1.gif", "susukistouka.gif"]
23:     
24:     
25:     BGS = [('aliceblue', '#F0F8FF'), ('azure', '#F0FFFF'), ('beige', '#F5F5DC'),              \
26:            ('cornsilk', '#FFF8DC'), ('khaki', '#F0E68C'), ('lightgreen', '#90EE90'),          \
27:            ('lightpink', '#FFB6C1'), ('lightskyblue', '#87CEFA'), ('palegreen', '#98FB98')]
28:     
29:     
30:     
31:     class BgChange:
32:     
33:         def __init__(self, label, color):
34:             self.label = label
35:             self.color = color
36:     
37:         def __call__(self, event=None):
38:             self.label.configure(bg=self.color)
39:     
40:     
41:     class Frame(Tk.Frame):
42:         
43:         def __init__(self, master=None):
44:             Tk.Frame.__init__(self, master)
45:             self.master.title('flower image and background')
46:             intro = Tk.Label(self, font=('Helvetica', '12'),  justify=Tk.LEFT, wraplength='8c', 
47:                              text = u"リストボックスから画像ファイル(マウス左ダブルクリック)、"
48:                                     u"ボタンから背景色を選択してください。" 
49:                                     u"左側のラベルに画像が表示されます。")
50:             intro.pack()
51:             f = Tk.Frame(self, bd=3, relief=Tk.RIDGE)
52:             f.pack(fill=Tk.BOTH, expand=1)
53:             
54:             self.listbox = SL.ScrolledListbox(f)
55:             self.listbox.pack(side=Tk.LEFT, padx=5, pady=5, fill=Tk.Y)
56:             self.listbox.bind("<Double-Button-1>", self.change_flower)
57:             self.listbox.insert(Tk.END, *FLOWERS)
58:                 
59:             f_button = Tk.Frame(f)
60:             f_button.pack(side=Tk.LEFT, padx=5, pady=5)
61:             self.flower = Tk.PhotoImage(file=FLOWERS[0])
62:             self.label = Tk.Label(f, image=self.flower, relief=Tk.RAISED, bd=3)
63:             self.label.pack(side=Tk.RIGHT, padx =5)
64:     
65:             for name, code in BGS:
66:                 b = Tk.Button(f_button, text=name,  bg=code, command=BgChange(self.label, code))
67:                 b.pack(fill=Tk.X)
68:     
69:         def change_flower(self, event):
70:             self.flower = Tk.PhotoImage(file=self.listbox.get(Tk.ACTIVE))
71:             self.label.configure(image=self.flower)
72:     
73:                 
74:     ##------------------------------------------------ 
75:     
76:     if __name__ == '__main__':
77:         f = Frame()
78:         f.pack()
79:         f.mainloop()

4.1. 簡単な説明

前回作ったスクリプトと重複する部分があるので、簡単に説明します。 Listbox に関する部分は詳しく説明したいと思います。

カッコ内は行番号です。

図1のように花の色と背景色が近い色だときれいに見えます。試してみてください。

5. 複数の花の画像を選んで表示するプログラム

リストボックスから複数のアイテムを選択するプログラムの例として、 複数の画像ファイルを表示するプルグラムを書いてみました。 ソースコードを [code 2] に示します。

[code 2] (flowers.py)

01:     #! /usr/bin/env python
02:     # -*- coding: shift_jis -*-
03:     """
04:     flowers.py 
05:     
06:     Show flower images
07:     
08:     June 28, 2005
09:     """
10:     
11:     
12:     import Tkinter as Tk
13:     import Image as I
14:     import ImageTk as Itk
15:     import math
16:     import scrolled_listbox as SL
17:     
18:     # thanks to 素材屋ひなとん(http://www.jttk.zaq.ne.jp/bacsn908/)
19:     FLOWERS = ["suisencut4.gif", "tanpopotouka1.gif", "odamakitouka.gif", "rengetouka2.gif",              \
20:                "ajisaicatmurasaki-a.gif", "cosmos-s.gif", "fujimurasakitouka.gif", "minaesi-5.gif",       \
21:                "hotarubukuro3ko.gif", "burudejinarabi.gif", "aoaji3touka.gif", "sakurasou.gif",           \
22:                "rengetakusann.gif", "nanohana3.gif", "suzurantouka2.gif", "liradai.gif",                  \
23:                "cosmostouka-b.gif", "syunrantouka2.gif", "sakuraeda9.gif", "syoubu-s.gif",                \
24:                "suirenpink-a.gif", "yuri2.gif", "aoasagaoline.gif", "asagaoyoujiro2.gif",                 \
25:                "himawari-l.gif", "yagurumagikutouka1.gif", "susukistouka.gif"]
26:     
27:     
28:     SIZE = 100
29:     
30:     
31:     
32:     def get_size(tup):
33:         """ It returns the size of images on the summary"""
34:         x, y = tup
35:         if (x<=100 and y<=100):
36:             return (x, y)
37:         elif x > y:
38:             r = float(SIZE) / float(x)
39:             return (100, int(y*r))
40:         else:
41:             r = float(SIZE) / float(y)
42:             return (int(x*r), 100)
43:             
44:     
45:     
46:     class Frame(Tk.Frame):
47:         
48:         def __init__(self, master=None):
49:             Tk.Frame.__init__(self, master)
50:             self.master.title('show flower images')
51:             intro = Tk.Label(self, font=('Helvetica', '12'),  justify=Tk.LEFT, wraplength='11c', width=50,
52:                              text =
53:               u"リストボックスから画像ファイルを選択してください。"
54:               u"左ボタンのドラッグ、Shift + 左ボタン、Ctrl + 左ボタン などで複数の画像の選択が可能です。\n"
55:               u"選択が終わったら、マウス右ボタンをクリックしてください。"
56:               u"選択された画像が左側に表示されます。")
57:               
58:             intro.pack()
59:             self.f = Tk.Frame(self, bd=3, relief=Tk.RIDGE)
60:             self.f.pack(fill=Tk.BOTH, expand=1)
61:             
62:             self.listbox = SL.ScrolledListbox(self.f, selectmode=Tk.EXTENDED)
63:             self.listbox.pack(side=Tk.LEFT, padx=5, pady=5, fill=Tk.Y)
64:             self.listbox.bind("<3>", self.show_flowers)
65:             self.listbox.insert(Tk.END, *FLOWERS)
66:                 
67:             self.renew()
68:             
69:     
70:         def show_flowers(self, event):
71:             if self.images:
72:                 self.ff.destroy()
73:                 self.renew()
74:                 
75:             selected = [ int(x) for x in self.listbox.curselection()]
76:             span = int(math.ceil(math.sqrt(len(selected))))
77:             for i, j in  enumerate(selected):
78:                 img = I.open(FLOWERS[j])
79:                 img = img.resize(get_size(img.size))
80:                 tkimg = Itk.PhotoImage(img)
81:                 la = Tk.Label(self.ff, image=tkimg)
82:                 la.grid(row=i/span, column=i%span, sticky=Tk.SW)
83:                 self.images.append(tkimg)
84:             self.listbox.selection_clear(min(selected), max(selected))
85:     
86:     
87:         def renew(self):
88:             self.images = []
89:             self.ff = Tk.Frame(self.f, border=3, relief=Tk.RAISED)
90:             self.ff.pack(side=Tk.RIGHT, fill=Tk.BOTH, expand=1, padx =5)
91:             
92:             
93:     ##------------------------------------------------ 
94:     
95:     if __name__ == '__main__':
96:         f = Frame()
97:         f.pack()
98:         f.mainloop()
99:     

5.1. 簡単な説明。

かなりの部分が [code 2] と同じですので、[code 2] と違っている点を主に説明します。 カッコ内の数字はソースコードの行番号です。