Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 79db9d9

Browse files
gh-72684: Tkinter: provide interface for "tk busy" subcommands (GH-107684)
Add tkinter.Misc methods: tk_busy_hold(), tk_busy_configure(), tk_busy_cget(), tk_busy_forget(), tk_busy_current(), and tk_busy_status().
1 parent ca0c6c1 commit 79db9d9

File tree

4 files changed

+146
-1
lines changed

4 files changed

+146
-1
lines changed

Doc/whatsnew/3.13.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,15 @@ pathlib
144144
:meth:`~pathlib.Path.is_dir`.
145145
(Contributed by Barney Gale in :gh:`77609` and :gh:`105793`.)
146146

147+
tkinter
148+
-------
149+
150+
* Add :mod:`tkinter` widget methods:
151+
:meth:`!tk_busy_hold`, :meth:`!tk_busy_configure`,
152+
:meth:`!tk_busy_cget`, :meth:`!tk_busy_forget`,
153+
:meth:`!tk_busy_current`, and :meth:`!tk_busy_status`.
154+
(Contributed by Miguel, klappnase and Serhiy Storchaka in :gh:`72684`.)
155+
147156
traceback
148157
---------
149158

Lib/test/test_tkinter/test_misc.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import functools
22
import unittest
33
import tkinter
4+
from tkinter import TclError
45
import enum
56
from test import support
6-
from test.test_tkinter.support import AbstractTkTest, AbstractDefaultRootTest
7+
from test.test_tkinter.support import AbstractTkTest, AbstractDefaultRootTest, requires_tk
78

89
support.requires('gui')
910

@@ -36,6 +37,59 @@ def test_generated_names(self):
3637
for name in str(b).split('.'):
3738
self.assertFalse(name.isidentifier(), msg=repr(name))
3839

40+
@requires_tk(8, 6, 6)
41+
def test_tk_busy(self):
42+
root = self.root
43+
f = tkinter.Frame(root, name='myframe')
44+
f2 = tkinter.Frame(root)
45+
f.pack()
46+
f2.pack()
47+
b = tkinter.Button(f)
48+
b.pack()
49+
f.tk_busy_hold()
50+
with self.assertRaisesRegex(TclError, 'unknown option "-spam"'):
51+
f.tk_busy_configure(spam='eggs')
52+
with self.assertRaisesRegex(TclError, 'unknown option "-spam"'):
53+
f.tk_busy_cget('spam')
54+
with self.assertRaisesRegex(TclError, 'unknown option "-spam"'):
55+
f.tk_busy_configure('spam')
56+
self.assertIsInstance(f.tk_busy_configure(), dict)
57+
58+
self.assertTrue(f.tk_busy_status())
59+
self.assertFalse(root.tk_busy_status())
60+
self.assertFalse(f2.tk_busy_status())
61+
self.assertFalse(b.tk_busy_status())
62+
self.assertIn(f, f.tk_busy_current())
63+
self.assertIn(f, f.tk_busy_current('*.m?f*me'))
64+
self.assertNotIn(f, f.tk_busy_current('*spam'))
65+
66+
f.tk_busy_forget()
67+
self.assertFalse(f.tk_busy_status())
68+
self.assertFalse(f.tk_busy_current())
69+
with self.assertRaisesRegex(TclError, "can't find busy window"):
70+
f.tk_busy_configure()
71+
with self.assertRaisesRegex(TclError, "can't find busy window"):
72+
f.tk_busy_forget()
73+
74+
@requires_tk(8, 6, 6)
75+
def test_tk_busy_with_cursor(self):
76+
root = self.root
77+
if root._windowingsystem == 'aqua':
78+
self.skipTest('the cursor option is not supported on OSX/Aqua')
79+
f = tkinter.Frame(root, name='myframe')
80+
f.pack()
81+
f.tk_busy_hold(cursor='gumby')
82+
83+
self.assertEqual(f.tk_busy_cget('cursor'), 'gumby')
84+
f.tk_busy_configure(cursor='heart')
85+
self.assertEqual(f.tk_busy_cget('cursor'), 'heart')
86+
self.assertEqual(f.tk_busy_configure()['cursor'][4], 'heart')
87+
self.assertEqual(f.tk_busy_configure('cursor')[4], 'heart')
88+
89+
f.tk_busy_forget()
90+
with self.assertRaisesRegex(TclError, "can't find busy window"):
91+
f.tk_busy_cget('cursor')
92+
3993
def test_tk_setPalette(self):
4094
root = self.root
4195
root.tk_setPalette('black')

