Skip to content

Commit b9bceb1

Browse files
gh-151876: Add tkinter Canvas methods rotate and rchars (GH-151877)
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>
1 parent 13c1225 commit b9bceb1

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
@@ -3743,6 +3743,15 @@ Widget classes
37433743
*yOrigin* changes by a factor of *yScale* (a factor of ``1.0`` leaves the
37443744
coordinate unchanged).
37453745

3746+
.. method:: rotate(tagOrId, xOrigin, yOrigin, angle, /)
3747+
3748+
Rotate the coordinates of all items given by *tagOrId* in canvas
3749+
coordinate space about the origin (*xOrigin*, *yOrigin*) by *angle*
3750+
degrees anticlockwise.
3751+
Negative values of *angle* rotate clockwise.
3752+
3753+
.. versionadded:: next
3754+
37463755
.. method:: delete(*tagOrIds)
37473756

37483757
Delete each of the items given by the *tagOrIds* arguments.
@@ -3762,6 +3771,17 @@ Widget classes
37623771
For line and polygon items *string* must be a valid sequence of
37633772
coordinates.
37643773

3774+
.. method:: rchars(tagOrId, first, last, string, /)
3775+
3776+
Replace the characters (for text items) or coordinates (for line and
3777+
polygon items) in the range from *first* to *last* inclusive of each of
3778+
the items given by *tagOrId* with *string*.
3779+
For line and polygon items *string* must be a valid sequence of
3780+
coordinates.
3781+
Items that do not support indexing ignore this operation.
3782+
3783+
.. versionadded:: next
3784+
37653785
.. method:: itemcget(tagOrId, option)
37663786

37673787
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
@@ -173,6 +173,11 @@ tkinter
173173
synchronization of the displayed view with the underlying text.
174174
(Contributed by Serhiy Storchaka in :gh:`151675`.)
175175

176+
* Added new :class:`!tkinter.Canvas` methods :meth:`~tkinter.Canvas.rchars`
177+
which replaces the text or coordinates of canvas items, and
178+
:meth:`~tkinter.Canvas.rotate` which rotates the coordinates of canvas items.
179+
(Contributed by Serhiy Storchaka in :gh:`151876`.)
180+
176181
* Added a :meth:`!validate` method to the :class:`!tkinter.Entry` and
177182
:class:`!tkinter.Spinbox` widgets, which forces an evaluation of the
178183
validation command.

Lib/test/test_tkinter/test_widgets.py

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

1412+
@requires_tk(8, 6)
1413+
def test_rchars(self):
1414+
c = self.create()
1415+
# On a line item, rchars replaces a range of the coordinate list.
1416+
line = c.create_line(0, 0, 10, 10, 20, 0)
1417+
c.rchars(line, 2, 5, (30, 30, 40, 40))
1418+
self.assertEqual(c.coords(line), [0.0, 0.0, 30.0, 30.0, 40.0, 40.0])
1419+
# On a text item, rchars replaces a range of characters.
1420+
text = c.create_text(10, 10, text='hello')
1421+
c.rchars(text, 0, 2, 'HE')
1422+
self.assertEqual(c.itemcget(text, 'text'), 'HElo')
1423+
self.assertRaises(TclError, c.rchars)
1424+
1425+
@requires_tk(9, 0)
1426+
def test_rotate(self):
1427+
c = self.create()
1428+
line = c.create_line(10, 0, 20, 0)
1429+
# The canvas y-axis points down, so an anticlockwise rotation about
1430+
# the origin maps (x, y) to (y, -x).
1431+
c.rotate(line, 0, 0, 90)
1432+
for got, expected in zip(c.coords(line), [0, -10, 0, -20]):
1433+
self.assertAlmostEqual(got, expected, places=3)
1434+
# A negative angle rotates clockwise, restoring the original position.
1435+
c.rotate(line, 0, 0, -90)
1436+
for got, expected in zip(c.coords(line), [10, 0, 20, 0]):
1437+
self.assertAlmostEqual(got, expected, places=3)
1438+
self.assertRaises(TclError, c.rotate, line, 0, 0, 'spam')
1439+
14121440
def test_delete(self):
14131441
c = self.create()
14141442
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
@@ -3270,6 +3270,22 @@ def tag_raise(self, *args):
32703270

32713271
lift = tkraise = tag_raise # overrides Misc.tkraise
32723272

3273+
def rchars(self, *args):
3274+
"""Replace the text or coordinates between indices FIRST and LAST of
3275+
the items identified by TAGORID with STRING.
3276+
3277+
Text items replace their text; line and polygon items replace their
3278+
coordinates, in which case STRING is a list of coordinates. Other
3279+
items ignore this operation."""
3280+
self.tk.call((self._w, 'rchars') + args)
3281+
3282+
def rotate(self, *args): # new in Tk 9.0
3283+
"""Rotate the coordinates of the items identified by TAGORID about the
3284+
origin (XORIGIN, YORIGIN) by ANGLE degrees anticlockwise.
3285+
3286+
Negative values of ANGLE rotate clockwise."""
3287+
self.tk.call((self._w, 'rotate') + args)
3288+
32733289
def scale(self, *args):
32743290
"""Scale item TAGORID with XORIGIN, YORIGIN, XSCALE, YSCALE."""
32753291
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)