|
1 #! /usr/bin/env python |
|
2 |
|
3 # A Python function that generates dialog boxes with a text message, |
|
4 # optional bitmap, and any number of buttons. |
|
5 # Cf. Ousterhout, Tcl and the Tk Toolkit, Figs. 27.2-3, pp. 269-270. |
|
6 |
|
7 from Tkinter import * |
|
8 |
|
9 mainWidget = None |
|
10 |
|
11 def dialog(master, title, text, bitmap, default, *args): |
|
12 |
|
13 # 1. Create the top-level window and divide it into top |
|
14 # and bottom parts. |
|
15 |
|
16 w = Toplevel(master, {'class': 'Dialog'}) |
|
17 w.title(title) |
|
18 w.iconname('Dialog') |
|
19 |
|
20 top = Frame(w, {'relief': 'raised', 'bd': 1, |
|
21 Pack: {'side': 'top', 'fill': 'both'}}) |
|
22 bot = Frame(w, {'relief': 'raised', 'bd': 1, |
|
23 Pack: {'side': 'bottom', 'fill': 'both'}}) |
|
24 |
|
25 # 2. Fill the top part with the bitmap and message. |
|
26 |
|
27 msg = Message(top, |
|
28 {'width': '3i', |
|
29 'text': text, |
|
30 'font': '-Adobe-Times-Medium-R-Normal-*-180-*', |
|
31 Pack: {'side': 'right', 'expand': 1, |
|
32 'fill': 'both', |
|
33 'padx': '3m', 'pady': '3m'}}) |
|
34 if bitmap: |
|
35 bm = Label(top, {'bitmap': bitmap, |
|
36 Pack: {'side': 'left', |
|
37 'padx': '3m', 'pady': '3m'}}) |
|
38 |
|
39 # 3. Create a row of buttons at the bottom of the dialog. |
|
40 |
|
41 buttons = [] |
|
42 i = 0 |
|
43 for but in args: |
|
44 b = Button(bot, {'text': but, |
|
45 'command': ('set', 'button', i)}) |
|
46 buttons.append(b) |
|
47 if i == default: |
|
48 bd = Frame(bot, {'relief': 'sunken', 'bd': 1, |
|
49 Pack: {'side': 'left', 'expand': 1, |
|
50 'padx': '3m', 'pady': '2m'}}) |
|
51 b.lift() |
|
52 b.pack ({'in': bd, 'side': 'left', |
|
53 'padx': '2m', 'pady': '2m', |
|
54 'ipadx': '2m', 'ipady': '1m'}) |
|
55 else: |
|
56 b.pack ({'side': 'left', 'expand': 1, |
|
57 'padx': '3m', 'pady': '3m', |
|
58 'ipady': '2m', 'ipady': '1m'}) |
|
59 i = i+1 |
|
60 |
|
61 # 4. Set up a binding for <Return>, if there's a default, |
|
62 # set a grab, and claim the focus too. |
|
63 |
|
64 if default >= 0: |
|
65 w.bind('<Return>', |
|
66 lambda e, b=buttons[default], i=default: |
|
67 (b.flash(), |
|
68 b.setvar('button', i))) |
|
69 |
|
70 oldFocus = w.tk.call('focus') # XXX |
|
71 w.grab_set() |
|
72 w.focus() |
|
73 |
|
74 # 5. Wait for the user to respond, then restore the focus |
|
75 # and return the index of the selected button. |
|
76 |
|
77 w.waitvar('button') |
|
78 w.destroy() |
|
79 w.tk.call('focus', oldFocus) # XXX |
|
80 return w.getint(w.getvar('button')) |
|
81 |
|
82 def strdialog(master, title, text, bitmap, default, *args): |
|
83 |
|
84 # 1. Create the top-level window and divide it into top |
|
85 # and bottom parts. |
|
86 |
|
87 w = Toplevel(master, {'class': 'Dialog'}) |
|
88 w.title(title) |
|
89 w.iconname('Dialog') |
|
90 |
|
91 top = Frame(w, {'relief': 'raised', 'bd': 1, |
|
92 Pack: {'side': 'top', 'fill': 'both'}}) |
|
93 if args: |
|
94 bot = Frame(w, {'relief': 'raised', 'bd': 1, |
|
95 Pack: {'side': 'bottom', 'fill': 'both'}}) |
|
96 |
|
97 # 2. Fill the top part with the bitmap, message and input field. |
|
98 |
|
99 if bitmap: |
|
100 bm = Label(top, {'bitmap': bitmap, |
|
101 Pack: {'side': 'left', |
|
102 'padx': '3m', 'pady': '3m'}}) |
|
103 |
|
104 msg = Message(top, |
|
105 {'width': '3i', |
|
106 'text': text, |
|
107 'font': '-Adobe-Times-Medium-R-Normal-*-180-*', |
|
108 Pack: {'side': 'left', |
|
109 'fill': 'both', |
|
110 'padx': '3m', 'pady': '3m'}}) |
|
111 |
|
112 field = Entry(top, |
|
113 {'relief':'sunken', |
|
114 Pack:{'side':'left', |
|
115 'fill':'x', |
|
116 'expand':1, |
|
117 'padx':'3m', 'pady':'3m'}}) |
|
118 # 3. Create a row of buttons at the bottom of the dialog. |
|
119 |
|
120 buttons = [] |
|
121 i = 0 |
|
122 for but in args: |
|
123 b = Button(bot, {'text': but, |
|
124 'command': ('set', 'button', i)}) |
|
125 buttons.append(b) |
|
126 if i == default: |
|
127 bd = Frame(bot, {'relief': 'sunken', 'bd': 1, |
|
128 Pack: {'side': 'left', 'expand': 1, |
|
129 'padx': '3m', 'pady': '2m'}}) |
|
130 b.lift() |
|
131 b.pack ({'in': bd, 'side': 'left', |
|
132 'padx': '2m', 'pady': '2m', |
|
133 'ipadx': '2m', 'ipady': '1m'}) |
|
134 else: |
|
135 b.pack ({'side': 'left', 'expand': 1, |
|
136 'padx': '3m', 'pady': '3m', |
|
137 'ipady': '2m', 'ipady': '1m'}) |
|
138 i = i+1 |
|
139 |
|
140 # 4. Set up a binding for <Return>, if there's a default, |
|
141 # set a grab, and claim the focus too. |
|
142 |
|
143 if not args: |
|
144 w.bind('<Return>', lambda arg, top=top: top.setvar('button', 0)) |
|
145 field.bind('<Return>', lambda arg, top=top: top.setvar('button', 0)) |
|
146 elif default >= 0: |
|
147 w.bind('<Return>', |
|
148 lambda e, b=buttons[default], i=default: |
|
149 (b.flash(), |
|
150 b.setvar('button', i))) |
|
151 field.bind('<Return>', |
|
152 lambda e, b=buttons[default], i=default: |
|
153 (b.flash(), |
|
154 b.setvar('button', i))) |
|
155 |
|
156 oldFocus = w.tk.call('focus') # XXX |
|
157 w.grab_set() |
|
158 field.focus() |
|
159 |
|
160 # 5. Wait for the user to respond, then restore the focus |
|
161 # and return the index of the selected button. |
|
162 |
|
163 w.waitvar('button') |
|
164 v = field.get() |
|
165 w.destroy() |
|
166 w.tk.call('focus', oldFocus) # XXX |
|
167 if args: |
|
168 return v, w.getint(w.getvar('button')) |
|
169 else: |
|
170 return v |
|
171 |
|
172 def message(str): |
|
173 i = dialog(mainWidget, 'Message', str, '', 0, 'OK') |
|
174 |
|
175 def askyn(str): |
|
176 i = dialog(mainWidget, 'Question', str, '', 0, 'No', 'Yes') |
|
177 return i |
|
178 |
|
179 def askync(str): |
|
180 i = dialog(mainWidget, 'Question', str, '', 0, 'Cancel', 'No', 'Yes') |
|
181 return i-1 |
|
182 |
|
183 def askstr(str): |
|
184 i = strdialog(mainWidget, 'Question', str, '', 0) |
|
185 return i |
|
186 |
|
187 def askfile(str): # XXXX For now... |
|
188 i = strdialog(mainWidget, 'Question', str, '', 0) |
|
189 return i |
|
190 |
|
191 # The rest is the test program. |
|
192 |
|
193 def _go(): |
|
194 i = dialog(mainWidget, |
|
195 'Not Responding', |
|
196 "The file server isn't responding right now; " |
|
197 "I'll keep trying.", |
|
198 '', |
|
199 -1, |
|
200 'OK') |
|
201 print 'pressed button', i |
|
202 i = dialog(mainWidget, |
|
203 'File Modified', |
|
204 'File "tcl.h" has been modified since ' |
|
205 'the last time it was saved. ' |
|
206 'Do you want to save it before exiting the application?', |
|
207 'warning', |
|
208 0, |
|
209 'Save File', |
|
210 'Discard Changes', |
|
211 'Return To Editor') |
|
212 print 'pressed button', i |
|
213 print message('Test of message') |
|
214 print askyn('Test of yes/no') |
|
215 print askync('Test of yes/no/cancel') |
|
216 print askstr('Type a string:') |
|
217 print strdialog(mainWidget, 'Question', 'Another string:', '', |
|
218 0, 'Save', 'Save as text') |
|
219 |
|
220 def _test(): |
|
221 global mainWidget |
|
222 mainWidget = Frame() |
|
223 Pack.config(mainWidget) |
|
224 start = Button(mainWidget, |
|
225 {'text': 'Press Here To Start', 'command': _go}) |
|
226 start.pack() |
|
227 endit = Button(mainWidget, |
|
228 {'text': 'Exit', |
|
229 'command': 'exit', |
|
230 Pack: {'fill' : 'both'}}) |
|
231 mainWidget.mainloop() |
|
232 |
|
233 if __name__ == '__main__': |
|
234 _test() |