tkSimpleDialog.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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. # dialog base class
  12. '''Dialog boxes
  13. This module handles dialog boxes. It contains the following
  14. public symbols:
  15. Dialog -- a base class for dialogs
  16. askinteger -- get an integer from the user
  17. askfloat -- get a float from the user
  18. askstring -- get a string from the user
  19. '''
  20. from Tkinter import *
  21. class Dialog(Toplevel):
  22. '''Class to open dialogs.
  23. This class is intended as a base class for custom dialogs
  24. '''
  25. def __init__(self, parent, title = None):
  26. '''Initialize a dialog.
  27. Arguments:
  28. parent -- a parent window (the application window)
  29. title -- the dialog title
  30. '''
  31. Toplevel.__init__(self, parent)
  32. self.withdraw() # remain invisible for now
  33. # If the master is not viewable, don't
  34. # make the child transient, or else it
  35. # would be opened withdrawn
  36. if parent.winfo_viewable():
  37. self.transient(parent)
  38. if title:
  39. self.title(title)
  40. self.parent = parent
  41. self.result = None
  42. body = Frame(self)
  43. self.initial_focus = self.body(body)
  44. body.pack(padx=5, pady=5)
  45. self.buttonbox()
  46. if not self.initial_focus:
  47. self.initial_focus = self
  48. self.protocol("WM_DELETE_WINDOW", self.cancel)
  49. if self.parent is not None:
  50. self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
  51. parent.winfo_rooty()+50))
  52. self.deiconify() # become visibile now
  53. self.initial_focus.focus_set()
  54. # wait for window to appear on screen before calling grab_set
  55. self.wait_visibility()
  56. self.grab_set()
  57. self.wait_window(self)
  58. def destroy(self):
  59. '''Destroy the window'''
  60. self.initial_focus = None
  61. Toplevel.destroy(self)
  62. #
  63. # construction hooks
  64. def body(self, master):
  65. '''create dialog body.
  66. return widget that should have initial focus.
  67. This method should be overridden, and is called
  68. by the __init__ method.
  69. '''
  70. pass
  71. def buttonbox(self):
  72. '''add standard button box.
  73. override if you do not want the standard buttons
  74. '''
  75. box = Frame(self)
  76. w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
  77. w.pack(side=LEFT, padx=5, pady=5)
  78. w = Button(box, text="Cancel", width=10, command=self.cancel)
  79. w.pack(side=LEFT, padx=5, pady=5)
  80. self.bind("<Return>", self.ok)
  81. self.bind("<Escape>", self.cancel)
  82. box.pack()
  83. #
  84. # standard button semantics
  85. def ok(self, event=None):
  86. if not self.validate():
  87. self.initial_focus.focus_set() # put focus back
  88. return
  89. self.withdraw()
  90. self.update_idletasks()
  91. try:
  92. self.apply()
  93. finally:
  94. self.cancel()
  95. def cancel(self, event=None):
  96. # put focus back to the parent window
  97. if self.parent is not None:
  98. self.parent.focus_set()
  99. self.destroy()
  100. #
  101. # command hooks
  102. def validate(self):
  103. '''validate the data
  104. This method is called automatically to validate the data before the
  105. dialog is destroyed. By default, it always validates OK.
  106. '''
  107. return 1 # override
  108. def apply(self):
  109. '''process the data
  110. This method is called automatically to process the data, *after*
  111. the dialog is destroyed. By default, it does nothing.
  112. '''
  113. pass # override
  114. # --------------------------------------------------------------------
  115. # convenience dialogues
  116. class _QueryDialog(Dialog):
  117. def __init__(self, title, prompt,
  118. initialvalue=None,
  119. minvalue = None, maxvalue = None,
  120. parent = None):
  121. if not parent:
  122. import Tkinter
  123. parent = Tkinter._default_root
  124. self.prompt = prompt
  125. self.minvalue = minvalue
  126. self.maxvalue = maxvalue
  127. self.initialvalue = initialvalue
  128. Dialog.__init__(self, parent, title)
  129. def destroy(self):
  130. self.entry = None
  131. Dialog.destroy(self)
  132. def body(self, master):
  133. w = Label(master, text=self.prompt, justify=LEFT)
  134. w.grid(row=0, padx=5, sticky=W)
  135. self.entry = Entry(master, name="entry")
  136. self.entry.grid(row=1, padx=5, sticky=W+E)
  137. if self.initialvalue is not None:
  138. self.entry.insert(0, self.initialvalue)
  139. self.entry.select_range(0, END)
  140. return self.entry
  141. def validate(self):
  142. import tkMessageBox
  143. try:
  144. result = self.getresult()
  145. except ValueError:
  146. tkMessageBox.showwarning(
  147. "Illegal value",
  148. self.errormessage + "\nPlease try again",
  149. parent = self
  150. )
  151. return 0
  152. if self.minvalue is not None and result < self.minvalue:
  153. tkMessageBox.showwarning(
  154. "Too small",
  155. "The allowed minimum value is %s. "
  156. "Please try again." % self.minvalue,
  157. parent = self
  158. )
  159. return 0
  160. if self.maxvalue is not None and result > self.maxvalue:
  161. tkMessageBox.showwarning(
  162. "Too large",
  163. "The allowed maximum value is %s. "
  164. "Please try again." % self.maxvalue,
  165. parent = self
  166. )
  167. return 0
  168. self.result = result
  169. return 1
  170. class _QueryInteger(_QueryDialog):
  171. errormessage = "Not an integer."
  172. def getresult(self):
  173. return int(self.entry.get())
  174. def askinteger(title, prompt, **kw):
  175. '''get an integer from the user
  176. Arguments:
  177. title -- the dialog title
  178. prompt -- the label text
  179. **kw -- see SimpleDialog class
  180. Return value is an integer
  181. '''
  182. d = _QueryInteger(title, prompt, **kw)
  183. return d.result
  184. class _QueryFloat(_QueryDialog):
  185. errormessage = "Not a floating point value."
  186. def getresult(self):
  187. return float(self.entry.get())
  188. def askfloat(title, prompt, **kw):
  189. '''get a float from the user
  190. Arguments:
  191. title -- the dialog title
  192. prompt -- the label text
  193. **kw -- see SimpleDialog class
  194. Return value is a float
  195. '''
  196. d = _QueryFloat(title, prompt, **kw)
  197. return d.result
  198. class _QueryString(_QueryDialog):
  199. def __init__(self, *args, **kw):
  200. if "show" in kw:
  201. self.__show = kw["show"]
  202. del kw["show"]
  203. else:
  204. self.__show = None
  205. _QueryDialog.__init__(self, *args, **kw)
  206. def body(self, master):
  207. entry = _QueryDialog.body(self, master)
  208. if self.__show is not None:
  209. entry.configure(show=self.__show)
  210. return entry
  211. def getresult(self):
  212. return self.entry.get()
  213. def askstring(title, prompt, **kw):
  214. '''get a string from the user
  215. Arguments:
  216. title -- the dialog title
  217. prompt -- the label text
  218. **kw -- see SimpleDialog class
  219. Return value is a string
  220. '''
  221. d = _QueryString(title, prompt, **kw)
  222. return d.result
  223. if __name__ == "__main__":
  224. root = Tk()
  225. root.update()
  226. print askinteger("Spam", "Egg count", initialvalue=12*12)
  227. print askfloat("Spam", "Egg weight\n(in tons)", minvalue=1, maxvalue=100)
  228. print askstring("Spam", "Egg label")