Skip to content

Commit 41fba5b

Browse files
gh-151876: Add tkinter Canvas methods rotate and rchars
Wrap the Tk canvas commands "rchars" (replace the text or coordinates of items, since Tk 8.6) and "rotate" (rotate the coordinates of items about an origin, new in Tk 9.0) as the methods Canvas.rchars() and Canvas.rotate(), complementing the existing dchars/insert and move/scale methods. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWevzas4XVpjzedzR9gKVo
1 parent f28ef85 commit 41fba5b

5 files changed

Lines changed: 71 additions & 0 deletions

File tree

Doc/library/tkinter.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3648,6 +3648,15 @@ Widget classes
36483648
*yOrigin* changes by a factor of *yScale* (a factor of ``1.0`` leaves the
36493649
coordinate unchanged).
36503650

3651+
.. method:: rotate(tagOrId, xOrigin, yOrigin, angle, /)
3652+
3653+
Rotate the coordinates of all items given by *tagOrId* in canvas
3654+
coordinate space about the origin (*xOrigin*, *yOrigin*) by *angle*
3655+
degrees anticlockwise.
3656+
Negative values of *angle* rotate clockwise.
3657+
3658+
.. versionadded:: next
3659+
36513660
.. method:: delete(*tagOrIds)
36523661

36533662
Delete each of the items given by the *tagOrIds* arguments.
@@ -3667,6 +3676,17 @@ Widget classes
36673676
For line and polygon items *string* must be a valid sequence of
36683677
coordinates.
36693678

3679+
.. method:: rchars(tagOrId, first, last, string, /)
3680+
3681+
Replace the characters (for text items) or coordinates (for line and
3682+
polygon items) in the range from *first* to *last* inclusive of each of
3683+
the items given by *tagOrId* with *string*.
3684+
For line and polygon items *string* must be a valid sequence of
3685+
coordinates.
3686+
Items that do not support indexing ignore this operation.
3687+
3688+
.. versionadded:: next
3689+
36703690
.. method:: itemcget(tagOrId, option)
36713691

36723692
Return the current value of the configuration option *option* for the

Doc/whatsnew/3.16.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ tkinter
157157
synchronization of the displayed view with the underlying text.
158158
(Contributed by Serhiy Storchaka in :gh:`151675`.)
159159

160+
* Added new :class:`!tkinter.Canvas` methods :meth:`~tkinter.Canvas.rchars`
161+
which replaces the text or coordinates of canvas items, and
162+
:meth:`~tkinter.Canvas.rotate` which rotates the coordinates of canvas items.
163+
(Contributed by Serhiy Storchaka in :gh:`151876`.)
164+
160165
xml
161166
---
162167

Lib/test/test_tkinter/test_widgets.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,34 @@ def test_scale(self):
13901390
self.assertRaises(TclError, c.scale, rect, 0, 0, 'spam', 2)
13911391
self.assertRaises(TclError, c.scale, rect, 0, 0) # missing factors
13921392

1393+
@requires_tk(8, 6)
1394+
def test_rchars(self):
1395+
c = self.create()
1396+
# On a line item, rchars replaces a range of the coordinate list.
1397+
line = c.create_line(0, 0, 10, 10, 20, 0)
1398+
c.rchars(line, 2, 5, (30, 30, 40, 40))
1399+
self.assertEqual(c.coords(line), [0.0, 0.0, 30.0, 30.0, 40.0, 40.0])
1400+
# On a text item, rchars replaces a range of characters.
1401+
text = c.create_text(10, 10, text='hello')
1402+
c.rchars(text, 0, 2, 'HE')
1403+
self.assertEqual(c.itemcget(text, 'text'), 'HElo')
1404+
self.assertRaises(TclError, c.rchars)
1405+
1406+
@requires_tk(9, 0)
1407+
def test_rotate(self):
1408+
c = self.create()
1409+
line = c.create_line(10, 0, 20, 0)
1410+
# The canvas y-axis points down, so an anticlockwise rotation about
1411+
# the origin maps (x, y) to (y, -x).
1412+
c.rotate(line, 0, 0, 90)
1413+
for got, expected in zip(c.coords(line), [0, -10, 0, -20]):
1414+
self.assertAlmostEqual(got, expected, places=3)
1415+
# A negative angle rotates clockwise, restoring the original position.
1416+
c.rotate(line, 0, 0, -90)
1417+
for got, expected in zip(c.coords(line), [10, 0, 20, 0]):
1418+
self.assertAlmostEqual(got, expected, places=3)
1419+
self.assertRaises(TclError, c.rotate, line, 0, 0, 'spam')
1420+
13931421
def test_delete(self):
13941422
c = self.create()
13951423
r1 = c.create_rectangle(10, 10, 30, 30)

Lib/tkinter/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3226,6 +3226,22 @@ def tag_raise(self, *args):
32263226

32273227
lift = tkraise = tag_raise
32283228

3229+
def rchars(self, *args):
3230+
"""Replace the text or coordinates between indices FIRST and LAST of
3231+
the items identified by TAGORID with STRING.
3232+
3233+
Text items replace their text; line and polygon items replace their
3234+
coordinates, in which case STRING is a list of coordinates. Other
3235+
items ignore this operation."""
3236+
self.tk.call((self._w, 'rchars') + args)
3237+
3238+
def rotate(self, *args): # new in Tk 9.0
3239+
"""Rotate the coordinates of the items identified by TAGORID about the
3240+
origin (XORIGIN, YORIGIN) by ANGLE degrees anticlockwise.
3241+
3242+
Negative values of ANGLE rotate clockwise."""
3243+
self.tk.call((self._w, 'rotate') + args)
3244+
32293245
def scale(self, *args):
32303246
"""Scale item TAGORID with XORIGIN, YORIGIN, XSCALE, YSCALE."""
32313247
self.tk.call((self._w, 'scale') + args)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add the :class:`tkinter.Canvas` methods :meth:`!rchars` and :meth:`!rotate`,
2+
wrapping the ``rchars`` and ``rotate`` Tk canvas commands.

0 commit comments

Comments
 (0)