A true *boolean* value enables strict Motif compliance (for example, no
color change when the mouse passes over a slider).
Return the resulting setting.
+
+ .. method:: tk_scaling(number=None, *, displayof=0)
+
+ Query or set the scaling factor used by Tk to convert between physical
+ units (such as points, inches or millimeters) and pixels, expressed as
+ the number of pixels per point (where a point is 1/72 inch).
+ With no argument, return the current factor; otherwise set it to the
+ floating-point *number*.
+
+ .. versionadded:: next
+
+ .. method:: tk_inactive(reset=False, *, displayof=0)
+
+ Return the number of milliseconds since the last time the user interacted
+ with the system, or ``-1`` if the windowing system does not support this.
+ If *reset* is true, reset the inactivity timer to zero instead and return
+ ``None``.
+
+ .. versionadded:: next
+
.. method:: busy(**kw)
:no-typesetting:
If the *postcommand* option has been specified, it is evaluated before
the menu is posted.
+ .. method:: postcascade(index)
+
+ Post the submenu associated with the cascade entry given by *index*,
+ unposting any previously posted submenu.
+ This has no effect if *index* does not name a cascade entry or if the
+ menu itself is not posted.
+
+ .. versionadded:: next
+
.. method:: tk_popup(x, y, entry='')
Post the menu as a popup at the root-window coordinates *x* and *y*.
validation command.
(Contributed by Serhiy Storchaka in :gh:`151878`.)
+* Added the :meth:`tkinter.Menu.postcascade` method, and the
+ :meth:`~tkinter.Misc.tk_scaling` and :meth:`~tkinter.Misc.tk_inactive`
+ methods which respectively query or set the display scaling factor and
+ report the user idle time.
+ (Contributed by Serhiy Storchaka in :gh:`151881`.)
+
* Added new window-management methods :meth:`~tkinter.Misc.winfo_isdark`
(dark mode detection), :meth:`~tkinter.Wm.wm_iconbadge` (application icon
badge) and :meth:`~tkinter.Wm.wm_stackorder` (toplevel stacking order).
self.assertEqual(root['background'], '#ffe4c4')
self.assertRaises(TypeError, root.tk_bisque, 'x')
+ def test_tk_scaling(self):
+ old = self.root.tk_scaling()
+ self.assertIsInstance(old, float)
+ self.assertGreater(old, 0)
+ self.addCleanup(self.root.tk_scaling, old)
+ # Setting the factor is reflected by a subsequent query. Tk may round
+ # it slightly when converting to and from its internal representation.
+ self.root.tk_scaling(2.0)
+ self.assertAlmostEqual(self.root.tk_scaling(), 2.0, delta=0.1)
+
+ def test_tk_inactive(self):
+ ms = self.root.tk_inactive()
+ self.assertIsInstance(ms, int)
+ # A count of milliseconds, or -1 if the windowing system lacks support.
+ self.assertGreaterEqual(ms, -1)
+ # Resetting the timer returns None and does not raise.
+ self.assertIsNone(self.root.tk_inactive(reset=True))
+
def test_wait_variable(self):
var = tkinter.StringVar(self.root)
self.assertEqual(self.root.waitvar, self.root.wait_variable)
m.update()
self.assertFalse(m.winfo_ismapped())
+ def test_postcascade(self):
+ m = self.create(tearoff=False)
+ submenu = tkinter.Menu(m, tearoff=False)
+ submenu.add_command(label='Item')
+ m.add_cascade(label='Cascade', menu=submenu)
+ m.add_command(label='Plain')
+ # No effect (but no error) when the menu is not posted, when the index
+ # is not a cascade entry, or when given a label.
+ m.postcascade(0)
+ m.postcascade(1)
+ m.postcascade('Cascade')
+
+ with self.subTest('posted menu'):
+ if m._windowingsystem != 'x11':
+ # Posting a menu is modal on Windows and uses a native,
+ # unmapped menu on Aqua, so it cannot be tested synchronously
+ # there.
+ self.skipTest('menu posting is not testable on this platform')
+ m.post(0, 0)
+ m.update()
+ m.postcascade('Cascade')
+ m.update()
+ self.assertTrue(submenu.winfo_ismapped())
+ # A non-cascade index unposts the currently posted submenu.
+ m.postcascade(1)
+ m.update()
+ self.assertFalse(submenu.winfo_ismapped())
+ m.unpost()
+
def check_entry_option(self, m, index, option, value, expected=None):
if expected is None:
expected = value
self.tk.call(('tk_setPalette',)
+ _flatten(args) + _flatten(list(kw.items())))
+ def tk_scaling(self, number=None, *, displayof=0):
+ """Query or set the scaling factor used by Tk to convert between
+ physical units and pixels.
+
+ The scaling factor is the number of pixels per point on the display,
+ where a point is 1/72 inch. With no argument, return the current
+ factor; otherwise set it to the floating-point NUMBER."""
+ args = ('tk', 'scaling') + self._displayof(displayof)
+ if number is not None:
+ self.tk.call(args + (number,))
+ else:
+ return self.tk.getdouble(self.tk.call(args))
+
+ def tk_inactive(self, reset=False, *, displayof=0):
+ """Return the number of milliseconds since the last time the user
+ interacted with the system, or -1 if the windowing system does not
+ support this.
+
+ If RESET is true, reset the inactivity timer to zero instead and
+ return None."""
+ args = ('tk', 'inactive') + self._displayof(displayof)
+ if reset:
+ self.tk.call(args + ('reset',))
+ else:
+ return self.tk.getint(self.tk.call(args))
+
def wait_variable(self, name='PY_VAR'):
"""Wait until the variable is modified.
"""Display a menu at position X,Y."""
self.tk.call(self._w, 'post', x, y)
+ def postcascade(self, index):
+ """Post the submenu of the cascade entry at INDEX, unposting any
+ previously posted submenu.
+
+ Has no effect if INDEX does not name a cascade entry or if this menu
+ is not posted."""
+ self.tk.call(self._w, 'postcascade', index)
+
def type(self, index):
"""Return the type of the menu item at INDEX."""
return self.tk.call(self._w, 'type', index)
--- /dev/null
+Add the :meth:`tkinter.Menu.postcascade` method and the
+:meth:`!tkinter.Misc.tk_scaling` and :meth:`!tkinter.Misc.tk_inactive`
+methods, wrapping the ``postcascade``, ``tk scaling`` and ``tk inactive``
+Tk commands.