SimpleDialog.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. """A simple but flexible modal dialog box."""
  2. from Tkinter import *
  3. class SimpleDialog:
  4. def __init__(self, master,
  5. text='', buttons=[], default=None, cancel=None,
  6. title=None, class_=None):
  7. if class_:
  8. self.root = Toplevel(master, class_=class_)
  9. else:
  10. self.root = Toplevel(master)
  11. if title:
  12. self.root.title(title)
  13. self.root.iconname(title)
  14. self.message = Message(self.root, text=text, aspect=400)
  15. self.message.pack(expand=1, fill=BOTH)
  16. self.frame = Frame(self.root)
  17. self.frame.pack()
  18. self.num = default
  19. self.cancel = cancel
  20. self.default = default
  21. self.root.bind('<Return>', self.return_event)
  22. for num in range(len(buttons)):
  23. s = buttons[num]
  24. b = Button(self.frame, text=s,
  25. command=(lambda self=self, num=num: self.done(num)))
  26. if num == default:
  27. b.config(relief=RIDGE, borderwidth=8)
  28. b.pack(side=LEFT, fill=BOTH, expand=1)
  29. self.root.protocol('WM_DELETE_WINDOW', self.wm_delete_window)
  30. self._set_transient(master)
  31. def _set_transient(self, master, relx=0.5, rely=0.3):
  32. widget = self.root
  33. widget.withdraw() # Remain invisible while we figure out the geometry
  34. widget.transient(master)
  35. widget.update_idletasks() # Actualize geometry information
  36. if master.winfo_ismapped():
  37. m_width = master.winfo_width()
  38. m_height = master.winfo_height()
  39. m_x = master.winfo_rootx()
  40. m_y = master.winfo_rooty()
  41. else:
  42. m_width = master.winfo_screenwidth()
  43. m_height = master.winfo_screenheight()
  44. m_x = m_y = 0
  45. w_width = widget.winfo_reqwidth()
  46. w_height = widget.winfo_reqheight()
  47. x = m_x + (m_width - w_width) * relx
  48. y = m_y + (m_height - w_height) * rely
  49. if x+w_width > master.winfo_screenwidth():
  50. x = master.winfo_screenwidth() - w_width
  51. elif x < 0:
  52. x = 0
  53. if y+w_height > master.winfo_screenheight():
  54. y = master.winfo_screenheight() - w_height
  55. elif y < 0:
  56. y = 0
  57. widget.geometry("+%d+%d" % (x, y))
  58. widget.deiconify() # Become visible at the desired location
  59. def go(self):
  60. self.root.wait_visibility()
  61. self.root.grab_set()
  62. self.root.mainloop()
  63. self.root.destroy()
  64. return self.num
  65. def return_event(self, event):
  66. if self.default is None:
  67. self.root.bell()
  68. else:
  69. self.done(self.default)
  70. def wm_delete_window(self):
  71. if self.cancel is None:
  72. self.root.bell()
  73. else:
  74. self.done(self.cancel)
  75. def done(self, num):
  76. self.num = num
  77. self.root.quit()
  78. if __name__ == '__main__':
  79. def test():
  80. root = Tk()
  81. def doit(root=root):
  82. d = SimpleDialog(root,
  83. text="This is a test dialog. "
  84. "Would this have been an actual dialog, "
  85. "the buttons below would have been glowing "
  86. "in soft pink light.\n"
  87. "Do you believe this?",
  88. buttons=["Yes", "No", "Cancel"],
  89. default=0,
  90. cancel=2,
  91. title="Test Dialog")
  92. print d.go()
  93. t = Button(root, text='Test', command=doit)
  94. t.pack()
  95. q = Button(root, text='Quit', command=t.quit)
  96. q.pack()
  97. t.mainloop()
  98. test()