Lib/tkinter/__init__.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,85 @@ def bell(self, displayof=0):
901901
"""Ring a display's bell."""
902902
self.tk.call(('bell',) + self._displayof(displayof))
903903

904+
def tk_busy_cget(self, option):
905+
"""Return the value of busy configuration option.
906+
907+
The widget must have been previously made busy by
908+
tk_busy_hold(). Option may have any of the values accepted by
909+
tk_busy_hold().
910+
"""
911+
return self.tk.call('tk', 'busy', 'cget', self._w, '-'+option)
912+
busy_cget = tk_busy_cget
913+
914+
def tk_busy_configure(self, cnf=None, **kw):
915+
"""Query or modify the busy configuration options.
916+
917+
The widget must have been previously made busy by
918+
tk_busy_hold(). Options may have any of the values accepted by
919+
tk_busy_hold().
920+
921+
Please note that the option database is referenced by the widget
922+
name or class. For example, if a Frame widget with name "frame"
923+
is to be made busy, the busy cursor can be specified for it by
924+
either call:
925+
926+
w.option_add('*frame.busyCursor', 'gumby')
927+
w.option_add('*Frame.BusyCursor', 'gumby')
928+
"""
929+
if kw:
930+
cnf = _cnfmerge((cnf, kw))
931+
elif cnf:
932+
cnf = _cnfmerge(cnf)
933+
if cnf is None:
934+
return self._getconfigure(
935+
'tk', 'busy', 'configure', self._w)
936+
if isinstance(cnf, str):
937+
return self._getconfigure1(
938+
'tk', 'busy', 'configure', self._w, '-'+cnf)
939+
self.tk.call('tk', 'busy', 'configure', self._w, *self._options(cnf))
940+
busy_config = busy_configure = tk_busy_config = tk_busy_configure
941+
942+
def tk_busy_current(self, pattern=None):
943+
"""Return a list of widgets that are currently busy.
944+
945+
If a pattern is given, only busy widgets whose path names match
946+
a pattern are returned.
947+
"""
948+
return [self._nametowidget(x) for x in
949+
self.tk.splitlist(self.tk.call(
950+
'tk', 'busy', 'current', pattern))]
951+
busy_current = tk_busy_current
952+
953+
def tk_busy_forget(self):
954+
"""Make this widget no longer busy.
955+
956+
User events will again be received by the widget.
957+
"""
958+
self.tk.call('tk', 'busy', 'forget', self._w)
959+
busy_forget = tk_busy_forget
960+
961+
def tk_busy_hold(self, **kw):
962+
"""Make this widget appear busy.
963+
964+
The specified widget and its descendants will be blocked from
965+
user interactions. Normally update() should be called
966+
immediately afterward to insure that the hold operation is in
967+
effect before the application starts its processing.
968+
969+
The only supported configuration option is:
970+
971+
cursor: the cursor to be displayed when the widget is made
972+
busy.
973+
"""
974+
self.tk.call('tk', 'busy', 'hold', self._w, *self._options(kw))
975+
busy = busy_hold = tk_busy = tk_busy_hold
976+
977+
def tk_busy_status(self):
978+
"""Return True if the widget is busy, False otherwise."""
979+
return self.tk.getboolean(self.tk.call(
980+
'tk', 'busy', 'status', self._w))
981+
busy_status = tk_busy_status
982+
904983
# Clipboard handling:
905984
def clipboard_get(self, **kw):
906985
"""Retrieve data from the clipboard on window's display.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add :mod:`tkinter` widget methods: :meth:`!tk_busy_hold`,
2+
:meth:`!tk_busy_configure`, :meth:`!tk_busy_cget`, :meth:`!tk_busy_forget`,
3+
:meth:`!tk_busy_current`, and :meth:`!tk_busy_status`.

0 commit comments

Comments
 (0)