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