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