logo

oasis-root

Compiled tree of Oasis Linux based on own branch at <https://hacktivis.me/git/oasis/> git clone https://anongit.hacktivis.me/git/oasis-root.git

simpledialog.py (11753B)


  1. #
  2. # An Introduction to Tkinter
  3. #
  4. # Copyright (c) 1997 by Fredrik Lundh
  5. #
  6. # This copyright applies to Dialog, askinteger, askfloat and asktring
  7. #
  8. # fredrik@pythonware.com
  9. # http://www.pythonware.com
  10. #
  11. """This modules handles dialog boxes.
  12. It contains the following public symbols:
  13. SimpleDialog -- A simple but flexible modal dialog box
  14. Dialog -- a base class for dialogs
  15. askinteger -- get an integer from the user
  16. askfloat -- get a float from the user
  17. askstring -- get a string from the user
  18. """
  19. from tkinter import *
  20. from tkinter import _get_temp_root, _destroy_temp_root
  21. from tkinter import messagebox
  22. class SimpleDialog:
  23. def __init__(self, master,
  24. text='', buttons=[], default=None, cancel=None,
  25. title=None, class_=None):
  26. if class_:
  27. self.root = Toplevel(master, class_=class_)
  28. else:
  29. self.root = Toplevel(master)
  30. if title:
  31. self.root.title(title)
  32. self.root.iconname(title)
  33. _setup_dialog(self.root)
  34. self.message = Message(self.root, text=text, aspect=400)
  35. self.message.pack(expand=1, fill=BOTH)
  36. self.frame = Frame(self.root)
  37. self.frame.pack()
  38. self.num = default
  39. self.cancel = cancel
  40. self.default = default
  41. self.root.bind('<Return>', self.return_event)
  42. for num in range(len(buttons)):
  43. s = buttons[num]
  44. b = Button(self.frame, text=s,
  45. command=(lambda self=self, num=num: self.done(num)))
  46. if num == default:
  47. b.config(relief=RIDGE, borderwidth=8)
  48. b.pack(side=LEFT, fill=BOTH, expand=1)
  49. self.root.protocol('WM_DELETE_WINDOW', self.wm_delete_window)
  50. self.root.transient(master)
  51. _place_window(self.root, master)
  52. def go(self):
  53. self.root.wait_visibility()
  54. self.root.grab_set()
  55. self.root.mainloop()
  56. self.root.destroy()
  57. return self.num
  58. def return_event(self, event):
  59. if self.default is None:
  60. self.root.bell()
  61. else:
  62. self.done(self.default)
  63. def wm_delete_window(self):
  64. if self.cancel is None:
  65. self.root.bell()
  66. else:
  67. self.done(self.cancel)
  68. def done(self, num):
  69. self.num = num
  70. self.root.quit()
  71. class Dialog(Toplevel):
  72. '''Class to open dialogs.
  73. This class is intended as a base class for custom dialogs
  74. '''
  75. def __init__(self, parent, title = None):
  76. '''Initialize a dialog.
  77. Arguments:
  78. parent -- a parent window (the application window)
  79. title -- the dialog title
  80. '''
  81. master = parent
  82. if master is None:
  83. master = _get_temp_root()
  84. Toplevel.__init__(self, master)
  85. self.withdraw() # remain invisible for now
  86. # If the parent is not viewable, don't
  87. # make the child transient, or else it
  88. # would be opened withdrawn
  89. if parent is not None and parent.winfo_viewable():
  90. self.transient(parent)
  91. if title:
  92. self.title(title)
  93. _setup_dialog(self)
  94. self.parent = parent
  95. self.result = None
  96. body = Frame(self)
  97. self.initial_focus = self.body(body)
  98. body.pack(padx=5, pady=5)
  99. self.buttonbox()
  100. if self.initial_focus is None:
  101. self.initial_focus = self
  102. self.protocol("WM_DELETE_WINDOW", self.cancel)
  103. _place_window(self, parent)
  104. self.initial_focus.focus_set()
  105. # wait for window to appear on screen before calling grab_set
  106. self.wait_visibility()
  107. self.grab_set()
  108. self.wait_window(self)
  109. def destroy(self):
  110. '''Destroy the window'''
  111. self.initial_focus = None
  112. Toplevel.destroy(self)
  113. _destroy_temp_root(self.master)
  114. #
  115. # construction hooks
  116. def body(self, master):
  117. '''create dialog body.
  118. return widget that should have initial focus.
  119. This method should be overridden, and is called
  120. by the __init__ method.
  121. '''
  122. pass
  123. def buttonbox(self):
  124. '''add standard button box.
  125. override if you do not want the standard buttons
  126. '''
  127. box = Frame(self)
  128. w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
  129. w.pack(side=LEFT, padx=5, pady=5)
  130. w = Button(box, text="Cancel", width=10, command=self.cancel)
  131. w.pack(side=LEFT, padx=5, pady=5)
  132. self.bind("<Return>", self.ok)
  133. self.bind("<Escape>", self.cancel)
  134. box.pack()
  135. #
  136. # standard button semantics
  137. def ok(self, event=None):
  138. if not self.validate():
  139. self.initial_focus.focus_set() # put focus back
  140. return
  141. self.withdraw()
  142. self.update_idletasks()
  143. try:
  144. self.apply()
  145. finally:
  146. self.cancel()
  147. def cancel(self, event=None):
  148. # put focus back to the parent window
  149. if self.parent is not None:
  150. self.parent.focus_set()
  151. self.destroy()
  152. #
  153. # command hooks
  154. def validate(self):
  155. '''validate the data
  156. This method is called automatically to validate the data before the
  157. dialog is destroyed. By default, it always validates OK.
  158. '''
  159. return 1 # override
  160. def apply(self):
  161. '''process the data
  162. This method is called automatically to process the data, *after*
  163. the dialog is destroyed. By default, it does nothing.
  164. '''
  165. pass # override
  166. # Place a toplevel window at the center of parent or screen
  167. # It is a Python implementation of ::tk::PlaceWindow.
  168. def _place_window(w, parent=None):
  169. w.wm_withdraw() # Remain invisible while we figure out the geometry
  170. w.update_idletasks() # Actualize geometry information
  171. minwidth = w.winfo_reqwidth()
  172. minheight = w.winfo_reqheight()
  173. maxwidth = w.winfo_vrootwidth()
  174. maxheight = w.winfo_vrootheight()
  175. if parent is not None and parent.winfo_ismapped():
  176. x = parent.winfo_rootx() + (parent.winfo_width() - minwidth) // 2
  177. y = parent.winfo_rooty() + (parent.winfo_height() - minheight) // 2
  178. vrootx = w.winfo_vrootx()
  179. vrooty = w.winfo_vrooty()
  180. x = min(x, vrootx + maxwidth - minwidth)
  181. x = max(x, vrootx)
  182. y = min(y, vrooty + maxheight - minheight)
  183. y = max(y, vrooty)
  184. if w._windowingsystem == 'aqua':
  185. # Avoid the native menu bar which sits on top of everything.
  186. y = max(y, 22)
  187. else:
  188. x = (w.winfo_screenwidth() - minwidth) // 2
  189. y = (w.winfo_screenheight() - minheight) // 2
  190. w.wm_maxsize(maxwidth, maxheight)
  191. w.wm_geometry('+%d+%d' % (x, y))
  192. w.wm_deiconify() # Become visible at the desired location
  193. def _setup_dialog(w):
  194. if w._windowingsystem == "aqua":
  195. w.tk.call("::tk::unsupported::MacWindowStyle", "style",
  196. w, "moveableModal", "")
  197. elif w._windowingsystem == "x11":
  198. w.wm_attributes("-type", "dialog")
  199. # --------------------------------------------------------------------
  200. # convenience dialogues
  201. class _QueryDialog(Dialog):
  202. def __init__(self, title, prompt,
  203. initialvalue=None,
  204. minvalue = None, maxvalue = None,
  205. parent = None):
  206. self.prompt = prompt
  207. self.minvalue = minvalue
  208. self.maxvalue = maxvalue
  209. self.initialvalue = initialvalue
  210. Dialog.__init__(self, parent, title)
  211. def destroy(self):
  212. self.entry = None
  213. Dialog.destroy(self)
  214. def body(self, master):
  215. w = Label(master, text=self.prompt, justify=LEFT)
  216. w.grid(row=0, padx=5, sticky=W)
  217. self.entry = Entry(master, name="entry")
  218. self.entry.grid(row=1, padx=5, sticky=W+E)
  219. if self.initialvalue is not None:
  220. self.entry.insert(0, self.initialvalue)
  221. self.entry.select_range(0, END)
  222. return self.entry
  223. def validate(self):
  224. try:
  225. result = self.getresult()
  226. except ValueError:
  227. messagebox.showwarning(
  228. "Illegal value",
  229. self.errormessage + "\nPlease try again",
  230. parent = self
  231. )
  232. return 0
  233. if self.minvalue is not None and result < self.minvalue:
  234. messagebox.showwarning(
  235. "Too small",
  236. "The allowed minimum value is %s. "
  237. "Please try again." % self.minvalue,
  238. parent = self
  239. )
  240. return 0
  241. if self.maxvalue is not None and result > self.maxvalue:
  242. messagebox.showwarning(
  243. "Too large",
  244. "The allowed maximum value is %s. "
  245. "Please try again." % self.maxvalue,
  246. parent = self
  247. )
  248. return 0
  249. self.result = result
  250. return 1
  251. class _QueryInteger(_QueryDialog):
  252. errormessage = "Not an integer."
  253. def getresult(self):
  254. return self.getint(self.entry.get())
  255. def askinteger(title, prompt, **kw):
  256. '''get an integer from the user
  257. Arguments:
  258. title -- the dialog title
  259. prompt -- the label text
  260. **kw -- see SimpleDialog class
  261. Return value is an integer
  262. '''
  263. d = _QueryInteger(title, prompt, **kw)
  264. return d.result
  265. class _QueryFloat(_QueryDialog):
  266. errormessage = "Not a floating point value."
  267. def getresult(self):
  268. return self.getdouble(self.entry.get())
  269. def askfloat(title, prompt, **kw):
  270. '''get a float from the user
  271. Arguments:
  272. title -- the dialog title
  273. prompt -- the label text
  274. **kw -- see SimpleDialog class
  275. Return value is a float
  276. '''
  277. d = _QueryFloat(title, prompt, **kw)
  278. return d.result
  279. class _QueryString(_QueryDialog):
  280. def __init__(self, *args, **kw):
  281. if "show" in kw:
  282. self.__show = kw["show"]
  283. del kw["show"]
  284. else:
  285. self.__show = None
  286. _QueryDialog.__init__(self, *args, **kw)
  287. def body(self, master):
  288. entry = _QueryDialog.body(self, master)
  289. if self.__show is not None:
  290. entry.configure(show=self.__show)
  291. return entry
  292. def getresult(self):
  293. return self.entry.get()
  294. def askstring(title, prompt, **kw):
  295. '''get a string from the user
  296. Arguments:
  297. title -- the dialog title
  298. prompt -- the label text
  299. **kw -- see SimpleDialog class
  300. Return value is a string
  301. '''
  302. d = _QueryString(title, prompt, **kw)
  303. return d.result
  304. if __name__ == '__main__':
  305. def test():
  306. root = Tk()
  307. def doit(root=root):
  308. d = SimpleDialog(root,
  309. text="This is a test dialog. "
  310. "Would this have been an actual dialog, "
  311. "the buttons below would have been glowing "
  312. "in soft pink light.\n"
  313. "Do you believe this?",
  314. buttons=["Yes", "No", "Cancel"],
  315. default=0,
  316. cancel=2,
  317. title="Test Dialog")
  318. print(d.go())
  319. print(askinteger("Spam", "Egg count", initialvalue=12*12))
  320. print(askfloat("Spam", "Egg weight\n(in tons)", minvalue=1,
  321. maxvalue=100))
  322. print(askstring("Spam", "Egg label"))
  323. t = Button(root, text='Test', command=doit)
  324. t.pack()
  325. q = Button(root, text='Quit', command=t.quit)
  326. q.pack()
  327. t.mainloop()
  328. test()