Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | # |
2 | # An Introduction to Tkinter | |
3 | # tkSimpleDialog.py | |
4 | # | |
5 | # Copyright (c) 1997 by Fredrik Lundh | |
6 | # | |
7 | # fredrik@pythonware.com | |
8 | # http://www.pythonware.com | |
9 | # | |
10 | ||
11 | # -------------------------------------------------------------------- | |
12 | # dialog base class | |
13 | ||
14 | '''Dialog boxes | |
15 | ||
16 | This module handles dialog boxes. It contains the following | |
17 | public symbols: | |
18 | ||
19 | Dialog -- a base class for dialogs | |
20 | ||
21 | askinteger -- get an integer from the user | |
22 | ||
23 | askfloat -- get a float from the user | |
24 | ||
25 | askstring -- get a string from the user | |
26 | ''' | |
27 | ||
28 | from Tkinter import * | |
29 | import os | |
30 | ||
31 | class Dialog(Toplevel): | |
32 | ||
33 | '''Class to open dialogs. | |
34 | ||
35 | This class is intended as a base class for custom dialogs | |
36 | ''' | |
37 | ||
38 | def __init__(self, parent, title = None): | |
39 | ||
40 | '''Initialize a dialog. | |
41 | ||
42 | Arguments: | |
43 | ||
44 | parent -- a parent window (the application window) | |
45 | ||
46 | title -- the dialog title | |
47 | ''' | |
48 | Toplevel.__init__(self, parent) | |
49 | self.transient(parent) | |
50 | ||
51 | if title: | |
52 | self.title(title) | |
53 | ||
54 | self.parent = parent | |
55 | ||
56 | self.result = None | |
57 | ||
58 | body = Frame(self) | |
59 | self.initial_focus = self.body(body) | |
60 | body.pack(padx=5, pady=5) | |
61 | ||
62 | self.buttonbox() | |
63 | ||
64 | self.wait_visibility() # window needs to be visible for the grab | |
65 | self.grab_set() | |
66 | ||
67 | if not self.initial_focus: | |
68 | self.initial_focus = self | |
69 | ||
70 | self.protocol("WM_DELETE_WINDOW", self.cancel) | |
71 | ||
72 | if self.parent is not None: | |
73 | self.geometry("+%d+%d" % (parent.winfo_rootx()+50, | |
74 | parent.winfo_rooty()+50)) | |
75 | ||
76 | self.initial_focus.focus_set() | |
77 | ||
78 | self.wait_window(self) | |
79 | ||
80 | def destroy(self): | |
81 | '''Destroy the window''' | |
82 | self.initial_focus = None | |
83 | Toplevel.destroy(self) | |
84 | ||
85 | # | |
86 | # construction hooks | |
87 | ||
88 | def body(self, master): | |
89 | '''create dialog body. | |
90 | ||
91 | return widget that should have initial focus. | |
92 | This method should be overridden, and is called | |
93 | by the __init__ method. | |
94 | ''' | |
95 | pass | |
96 | ||
97 | def buttonbox(self): | |
98 | '''add standard button box. | |
99 | ||
100 | override if you do not want the standard buttons | |
101 | ''' | |
102 | ||
103 | box = Frame(self) | |
104 | ||
105 | w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE) | |
106 | w.pack(side=LEFT, padx=5, pady=5) | |
107 | w = Button(box, text="Cancel", width=10, command=self.cancel) | |
108 | w.pack(side=LEFT, padx=5, pady=5) | |
109 | ||
110 | self.bind("<Return>", self.ok) | |
111 | self.bind("<Escape>", self.cancel) | |
112 | ||
113 | box.pack() | |
114 | ||
115 | # | |
116 | # standard button semantics | |
117 | ||
118 | def ok(self, event=None): | |
119 | ||
120 | if not self.validate(): | |
121 | self.initial_focus.focus_set() # put focus back | |
122 | return | |
123 | ||
124 | self.withdraw() | |
125 | self.update_idletasks() | |
126 | ||
127 | self.apply() | |
128 | ||
129 | self.cancel() | |
130 | ||
131 | def cancel(self, event=None): | |
132 | ||
133 | # put focus back to the parent window | |
134 | if self.parent is not None: | |
135 | self.parent.focus_set() | |
136 | self.destroy() | |
137 | ||
138 | # | |
139 | # command hooks | |
140 | ||
141 | def validate(self): | |
142 | '''validate the data | |
143 | ||
144 | This method is called automatically to validate the data before the | |
145 | dialog is destroyed. By default, it always validates OK. | |
146 | ''' | |
147 | ||
148 | return 1 # override | |
149 | ||
150 | def apply(self): | |
151 | '''process the data | |
152 | ||
153 | This method is called automatically to process the data, *after* | |
154 | the dialog is destroyed. By default, it does nothing. | |
155 | ''' | |
156 | ||
157 | pass # override | |
158 | ||
159 | ||
160 | # -------------------------------------------------------------------- | |
161 | # convenience dialogues | |
162 | ||
163 | class _QueryDialog(Dialog): | |
164 | ||
165 | def __init__(self, title, prompt, | |
166 | initialvalue=None, | |
167 | minvalue = None, maxvalue = None, | |
168 | parent = None): | |
169 | ||
170 | if not parent: | |
171 | import Tkinter | |
172 | parent = Tkinter._default_root | |
173 | ||
174 | self.prompt = prompt | |
175 | self.minvalue = minvalue | |
176 | self.maxvalue = maxvalue | |
177 | ||
178 | self.initialvalue = initialvalue | |
179 | ||
180 | Dialog.__init__(self, parent, title) | |
181 | ||
182 | def destroy(self): | |
183 | self.entry = None | |
184 | Dialog.destroy(self) | |
185 | ||
186 | def body(self, master): | |
187 | ||
188 | w = Label(master, text=self.prompt, justify=LEFT) | |
189 | w.grid(row=0, padx=5, sticky=W) | |
190 | ||
191 | self.entry = Entry(master, name="entry") | |
192 | self.entry.grid(row=1, padx=5, sticky=W+E) | |
193 | ||
194 | if self.initialvalue: | |
195 | self.entry.insert(0, self.initialvalue) | |
196 | self.entry.select_range(0, END) | |
197 | ||
198 | return self.entry | |
199 | ||
200 | def validate(self): | |
201 | ||
202 | import tkMessageBox | |
203 | ||
204 | try: | |
205 | result = self.getresult() | |
206 | except ValueError: | |
207 | tkMessageBox.showwarning( | |
208 | "Illegal value", | |
209 | self.errormessage + "\nPlease try again", | |
210 | parent = self | |
211 | ) | |
212 | return 0 | |
213 | ||
214 | if self.minvalue is not None and result < self.minvalue: | |
215 | tkMessageBox.showwarning( | |
216 | "Too small", | |
217 | "The allowed minimum value is %s. " | |
218 | "Please try again." % self.minvalue, | |
219 | parent = self | |
220 | ) | |
221 | return 0 | |
222 | ||
223 | if self.maxvalue is not None and result > self.maxvalue: | |
224 | tkMessageBox.showwarning( | |
225 | "Too large", | |
226 | "The allowed maximum value is %s. " | |
227 | "Please try again." % self.maxvalue, | |
228 | parent = self | |
229 | ) | |
230 | return 0 | |
231 | ||
232 | self.result = result | |
233 | ||
234 | return 1 | |
235 | ||
236 | ||
237 | class _QueryInteger(_QueryDialog): | |
238 | errormessage = "Not an integer." | |
239 | def getresult(self): | |
240 | return int(self.entry.get()) | |
241 | ||
242 | def askinteger(title, prompt, **kw): | |
243 | '''get an integer from the user | |
244 | ||
245 | Arguments: | |
246 | ||
247 | title -- the dialog title | |
248 | prompt -- the label text | |
249 | **kw -- see SimpleDialog class | |
250 | ||
251 | Return value is an integer | |
252 | ''' | |
253 | d = _QueryInteger(title, prompt, **kw) | |
254 | return d.result | |
255 | ||
256 | class _QueryFloat(_QueryDialog): | |
257 | errormessage = "Not a floating point value." | |
258 | def getresult(self): | |
259 | return float(self.entry.get()) | |
260 | ||
261 | def askfloat(title, prompt, **kw): | |
262 | '''get a float from the user | |
263 | ||
264 | Arguments: | |
265 | ||
266 | title -- the dialog title | |
267 | prompt -- the label text | |
268 | **kw -- see SimpleDialog class | |
269 | ||
270 | Return value is a float | |
271 | ''' | |
272 | d = _QueryFloat(title, prompt, **kw) | |
273 | return d.result | |
274 | ||
275 | class _QueryString(_QueryDialog): | |
276 | def __init__(self, *args, **kw): | |
277 | if kw.has_key("show"): | |
278 | self.__show = kw["show"] | |
279 | del kw["show"] | |
280 | else: | |
281 | self.__show = None | |
282 | _QueryDialog.__init__(self, *args, **kw) | |
283 | ||
284 | def body(self, master): | |
285 | entry = _QueryDialog.body(self, master) | |
286 | if self.__show is not None: | |
287 | entry.configure(show=self.__show) | |
288 | return entry | |
289 | ||
290 | def getresult(self): | |
291 | return self.entry.get() | |
292 | ||
293 | def askstring(title, prompt, **kw): | |
294 | '''get a string from the user | |
295 | ||
296 | Arguments: | |
297 | ||
298 | title -- the dialog title | |
299 | prompt -- the label text | |
300 | **kw -- see SimpleDialog class | |
301 | ||
302 | Return value is a string | |
303 | ''' | |
304 | d = _QueryString(title, prompt, **kw) | |
305 | return d.result | |
306 | ||
307 | if __name__ == "__main__": | |
308 | ||
309 | root = Tk() | |
310 | root.update() | |
311 | ||
312 | print askinteger("Spam", "Egg count", initialvalue=12*12) | |
313 | print askfloat("Spam", "Egg weight\n(in tons)", minvalue=1, maxvalue=100) | |
314 | print askstring("Spam", "Egg label") |