HOME | 6. Listbox を使ってお花を愛でましょう | Python | 8. Menu を使ったシンプル 画像 Viewer | download | 書き込む |
お題は画像ファイル Viewer (viewer.py) です。これだと前回までの話を引き継げるし、 無理なくいろいろな widget を使えます。生成する Window (図1) をみてお分かりになるように、いろいろな Widget が使ってあります。
前回までの解説でお分かりになったと思いますが、Tkinter の widget の使い方は 種類にかかわらず同じです。つまり、
(b) |
(c) |
(d) |
(e) |
図1.viewer.py で生成する Window。
a) メイン window。
b) オリジナルサイズの画像に (GIF の場合)背景色をつけたもの。
c) 背景色調節用 window
d) ディレクトリ選択 window
e) 説明 window
[code 1] (viewer.py)
01: #! /usr/bin/env python 02: # -*- coding: shift_jis -*- 03: 04: """ 05: viewer.py 06: 07: view images in a directory 08: 09: June 30, 2005 10: """ 11: 12: import re 13: import os 14: import os.path as P 15: import Tkinter as Tk 16: import Image as I 17: import ImageTk as Itk 18: import tkFileDialog as D 19: import tkMessageBox as M 20: 21: 22: SIZE = 100 23: IMAGR_TYPES = ['gif', 'png', 'bmp', 'jpg', 'tif', 'ppm'] 24: MAM_COLN = 6 25: GEO_MAIN = '+20+20' 26: GEO_SATE = '+750+50' 27: GEO_SCAL = '+750+400' 28: BGS = [('aliceblue', '#F0F8FF'), ('azure', '#F0FFFF'), ('beige', '#F5F5DC'), \ 29: ('cornsilk', '#FFF8DC'), ('khaki', '#F0E68C'), ('lightgreen', '#90EE90'), \ 30: ('lightpink', '#FFB6C1'), ('lightskyblue', '#87CEFA'), ('palegreen', '#98FB98')] 31: 32: 33: ## functions ------------------------------------------------ 34: def get_size(tup): 35: """ It returns the size of images on the summary""" 36: x, y = tup 37: if (x<=100 and y<=100): 38: return (x, y) 39: elif x > y: 40: r = float(SIZE) / float(x) 41: return (100, int(y*r)) 42: else: 43: r = float(SIZE) / float(y) 44: return (int(x*r), 100) 45: 46: 47: def make_regexp(types): 48: """ It returns the regular expression of the image file type""" 49: str = "\.(" 50: for k, v in types.iteritems(): 51: if v.get(): 52: str += k + '|' 53: 54: str = str[0:-1] + ')$' 55: return re.compile(str, re.I) 56: 57: 58: ## classes ------------------------------------------------------------------ 59: class ImageLabel(Tk.Frame): 60: """ A Label class to show an image """ 61: 62: id_original_size = None # ID of the Label showing an original size image 63: bg_var = None # variable for background color 64: 65: def __init__(self, master, image_file, img): 66: Tk.Frame.__init__(self, master) 67: self.image = img 68: self.image_file = image_file 69: img_label=Tk.Label(self, image=self.image) 70: img_label.pack() 71: txt_label=Tk.Label(self, text=P.basename(self.image_file), font=('Helvetica', '8')) 72: txt_label.pack() 73: img_label.bind('<Double-Button-1>', self.show) 74: 75: def show(self, event): 76: label = ImageLabel.id_original_size 77: if (label and label.winfo_exists()): 78: top = label.winfo_toplevel() 79: top.destroy() 80: top = Tk.Toplevel(self) 81: top.title(P.basename(self.image_file)) 82: top.geometry(GEO_SATE) 83: img = I.open(self.image_file) 84: self.timg = Itk.PhotoImage(img) 85: label=Tk.Label(top, image=self.timg, bg=ImageLabel.bg_var.get()) 86: label.pack() 87: ImageLabel.id_original_size = label 88: 89: 90: 91: class ImageFrame: 92: """ A Class to show summary of images """ 93: 94: def __init__(self, master, **key): 95: self.master=master 96: self.key = key 97: self.frame=Tk.Frame(master, **key) 98: self.frame.pack(padx=5, pady=5) 99: self.once = False 100: 101: def update(self, dir, types): 102: if self.once: 103: self.frame.destroy() 104: self.frame=Tk.Frame(self.master, **self.key) 105: self.frame.pack(padx=5, pady=5) 106: self.once = True 107: pat = make_regexp(types) 108: files = [P.join(dir, file) for file in os.listdir(dir) if pat.search(file)] 109: for i, file in enumerate(files): 110: img_temp = I.open(file) 111: img = img_temp.resize(get_size(img_temp.size), I.NEAREST) 112: tkimg = Itk.PhotoImage(img) 113: la = ImageLabel(self.frame, file, tkimg) 114: la.grid(row = i/MAM_COLN, column=i%MAM_COLN, sticky=Tk.S+Tk.W+Tk.E) 115: 116: 117: 118: class Frame(Tk.Frame): 119: """ The main class of this program. """ 120: 121: def __init__(self, master=None): 122: Tk.Frame.__init__(self, master) 123: self.master.title('Image Viewer') 124: self.master.geometry(GEO_MAIN) 125: self.cus_top = None 126: 127: f_dir = Tk.LabelFrame(self, text='Directory') 128: f_dir.pack(anchor=Tk.W, padx=10, pady=2) 129: self.e_dir = Tk.Entry(f_dir, width=50) 130: self.e_dir.pack(side=Tk.LEFT) 131: self.e_dir.bind('<Return>', self.show_sum) 132: self.b_dir = Tk.Button(f_dir, text='Browse', command=self.browse) 133: self.b_dir.pack(side=Tk.LEFT, padx=2) 134: f=Tk.Frame(self) 135: f.pack(fill=Tk.X) 136: b_info=Tk.Button(f, bitmap='info', width=25, command=self.show_info) 137: b_info.pack(side=Tk.RIGHT, padx=20, pady=10, anchor=Tk.CENTER) 138: f_type = Tk.LabelFrame(f, text='File Type') 139: f_type.pack(side=Tk.LEFT, padx=10, pady=2) 140: b_custom_bg = Tk.Button(f, text='Customize Background', command=self.cus_bg) 141: b_custom_bg.pack(side=Tk.LEFT, anchor=Tk.S, padx=10) 142: 143: self.var_type = dict() 144: for image_type in IMAGR_TYPES: 145: self.var_type[image_type] = Tk.IntVar() 146: cb = Tk.Checkbutton(f_type, text=image_type, variable=self.var_type[image_type], 147: relief=Tk.FLAT, justify = Tk.LEFT) 148: cb.select() 149: cb.pack(side=Tk.LEFT, padx=5) 150: 151: ImageLabel.bg_var = Tk.StringVar() 152: ImageLabel.bg_var.set('#FFFFFF') 153: 154: self.f_bg = Tk.LabelFrame(self, text='Background') 155: self.f_bg.pack(anchor=Tk.W, padx=10, pady=2) 156: 157: for name, code in BGS: 158: rb = Tk.Radiobutton(self.f_bg, text=name, variable=ImageLabel.bg_var, value=code, 159: bg=code, command=self.change_bg, bd=1, relief=Tk.GROOVE) 160: rb.pack(side=Tk.LEFT, padx=5) 161: 162: self.image_frame = ImageFrame(self, relief=Tk.RIDGE, border=2) 163: 164: 165: 166: 167: def change_bg(self): 168: bg1 = ImageLabel.bg_var.get() 169: label = ImageLabel.id_original_size 170: if label and label.winfo_exists(): 171: label.configure(bg=bg1) 172: top = label.winfo_toplevel() 173: top.focus_set() 174: 175: def browse(self): 176: dir = D.askdirectory() 177: if dir: 178: self.e_dir.delete(0, Tk.END) 179: self.e_dir.insert(0, dir) 180: self.image_frame.update(dir, self.var_type) 181: 182: def show_sum(self, event): 183: self.image_frame.update(self.e_dir.get(), self.var_type) 184: 185: 186: def show_info(self): 187: M.showinfo(u"使い方", u"Entry か Browse ボタンでディレクトリを選択してください。\n" 188: u"そのディレクトリに含まれる画像ファイルの一覧が表示されます。\n" 189: u"一覧にある画像をクリックすると、別窓でオリジナルサイズの画像が表示されます。\n" 190: u"透過型 GIF の場合は背景色を変えることができます。\n" 191: u"ラジオボタンにある背景色が気に入らない場合は、\n" 192: u"Customize Background ボタンを押して現れる\n赤、緑、青用の3つのスケールで" 193: u"背景色を調節してください。") 194: 195: def cus_bg(self): 196: if not (self.cus_top and self.cus_top.winfo_exists()): 197: self.cus_top = Tk.Toplevel(self) 198: self.cus_top.title('Create Back Ground') 199: self.cus_top.geometry(GEO_SCAL) 200: cusf = Tk.Frame(self.cus_top) 201: cusf.pack(fill=Tk.BOTH, padx=10, pady=10) 202: self.scale = dict() 203: for i, color in enumerate(('red', 'green', 'blue')): 204: l=Tk.Label(cusf, text=color+': ', anchor=Tk.W, fg=color, font=('Helvetica', '10', 'bold')) 205: l.grid(row=i, column=0, sticky=Tk.W) 206: self.scale[color] = Tk.Scale(cusf, orient=Tk.HORIZONTAL, length=300, from_=0, to=255, 207: command=self.customize_bg, tickinterval=50) 208: self.scale[color].set(255) 209: self.scale[color].grid(row=i, column=1) 210: 211: self.cus_top.bind('<FocusIn>', self.customize_bg) 212: 213: def customize_bg(self, event): 214: ImageLabel.bg_var.set('#%02X%02X%02X' % 215: (self.scale['red'].get(), self.scale['green'].get(), self.scale['blue'].get())) 216: self.change_bg() 217: 218: ##------------------------------------------------ 219: 220: if __name__ == '__main__': 221: f = Frame() 222: f.pack() 223: f.mainloop()
このプログラムのミソは、ImageLabel クラスです。 刺激に反応する Widget は Tk.Widget の派生クラスとして 定義するとうまく書けます。与えられた刺激にどう反応するかを method として含めてしまえばいいのです。 また、クラス変数 id_original_size と bg_var を定義してメインフレーム (図1a) と ImageLabel のインスタンスで変数を共有しています。
プログラムが若干長いので、部分ごとに説明していきたいと思います。見出しのカッコ内の数字はコードの行数です。
定数 | 説明 |
---|---|
SIZE | 一覧に表示する画像のサイズです。 |
IMAGR_TYPES | 画像ファイルの種類です。 |
MAM_COLN | 一覧に表示する列の数です。 |
GEO_MAIN | メイン window の位置を指定します。 |
GEO_SATE | 原寸画像 window の位置を指定します。 |
GEO_SCAL | 背景色調節 window の位置を指定します。 |
BGS | あらかじめ登録されている背景色のリストです。 |
以下にに使用例を示します。
[code 2](jcheck.py)
01: #! /usr/bin/env python 02: # -*- coding: shift_jis -*- 03: """ 04: jcheck.py 05: 06: """ 07: 08: 09: import Tkinter as Tk 10: 11: class Frame(Tk.Frame): 12: def __init__(self, master=None): 13: Tk.Frame.__init__(self, master) 14: la = Tk.Label(self, text=u"普段お使いの OS は何ですか?(複数選択可)") 15: la.pack(padx=5, pady=5) 16: f1 = Tk.Frame(self) 17: f1.pack(padx=5, pady=5) 18: self.str = Tk.StringVar() 19: self.v=dict() 20: for your_os in ['Unix', 'Windows', 'Mac', 'VMS', 'OS/2']: 21: self.v[your_os] = Tk.IntVar() 22: cb = Tk.Checkbutton(f1, text=your_os, variable=self.v[your_os], command=self.echo) 23: cb.pack(side=Tk.LEFT) 24: 25: lb = Tk.Label(self, textvariable = self.str, justify=Tk.LEFT, anchor=Tk.W) 26: lb.pack(padx=5, pady=5, fill=Tk.X) 27: 28: def echo(self): 29: if sum ([v.get() for v in self.v.values()]) == 0: 30: self.str.set(u"私はメインフレームしか使ったことがありません。") 31: else: 32: str = u"私が使っている OS は、\n" 33: for your_os, v in self.v.iteritems(): 34: if v.get(): 35: str += your_os + u"と、" 36: self.str.set(str[0:-2] + u"です。") 37: 38: ##------------------------------------------------ 39: 40: if __name__ == '__main__': 41: f = Frame() 42: f.pack() 43: f.mainloop()こんな感じの window ができます。
Tk.Checkbutton の option とメソッドについては以下を参照してください。
[code 3](jradio.py)
01: #! /usr/bin/env python 02: # -*- coding: shift_jis -*- 03: """ 04: jradio.py 05: 06: """ 07: 08: 09: import Tkinter as Tk 10: 11: COLS = [(u'黒', 'black'), (u'白', 'white'), (u'赤', 'red'), (u'緑', 'green'), (u'黄', 'yellow'), (u'青', 'blue')] 12: 13: 14: def assoc(key, ls): 15: for k, v in ls: 16: if key == k: 17: return v 18: 19: class Frame(Tk.Frame): 20: def __init__(self, master=None): 21: Tk.Frame.__init__(self, master) 22: 23: self.vf = Tk.StringVar() # 文字色 24: self.vb = Tk.StringVar() # 背景色 25: self.str = Tk.StringVar() # 表示文字列 26: 27: 28: 29: ff = Tk.LabelFrame(self, text=u'文字色') 30: ff.pack(padx=5, pady=5) 31: fb = Tk.LabelFrame(self, text=u'背景色') 32: fb.pack(padx=5, pady=5) 33: 34: for jp, en in COLS: 35: # 文字色の選択肢 36: rbf = Tk.Radiobutton(ff, text=jp, variable=self.vf, value=jp, command=self.echo) 37: if en == 'black': 38: rbf.select() 39: rbf.pack(side=Tk.LEFT) 40: # 背景色の選択肢 41: rbb = Tk.Radiobutton(fb, text=jp, variable=self.vb, value=jp, command=self.echo) 42: if en == 'white': 43: rbb.select() 44: rbb.pack(side=Tk.LEFT) 45: 46: self.la = Tk.Label(self, textvariable=self.str, font=('Helvetica', '14', 'bold')) 47: self.la.pack(padx=5, pady=5, fill=Tk.X) 48: 49: self.echo() 50: 51: 52: def echo(self): 53: f = self.vf.get() 54: b = self.vb.get() 55: self.str.set (u'%s地に%s字' % (b, f)) 56: self.la.configure(fg=assoc(f, COLS)) 57: self.la.configure(bg=assoc(b, COLS)) 58: 59: ##------------------------------------------------ 60: 61: if __name__ == '__main__': 62: f = Frame() 63: f.pack() 64: f.mainloop()
こんな感じの window ができます。
Tk.Radiobutton の option とメソッドについては以下を参照してください。
[code 4] (jscale.py)
01: #! /usr/bin/env python 02: # -*- coding: shift_jis -*- 03: """ 04: jscale.py 05: 06: """ 07: 08: 09: import Tkinter as Tk 10: 11: 12: def e2j(en): 13: if en=='red': 14: return u'赤' 15: elif en=='green': 16: return u'緑' 17: else: 18: return u'青' 19: 20: 21: def change_bg_rec(item, color): 22: item.configure(bg=color) 23: for child in item.winfo_children(): 24: change_bg_rec(child, color) 25: 26: 27: 28: class Frame(Tk.Frame): 29: def __init__(self, master=None): 30: Tk.Frame.__init__(self, master) 31: info = Tk.Label(self, text=u'スケールをいじってフレームの色を変えてください。', font=('Helvetica', '12', 'bold')) 32: info.pack(padx=10, pady=5) 33: f = Tk.Frame(self) 34: f.pack(padx=5, pady=5) 35: self.sc = dict() 36: for i, color in enumerate(['red', 'green', 'blue']): 37: la = Tk.Label(f, text=e2j(color), fg=color, font=('Helvetica', '12', 'bold')) 38: la.grid(row=0, column=i, padx=10, pady=5) 39: self.sc[color] = Tk.Scale(f, from_=0, to=255, length=150, bd=0, 40: command=self.change_bg, tickinterval=50, orient=Tk.VERTICAL) 41: self.sc[color].set(255) 42: self.sc[color].grid(row=1, column=i, padx=10, pady=5) 43: 44: 45: def change_bg(self, event): 46: color = '#%02X%02X%02X' % (self.sc['red'].get(), self.sc['green'].get(), self.sc['blue'].get()) 47: change_bg_rec(self, color) 48: 49: 50: 51: ##------------------------------------------------ 52: 53: if __name__ == '__main__': 54: f = Frame() 55: f.pack() 56: f.mainloop()
こんな感じの window ができます。
Tk.Scale の option とメソッドについては以下を参照してください。
[code 5](jspinbox.py)
01: #! /usr/bin/env python 02: # -*- coding: shift_jis -*- 03: """ 04: jspinbox.py 05: """ 06: 07: 08: 09: import Tkinter as Tk 10: 11: 12: CONSTELLATIONS = ( u'水瓶座', u'魚 座', u'牡羊座', u'牡牛座', u'双子座', u'蟹 座', u'獅子座', 13: u'乙女座', u'天秤座', u'蠍 座', u'射手座', u'山羊座') 14: 15: 16: BLOOD = ('A', 'B', 'O', 'AB') 17: 18: FORTUNE = [u'大吉', u'中吉', u'吉', u'凶'] 19: 20: 21: def position(obj, tup): 22: for i, o in enumerate(tup): 23: if o==obj: 24: return i 25: 26: class Frame(Tk.Frame): 27: def __init__(self, master=None): 28: Tk.Frame.__init__(self, master) 29: info = Tk.Label(self, text=u'Spinbox をつかったいかさま占い。') 30: info.pack(padx=5, pady=5) 31: f = Tk.Frame(self) 32: f.pack(padx=5, pady=5) 33: lb=Tk.Label(f, text=u'血液型') 34: lb.grid(row=0, column=0, padx=5, pady=5) 35: self.sb=Tk.Spinbox(f, values=BLOOD) 36: self.sb.grid(row=0, column=1, padx=5, pady=5) 37: lc=Tk.Label(f, text=u'星座') 38: lc.grid(row=1, column=0, padx=5, pady=5) 39: self.sc = Tk.Spinbox(f, values=CONSTELLATIONS) 40: self.sc.grid(row=1, column=1, padx=5, pady=5) 41: b=Tk.Button(self, text=u'占う', command=self.tell_fortune) 42: b.pack(padx=5, pady=5) 43: self.fortune=Tk.StringVar() 44: lf = Tk.Label(self, textvariable=self.fortune, fg='red', font=('Helvetica', '14', 'bold')) 45: lf.pack(padx=5, pady=5) 46: 47: def tell_fortune(self): 48: i = position(self.sb.get(), BLOOD) + 1 49: j = position(self.sc.get(), CONSTELLATIONS) + 1 50: self.fortune.set(FORTUNE[(i*j*j)%4]) 51: 52: 53: ##------------------------------------------------ 54: 55: if __name__ == '__main__': 56: f = Frame() 57: f.pack() 58: f.mainloop()
こんな感じの window ができます。
option, method については、The Tkinter Spinbox Widge
を参照してください。
[code 5](jtop.py)
こんな感じの window ができます。
3.7. Tk.Toplevel
別 Window を表示するための Widget です。作成するときに親 widget を指定することができ、
親 widget があるときは親 widget が消えると親子関係にある toplevel も消えます。
[code 5] に例を示します。
01: #! /usr/bin/env python
02: # -*- coding: shift_jis -*-
03: """
04: jtop.py
05:
06: """
07:
08:
09: import Tkinter as Tk
10:
11: class Mtop:
12: def __init__(self, master):
13: self.master = master
14:
15: def __call__(self, event=None):
16: top = Tk.Toplevel(self.master)
17: f = Tk.Frame(top)
18: f.pack()
19: la = Tk.Label(f, text=self.master and u'子供' or u'他人', font =('Helvetica', '12'))
20: la.pack()
21: lb = Tk.Label(f, text=self.master and u'この Toplevel は親フレームとともに消えます。' or
22: u'この Toplevel は親フレームが消えても残ります。' )
23: lb.pack()
24:
25: class Frame(Tk.Frame):
26: def __init__(self, master=None):
27: Tk.Frame.__init__(self, master)
28: l = Tk.Label(self, text=u'下のボタンを押して、下の \'親フレーム\' と親子関係にある TopLevel と \n'
29: u'独立した Toplevel を作成してください。\n'
30: u'それから、\'親フレームを消す\'ボタンを押すと、\n親フレームと、親子関係にある Toplevel が消え、\n'
31: u'独立した Toplebel は残ります。', justify=Tk.LEFT)
32: l.pack(padx=10, pady=5)
33: f = Tk.LabelFrame(self, text=u'親フレーム')
34: f.pack(padx=10, pady=5)
35: bc = Tk.Button(f, text=u'親フレームの子供のトップレベルを作成', command=Mtop(f))
36: bc.pack(fill=Tk.X, pady=5, padx=10)
37: bn = Tk.Button(f, text=u'他人のトップレベルを作成', command=Mtop(None))
38: bn.pack(fill=Tk.X, pady=5, padx=10)
39: bd = Tk.Button(f, text=u'親フレームを消す', command=f.destroy)
40: bd.pack(fill=Tk.X, pady=5, padx=10)
41:
42:
43:
44: ##------------------------------------------------
45:
46: if __name__ == '__main__':
47: f = Frame()
48: f.pack()
49: f.mainloop()
Tk.Toplevel の option とメソッドについては以下を参照してください。
3.8. tkFileDialog
ファイル(名)を取得するダイアログを生成するモジュールです。
以下の関数があります。
askdirectory(**options) | ディレクトリ名を入力するダイアログを表示し、ディレクトリ名を返します。 |
askopenfile(mode='r', **options) | ファイル名を入力するダイアログを表示し、開いたファイルハンドルを返します。 |
askopenfilename(**options) | ファイル名を入力するダイアログを表示し、ファイル名を返します。 |
askopenfilenames(**options) | ファイル名を入力するダイアログを表示し、ファイル名のリストを返します。 |
askopenfiles(mode='r', **options) | ファイル名を入力するダイアログを表示し、ファイルハンドルのリストを返します。 |
asksaveasfile(mode='w', **options) | ファイル名を入力するダイアログを表示し、開いているファイルハンドルを返します。 |
asksaveasfilename(**options) | ファイル名を入力するダイアログを表示し、ファイル名を返します。 |
[code 6] に選択したファイルを開いて、標準出力に最初の 15 行を出力するプログラムを示します。
[code 6](py_head.py)
01: #! /usr/bin/env python 02: # -*- coding: shift_jis -*- 03: 04: import tkFileDialog as FD 05: 06: f = FD.askopenfile(mode='r', initialfile='index.html', 07: initialdir='D:/doc/05-07/sh_home', 08: filetypes =[('html files', ('*.html', '*.htm')), 09: ('text files', ('*.txt', '*.css'))]) 10: 11: 12: for i, l in enumerate(f): 13: if i<15: 14: print '%02d: %s' % (i+1, l.rstrip()) 15:
askokcancel(title=None, message=None, **options) | OK か Cancel か聞いてきます。OK なら True を返します。 |
askquestion(title=None, message=None, **options) | 何か質問をします。 |
askretrycancel(title=None, message=None, **options) | 再試行するか聞いてきます。 Yes → True |
askyesno(title=None, message=None, **options) | 質問をします。 Yes → True |
showerror(title=None, message=None, **options) | エラーメッセージを表示します。 |
showinfo(title=None, message=None, **options) | Info を表示します。 |
showwarning(title=None, message=None, **options) | 警告を表示します。 |
[code 7] (jdialog.py)
01: #! /usr/bin/env python 02: # -*- coding: shift_jis -*- 03: 04: import Tkinter as Tk 05: import Dialog as D 06: 07: FLOWERS = [u'あさがお', u'タンポポ', u'ゆり', u'はす', u'桜'] 08: 09: class Frame (Tk.Frame): 10: def __init__(self, master=None, **key): 11: Tk.Frame.__init__(self, master, **key) 12: self.master.title(u'好きな花はなんですか') 13: svar = Tk.StringVar() 14: label = Tk.Label(textvariable=svar, font=('Helvetica', '12')) 15: label.pack(fill=Tk.BOTH, expand=1) 16: dialog = D.Dialog(self, title=u'好きな花', 17: text=u'下のボタンから好きな花を選んでください。', 18: bitmap='question', 19: default=0, 20: strings=FLOWERS) 21: svar.set(u'%s がお好きなのですね。' % FLOWERS[dialog.num]) 22: 23: if __name__=='__main__': 24: f = Frame() 25: f.pack(fill=Tk.BOTH, expand=1) 26: f.mainloop()
こんな感じの window ができます。
16 行目の Dialog で、回答を促すダイアログを生成します。 最初の引数は親 widget, 残りはキーワードパラメターです。
さて、今回作った Image Viewer は Widget が多くてうるさいので、 メニューバーにまとめたものを次回作ります。 また、一覧を表示するのがフレームだとスクロールバーがつけられないので、 一覧を ScrolledText に表示するようにします。
HOME | 6. Listbox を使ってお花を愛でましょう | Python | 8. Menu を使ったシンプル 画像 Viewer | download | 書き込む |