HOME | 4. タイマーにボタンをつけよう | Python | 6. Listbox を使ってお花を愛でましょう | download | 書き込む |
しかし、関数のクラスを用いると、あたかも引数をとる関数と Button や Event が バインドしたように見えます。
ここでは、図1に示す画像の背景を変えるプログラムを例にとって 説明していきたいと思います。
[code 1]
01: #! /usr/bin/env python 02: 03: """ 04: bg1.py 05: 06: Change Background of flower 07: 08: June 28, 2005 09: """ 10: 11: 12: import Tkinter as Tk 13: 14: FLOWER = 'nanohana3.gif' 15: 16: class Frame(Tk.Frame): 17: 18: def __init__(self, master=None): 19: Tk.Frame.__init__(self, master) 20: self.master.title('select background') 21: f_button = Tk.Frame(self) 22: f_button.pack(side=Tk.LEFT, padx=5, pady=5) 23: self.flower = Tk.PhotoImage(file=FLOWER) 24: self.label = Tk.Label(self, image=self.flower, relief=Tk.RAISED, bd=3) 25: self.label.pack(side=Tk.RIGHT, padx =5) 26: 27: b_aliceblue = Tk.Button(f_button, text='aliceblue', bg='#F0F8FF', command=self.c_aliceblue) 28: b_azure = Tk.Button(f_button, text='azure', bg='#F0FFFF', command=self.c_azure) 29: b_beige = Tk.Button(f_button, text='beige', bg='#F5F5DC', command=self.c_beige) 30: b_cornsilk = Tk.Button(f_button, text='cornsilk', bg='#FFF8DC', command=self.c_cornsilk) 31: b_khaki = Tk.Button(f_button, text='khaki', bg='#F0E68C', command=self.c_khaki) 32: b_lightgreen = Tk.Button(f_button, text='lightgreen', bg='#90EE90', command=self.c_lightgreen) 33: b_lightpink = Tk.Button(f_button, text='lightpink', bg='#FFB6C1', command=self.c_lightpink) 34: b_lightskyblue = Tk.Button(f_button, text='lightskyblue', bg='#87CEFA', command=self.c_lightskyblue) 35: b_palegreen = Tk.Button(f_button, text='palegreen', bg='#98FB98', command=self.c_palegreen) 36: 37: b_aliceblue.pack(fill=Tk.X) 38: b_azure.pack(fill=Tk.X) 39: b_beige.pack(fill=Tk.X) 40: b_cornsilk.pack(fill=Tk.X) 41: b_khaki.pack(fill=Tk.X) 42: b_lightgreen.pack(fill=Tk.X) 43: b_lightpink.pack(fill=Tk.X) 44: b_lightskyblue.pack(fill=Tk.X) 45: b_palegreen.pack(fill=Tk.X) 46: 47: def c_cornsilk(self): 48: self.label.configure(bg='#FFF8DC') 49: 50: def c_khaki(self): 51: self.label.configure(bg='#F0E68C') 52: 53: def c_lightgreen(self): 54: self.label.configure(bg='#90EE90') 55: 56: def c_lightpink(self): 57: self.label.configure(bg='#FFB6C1') 58: 59: def c_lightskyblue(self): 60: self.label.configure(bg='#87CEFA') 61: 62: def c_palegreen(self): 63: self.label.configure(bg='#98FB98') 64: 65: def c_azure(self): 66: self.label.configure(bg='#F0FFFF') 67: 68: def c_aliceblue(self): 69: self.label.configure(bg='#F0F8FF') 70: 71: def c_beige(self): 72: self.label.configure(bg='#F5F5DC') 73: 74: 75: ##------------------------------------------------ 76: 77: if __name__ == '__main__': 78: f = Frame() 79: f.pack() 80: f.mainloop()見てわかると思いますが、同じようなコードが9回現れるのできわめて冗長です。 特に目新しい部分はないので説明は省略したいと思います。
個の場合は Tk.Button の導出クラス Button を定義し、そのメソッドとして背景色の変更を定義します。 コードは下の [code 2] のようになります。
[code 2]
01: #! /usr/bin/env python 02: 03: """ 04: bg2.py 05: 06: Change Background of flower 07: 08: June 28, 2005 09: """ 10: 11: 12: import Tkinter as Tk 13: 14: FLOWER = 'nanohana3.gif' 15: 16: 17: BGS = [('aliceblue', #F0F8FF'), ('azure', '#F0FFFF'), ('beige', '#F5F5DC'), \ 18: ('cornsilk', '#FFF8DC'), ('khaki', '#F0E68C'), ('lightgreen', '#90EE90'), \ 19: ('lightpink', '#FFB6C1'), ('lightskyblue', '#87CEFA'), ('palegreen', '#98FB98')] 20: 21: 22: class Button(Tk.Button): 23: 24: def __init__(self, master, label, color_name, color_code): 25: Tk.Button.__init__(self, master, text=color_name, bg=color_code, command=self.bg_change) 26: self.label = label 27: self.color_code = color_code 28: 29: def bg_change(self): 30: self.label.configure(bg=self.color_code) 31: 32: 33: 34: class Frame(Tk.Frame): 35: 36: def __init__(self, master=None): 37: Tk.Frame.__init__(self, master) 38: self.master.title('select background') 39: f_button = Tk.Frame(self) 40: f_button.pack(side=Tk.LEFT, padx=5, pady=5) 41: self.flower = Tk.PhotoImage(file=FLOWER) 42: label = Tk.Label(self, image=self.flower, relief=Tk.RAISED, bd=3) 43: label.pack(side=Tk.RIGHT, padx =5) 44: 45: for name, code in BGS: 46: b = Button(f_button, label, name, code) 47: b.pack(fill=Tk.X) 48: 49: 50: 51: ##------------------------------------------------ 52: 53: if __name__ == '__main__': 54: f = Frame() 55: f.pack() 56: f.mainloop()ずいぶんすっきりと書けました。下に簡単な解説を示します。括弧の数字はソースコードの行番号です。
そもそも、グループ化したかったのは関数のほうであり、ボタンではありませんでした。 従って、上の方法は OOP の一般的な解決法ですが、問題が残ります。
そこで、お勧めなのが関数のクラスを用いる方法です。Python では関数のクラスをサポートしていて、 似たような関数をクラス定義から作り出すことができます。
早速コードを [code 3] に示します。
[code 3]
01: #! /usr/bin/env python 02: 03: """ 04: bg3.py 05: 06: Change Background of flower 07: 08: June 28, 2005 09: """ 10: 11: 12: import Tkinter as Tk 13: 14: FLOWER = 'nanohana3.gif' 15: 16: 17: BGS = [('aliceblue', '#F0F8FF'), ('azure', '#F0FFFF'), ('beige', '#F5F5DC'), \ 18: ('cornsilk', '#FFF8DC'), ('khaki', '#F0E68C'), ('lightgreen', '#90EE90'), \ 19: ('lightpink', '#FFB6C1'), ('lightskyblue', '#87CEFA'), ('palegreen', '#98FB98')] 20: 21: 22: class BgChange: 23: 24: def __init__(self, label, color): 25: self.label = label 26: self.color = color 27: 28: def __call__(self, event=None): 29: self.label.configure(bg=self.color) 30: 31: 32: class Frame(Tk.Frame): 33: 34: def __init__(self, master=None): 35: Tk.Frame.__init__(self, master) 36: self.master.title('select background') 37: f_button = Tk.Frame(self) 38: f_button.pack(side=Tk.LEFT, padx=5, pady=5) 39: self.flower = Tk.PhotoImage(file=FLOWER) 40: label = Tk.Label(self, image=self.flower, relief=Tk.RAISED, bd=3) 41: label.pack(side=Tk.RIGHT, padx =5) 42: 43: for name, code in BGS: 44: b = Tk.Button(f_button, text=name, bg=code, command=BgChange(label, code)) 45: b.pack(fill=Tk.X) 46: 47: 48: ##------------------------------------------------ 49: 50: if __name__ == '__main__': 51: f = Frame() 52: f.pack() 53: f.mainloop()[code 3] で注目して欲しいのは、22--29 行目の class BgChange の 定義の部分です。 これは、ラベルの背景色を変える関数のクラスの定義です。
まず、初期化するとき (__init__) は self, label, color の3つの変数を取ります。 label, color を内部変数に保持して、呼び出されるときに使います。
呼び出されるとき (__call__) は self, event の2つの変数を取ります。event は optional 変数なのでなくても差し支えありません。こうすることによって、ボタンを押されたときも、マウスやキーボード操作 などのイベントで呼び出されたときにも対処することができます。呼び出されると、 初期化したときに保持しておいた self.label と self.color を使って、背景の色を変えます。
このようにすると、45 行目のように Tk.Button の command オプションで、あたかも引数をとる関数を指定できるように なります。もう少し、詳しく説明すると、45 行目では、label と code から関数のクラス BgChange のインスタンスを作り、そのポインターを command にバインドしています。そして、これが呼び出されるときは 1 ないし 2 引数の関数として呼び出され、ラベルの背景色を変えるという動作をします。
この方法は Tk.Button のほかに Tk.Menu などのそのほかの widget や event にそのまま使えるので、 お勧めです。コードも Tk.Widget の導出クラスを作るよりもさらに短くなります。
また、Tcl/Tk の command は引数をとる関数を指定するので、Tcl/Tk のコードを翻訳するときにも 関数のクラスは有効です。つまり、Tcl/Tk の関数を Python の関数クラスとして定義しなおすことで、 他の部分を変更しないで、翻訳することができます。
HOME | 4. タイマーにボタンをつけよう | Python | 6. Listbox を使ってお花を愛でましょう | download | 書き込む |