return _default_root
+def _get_temp_root():
+ global _support_default_root
+ if not _support_default_root:
+ raise RuntimeError("No master specified and tkinter is "
+ "configured to not support default root")
+ root = _default_root
+ if root is None:
+ assert _support_default_root
+ _support_default_root = False
+ root = Tk()
+ _support_default_root = True
+ assert _default_root is None
+ root.withdraw()
+ root._temporary = True
+ return root
+
+
+def _destroy_temp_root(master):
+ if getattr(master, '_temporary', False):
+ try:
+ master.destroy()
+ except TclError:
+ pass
+
+
def _tkerror(err):
"""Internal function."""
pass
__all__ = ["Dialog"]
-from tkinter import Frame
+from tkinter import Frame, _get_temp_root, _destroy_temp_root
class Dialog:
self._fixoptions()
- # we need a dummy widget to properly process the options
- # (at least as long as we use Tkinter 1.63)
- w = Frame(self.master)
-
+ master = self.master
+ if master is None:
+ master = _get_temp_root()
try:
-
- s = w.tk.call(self.command, *w._options(self.options))
-
- s = self._fixresult(w, s)
-
+ self._test_callback(master) # The function below is replaced for some tests.
+ s = master.tk.call(self.command, *master._options(self.options))
+ s = self._fixresult(master, s)
finally:
-
- try:
- # get rid of the widget
- w.destroy()
- except:
- pass
+ _destroy_temp_root(master)
return s
+
+ def _test_callback(self, master):
+ pass
"""
from tkinter import *
-from tkinter import messagebox, _get_default_root
+from tkinter import _get_temp_root, _destroy_temp_root
+from tkinter import messagebox
class SimpleDialog:
'''
master = parent
if master is None:
- master = _get_default_root('create dialog window')
+ master = _get_temp_root()
Toplevel.__init__(self, master)
'''Destroy the window'''
self.initial_focus = None
Toplevel.destroy(self)
+ _destroy_temp_root(self.master)
#
# construction hooks
--- /dev/null
+import unittest
+import tkinter
+from test.support import requires, run_unittest, swap_attr
+from tkinter.test.support import AbstractDefaultRootTest
+from tkinter.commondialog import Dialog
+from tkinter.colorchooser import askcolor
+
+requires('gui')
+
+
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+ def test_askcolor(self):
+ def test_callback(dialog, master):
+ nonlocal ismapped
+ master.update()
+ ismapped = master.winfo_ismapped()
+ raise ZeroDivisionError
+
+ with swap_attr(Dialog, '_test_callback', test_callback):
+ ismapped = None
+ self.assertRaises(ZeroDivisionError, askcolor)
+ #askcolor()
+ self.assertEqual(ismapped, False)
+
+ root = tkinter.Tk()
+ ismapped = None
+ self.assertRaises(ZeroDivisionError, askcolor)
+ self.assertEqual(ismapped, True)
+ root.destroy()
+
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, askcolor)
+
+
+tests_gui = (DefaultRootTest,)
+
+if __name__ == "__main__":
+ run_unittest(*tests_gui)
--- /dev/null
+import unittest
+import tkinter
+from test.support import requires, run_unittest, swap_attr
+from tkinter.test.support import AbstractDefaultRootTest
+from tkinter.commondialog import Dialog
+from tkinter.messagebox import showinfo
+
+requires('gui')
+
+
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+ def test_showinfo(self):
+ def test_callback(dialog, master):
+ nonlocal ismapped
+ master.update()
+ ismapped = master.winfo_ismapped()
+ raise ZeroDivisionError
+
+ with swap_attr(Dialog, '_test_callback', test_callback):
+ ismapped = None
+ self.assertRaises(ZeroDivisionError, showinfo, "Spam", "Egg Information")
+ self.assertEqual(ismapped, False)
+
+ root = tkinter.Tk()
+ ismapped = None
+ self.assertRaises(ZeroDivisionError, showinfo, "Spam", "Egg Information")
+ self.assertEqual(ismapped, True)
+ root.destroy()
+
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, showinfo, "Spam", "Egg Information")
+
+
+tests_gui = (DefaultRootTest,)
+
+if __name__ == "__main__":
+ run_unittest(*tests_gui)
class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
def test_askinteger(self):
- self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
- root = tkinter.Tk()
- with swap_attr(Dialog, 'wait_window', lambda self, w: w.destroy()):
+ @staticmethod
+ def mock_wait_window(w):
+ nonlocal ismapped
+ ismapped = w.master.winfo_ismapped()
+ w.destroy()
+
+ with swap_attr(Dialog, 'wait_window', mock_wait_window):
+ ismapped = None
+ askinteger("Go To Line", "Line number")
+ self.assertEqual(ismapped, False)
+
+ root = tkinter.Tk()
+ ismapped = None
askinteger("Go To Line", "Line number")
- root.destroy()
- tkinter.NoDefaultRoot()
- self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
+ self.assertEqual(ismapped, True)
+ root.destroy()
+
+ tkinter.NoDefaultRoot()
+ self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
tests_gui = (DefaultRootTest,)
--- /dev/null
+When simple query dialogs (:mod:`tkinter.simpledialog`), message boxes
+(:mod:`tkinter.messagebox`) or color choose dialog
+(:mod:`tkinter.colorchooser`) are created without arguments *master* and
+*parent*, and the default root window is not yet created, and
+:func:`~tkinter.NoDefaultRoot` was not called, a new temporal
+hidden root window will be created automatically. It will not be set as the
+default root window and will be destroyed right after closing the dialog
+window. It will help to use these simple dialog windows in programs which
+do not need other GUI.