blob: 4d11ce0209481f57e1e9c20aa5094e9e0037a085 [file] [log] [blame]
Guido van Rossumf55afae1997-08-12 18:21: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
Guido van Rossumd5062ba2000-02-24 15:01:43 +000014'''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
Guido van Rossumf55afae1997-08-12 18:21:21 +000028from Tkinter import *
29import os
30
31class Dialog(Toplevel):
32
Guido van Rossumd5062ba2000-02-24 15:01:43 +000033 '''Class to open dialogs.
34
35 This class is intended as a base class for custom dialogs
36 '''
37
Guido van Rossumf55afae1997-08-12 18:21:21 +000038 def __init__(self, parent, title = None):
39
Guido van Rossumd5062ba2000-02-24 15:01:43 +000040 '''Initialize a dialog.
41
42 Arguments:
43
44 parent -- a parent window (the application window)
45
46 title -- the dialog title
47 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +000048 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
Martin v. Löwisb217cd82004-08-03 18:36:25 +000064 self.wait_visibility() # window needs to be visible for the grab
Guido van Rossumf55afae1997-08-12 18:21:21 +000065 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
Fred Drake6b04ffe2001-12-06 16:51:41 +000072 if self.parent is not None:
73 self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
74 parent.winfo_rooty()+50))
Guido van Rossumf55afae1997-08-12 18:21:21 +000075
76 self.initial_focus.focus_set()
77
78 self.wait_window(self)
79
Guido van Rossum7ea8f841999-06-25 15:53:54 +000080 def destroy(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +000081 '''Destroy the window'''
Guido van Rossum7ea8f841999-06-25 15:53:54 +000082 self.initial_focus = None
83 Toplevel.destroy(self)
84
Guido van Rossumf55afae1997-08-12 18:21:21 +000085 #
86 # construction hooks
87
88 def body(self, master):
Guido van Rossumd5062ba2000-02-24 15:01:43 +000089 '''create dialog body.
Guido van Rossumf55afae1997-08-12 18:21:21 +000090
Fred Draked038ca82000-10-23 18:31:14 +000091 return widget that should have initial focus.
Guido van Rossumd5062ba2000-02-24 15:01:43 +000092 This method should be overridden, and is called
93 by the __init__ method.
94 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +000095 pass
96
97 def buttonbox(self):
Fred Draked038ca82000-10-23 18:31:14 +000098 '''add standard button box.
Guido van Rossumd5062ba2000-02-24 15:01:43 +000099
Fred Drake6b04ffe2001-12-06 16:51:41 +0000100 override if you do not want the standard buttons
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000101 '''
Fred Draked038ca82000-10-23 18:31:14 +0000102
Guido van Rossumf55afae1997-08-12 18:21:21 +0000103 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
Fred Drake6b04ffe2001-12-06 16:51:41 +0000134 if self.parent is not None:
135 self.parent.focus_set()
Guido van Rossumf55afae1997-08-12 18:21:21 +0000136 self.destroy()
137
138 #
139 # command hooks
140
141 def validate(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000142 '''validate the data
143
Fred Draked038ca82000-10-23 18:31:14 +0000144 This method is called automatically to validate the data before the
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000145 dialog is destroyed. By default, it always validates OK.
146 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000147
148 return 1 # override
149
150 def apply(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000151 '''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 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000156
157 pass # override
158
159
160# --------------------------------------------------------------------
161# convenience dialogues
162
Guido van Rossumf55afae1997-08-12 18:21:21 +0000163class _QueryDialog(Dialog):
164
165 def __init__(self, title, prompt,
Guido van Rossum1530c871997-08-14 14:17:28 +0000166 initialvalue=None,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000167 minvalue = None, maxvalue = None,
168 parent = None):
169
Guido van Rossumf55afae1997-08-12 18:21:21 +0000170 if not parent:
Guido van Rossum7f202631998-10-12 20:40:09 +0000171 import Tkinter
172 parent = Tkinter._default_root
Guido van Rossumf55afae1997-08-12 18:21:21 +0000173
174 self.prompt = prompt
175 self.minvalue = minvalue
176 self.maxvalue = maxvalue
177
Guido van Rossum1530c871997-08-14 14:17:28 +0000178 self.initialvalue = initialvalue
179
Guido van Rossumf55afae1997-08-12 18:21:21 +0000180 Dialog.__init__(self, parent, title)
181
Guido van Rossum7ea8f841999-06-25 15:53:54 +0000182 def destroy(self):
183 self.entry = None
184 Dialog.destroy(self)
185
Guido van Rossumf55afae1997-08-12 18:21:21 +0000186 def body(self, master):
187
Guido van Rossum1530c871997-08-14 14:17:28 +0000188 w = Label(master, text=self.prompt, justify=LEFT)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000189 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
Guido van Rossum1530c871997-08-14 14:17:28 +0000194 if self.initialvalue:
195 self.entry.insert(0, self.initialvalue)
196 self.entry.select_range(0, END)
197
Guido van Rossumf55afae1997-08-12 18:21:21 +0000198 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(
Guido van Rossum1530c871997-08-14 14:17:28 +0000208 "Illegal value",
Guido van Rossumf55afae1997-08-12 18:21:21 +0000209 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. "
Guido van Rossum1530c871997-08-14 14:17:28 +0000218 "Please try again." % self.minvalue,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000219 parent = self
220 )
221 return 0
222
223 if self.maxvalue is not None and result > self.maxvalue:
224 tkMessageBox.showwarning(
Guido van Rossum1530c871997-08-14 14:17:28 +0000225 "Too large",
Guido van Rossumf55afae1997-08-12 18:21:21 +0000226 "The allowed maximum value is %s. "
Guido van Rossum1530c871997-08-14 14:17:28 +0000227 "Please try again." % self.maxvalue,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000228 parent = self
229 )
230 return 0
Fred Draked038ca82000-10-23 18:31:14 +0000231
Guido van Rossumf55afae1997-08-12 18:21:21 +0000232 self.result = result
233
234 return 1
235
236
237class _QueryInteger(_QueryDialog):
Guido van Rossum1530c871997-08-14 14:17:28 +0000238 errormessage = "Not an integer."
Guido van Rossumf55afae1997-08-12 18:21:21 +0000239 def getresult(self):
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000240 return int(self.entry.get())
Guido van Rossumf55afae1997-08-12 18:21:21 +0000241
242def askinteger(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000243 '''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 '''
Raymond Hettingerff41c482003-04-06 09:01:11 +0000253 d = _QueryInteger(title, prompt, **kw)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000254 return d.result
255
256class _QueryFloat(_QueryDialog):
Guido van Rossum1530c871997-08-14 14:17:28 +0000257 errormessage = "Not a floating point value."
Guido van Rossumf55afae1997-08-12 18:21:21 +0000258 def getresult(self):
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000259 return float(self.entry.get())
Guido van Rossumf55afae1997-08-12 18:21:21 +0000260
261def askfloat(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000262 '''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 '''
Raymond Hettingerff41c482003-04-06 09:01:11 +0000272 d = _QueryFloat(title, prompt, **kw)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000273 return d.result
274
275class _QueryString(_QueryDialog):
Fred Drake6b04ffe2001-12-06 16:51:41 +0000276 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
Guido van Rossumf55afae1997-08-12 18:21:21 +0000290 def getresult(self):
291 return self.entry.get()
292
293def askstring(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000294 '''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 '''
Raymond Hettingerff41c482003-04-06 09:01:11 +0000304 d = _QueryString(title, prompt, **kw)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000305 return d.result
306
Fred Draked038ca82000-10-23 18:31:14 +0000307if __name__ == "__main__":
Guido van Rossumf55afae1997-08-12 18:21:21 +0000308
309 root = Tk()
310 root.update()
311
Guido van Rossum1530c871997-08-14 14:17:28 +0000312 print askinteger("Spam", "Egg count", initialvalue=12*12)
313 print askfloat("Spam", "Egg weight\n(in tons)", minvalue=1, maxvalue=100)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000314 print askstring("Spam", "Egg label")