Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tkinter Canvas.coords does not flatten arguments #94473

Closed
Why-not-now opened this issue Jul 1, 2022 · 9 comments
Closed

Tkinter Canvas.coords does not flatten arguments #94473

Why-not-now opened this issue Jul 1, 2022 · 9 comments
Labels
topic-tkinter type-feature A feature request or enhancement

Comments

@Why-not-now
Copy link

Why-not-now commented Jul 1, 2022

Bug report
Double nested arrays in tk.coords will produce errors in tkinter (_tkinter.TclError: wrong # coordinates: expected at least 4, got 2 in this case)

import tkinter as tk

coords = [[100, 100], [300, 300]]


root = tk.Tk()
canvas = tk.Canvas(width=400,
                   height=400,
                   background="bisque")
canvas.pack(fill="both", expand=True)
line = canvas.create_line(coords)
coords[1] = [200, 200]
canvas.coords(line, coords)  # line with error

root.mainloop()

Your environment

  • CPython versions tested on: 3.10.4
  • Operating system: Windows 10

Linked PRs

@Why-not-now Why-not-now added the type-bug An unexpected behavior, bug, or error label Jul 1, 2022
@Why-not-now
Copy link
Author

Upon further inspection, it seems that canvas.coords do not allow doubly nested loops

@stevendaprano
Copy link
Member

Is there something that suggests to you that using a numpy array for coords ought to work?

I don't know what you mean by double nested loops. There's no loop here.

@Why-not-now
Copy link
Author

Because the numpy array is similar to a list, and lists works for canvas.create_line() etc.

Also doubly nested would be a list inside a list. So canvas.coords(line, [[100, 100], [300, 300]]) wouldn't work while canvas.create_line([[100, 100], [300, 300]]) would work

@Why-not-now
Copy link
Author

Example of this is

import numpy as np
import tkinter as tk


root = tk.Tk()
canvas = tk.Canvas(width=400,
                   height=400,
                   background="bisque")
canvas.pack(fill="both", expand=True)
line = canvas.create_line([[100, 100], [300, 300]])
canvas.coords(line, [[100, 100], [200, 200]])  # line with error

root.mainloop()```

@ronaldoussoren
Copy link
Contributor

As mentioned on discuss.python.org the coords method requires at least 4 coordinates, not 2. The error message states this:

_tkinter.TclError: wrong # coordinates: expected at least 4, got 2

Supporting numpy arrays for coordinates, or rather anything other than builtin lists and tuples, could be a feature request, but would require a clear use case that sells this change.

@Why-not-now
Copy link
Author

I see, thanks for the help. Just one more question before I close this issue, why does canvas.coords(line, [[100, 100], [200, 200]]) not represent 4 coordinates while canvas.create_line([[100, 100], [300, 300]]) does?

@ronaldoussoren
Copy link
Contributor

Good question. To be honest I'm not a Tkinter expert.

Looking at the implementation and Tk documentation:

  • The Tk implementation represents the various x, y coordinates as separate arguments (see https://www.tcl.tk/man/tcl8.0/TkCmd/canvas.html#M40)
  • The Python wrapper for the create_* methods flattens arguments, basically turning canvas.create_line((startX, startY), (stopX, stopY)) into canvas.create_line(startX, startY, stopX, stopY)
  • The Python wrapper for coord method does not flatten, which means you have to pass the various coordinates as separate arguments (canvas.coords(line, startX, startY, stopX, stopY))

I don't know if that's intentional, but is does feel inconsistent. That said, canvas.coords(line) will return the current coordinates of the line (or other object) as an flattened list as well. Changing that is not backward compatible and IMHO is not worth changing even if we'd add argument flattening to the coords wrapper.

If you don't mind I'll change to title of this issue to Tkinter Canvas.coords does not flatten arguments, and leave it open for someone that knows more about Tk to comment on whether or not this is intentional behaviour.

@Why-not-now Why-not-now changed the title Numpy array not compatible with tkinter Inconsistent results for canvas.coords and canvas.create_<widget> Jul 2, 2022
@Why-not-now Why-not-now changed the title Inconsistent results for canvas.coords and canvas.create_<widget> Tkinter Canvas.coords does not flatten arguments Jul 2, 2022
@Why-not-now
Copy link
Author

Why-not-now commented Jul 3, 2022

Looking through the source code, at line 2817 of tkinter/__init__.py,

    def coords(self, *args):
        """Return a list of coordinates for the item given in ARGS."""
        # XXX Should use _flatten on args
        return [self.tk.getdouble(x) for x in
                           self.tk.splitlist(
                   self.tk.call((self._w, 'coords') + args))]

there is one comment saying they should use _flatten on args.

@serhiy-storchaka serhiy-storchaka added type-feature A feature request or enhancement and removed type-bug An unexpected behavior, bug, or error labels Oct 14, 2022
@serhiy-storchaka
Copy link
Member

It would be a new feature. And I agree that it is worth to use _flatten on args. Tk canvas subcommands coord and create has the same signature for coordinates. It natively supports both canvas.coords(line, 100, 100, 200, 200) and canvas.coords(line, [100, 100, 200, 200]), but unfortunately not more natural in Python canvas.coords(line, [100, 100], [200, 200]) and canvas.coords(line, [[100, 100], [200, 200]]).

serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue Oct 20, 2022
It is a pre-requisite for python#94473. Add tests for the coords() method and
for creation of some Canvas items.
serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue Oct 20, 2022
It is a prerequisite for python#94473. Add tests for the coords() method and
for creation of some Canvas items.
serhiy-storchaka added a commit that referenced this issue Oct 20, 2022
It is a prerequisite for #94473. Add tests for the coords() method and
for creation of some Canvas items.
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Oct 20, 2022
It is a prerequisite for pythonGH-94473. Add tests for the coords() method and
for creation of some Canvas items.
(cherry picked from commit ff173ed)

Co-authored-by: Serhiy Storchaka <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Oct 20, 2022
It is a prerequisite for pythonGH-94473. Add tests for the coords() method and
for creation of some Canvas items.
(cherry picked from commit ff173ed)

Co-authored-by: Serhiy Storchaka <[email protected]>
miss-islington added a commit that referenced this issue Oct 20, 2022
It is a prerequisite for GH-94473. Add tests for the coords() method and
for creation of some Canvas items.
(cherry picked from commit ff173ed)

Co-authored-by: Serhiy Storchaka <[email protected]>
serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue Oct 20, 2022
It now accepts not only "x1, y1, x2, y2, ..." and "[x1, y1, x2, y2, ...]",
but also "(x1, y1), (x2, y2), ..." and "[(x1, y1), (x2, y2), ...]".
ambv pushed a commit that referenced this issue Oct 28, 2022
Add more tkinter.Canvas tests (GH-98475)

It is a prerequisite for GH-94473. Add tests for the coords() method and
for creation of some Canvas items.
(cherry picked from commit ff173ed)

Co-authored-by: Serhiy Storchaka <[email protected]>
Co-authored-by: Alex Waygood <[email protected]>
serhiy-storchaka added a commit that referenced this issue May 22, 2023
It now accepts not only "x1, y1, x2, y2, ..." and "[x1, y1, x2, y2, ...]",
but also "(x1, y1), (x2, y2), ..." and "[(x1, y1), (x2, y2), ...]".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic-tkinter type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

5 participants