X Tutup
The Wayback Machine - https://web.archive.org/web/20230217044202/https://github.com/python/cpython/issues/93098
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

The Canvas widget of tkinter does not get redrawn/refreshed when contens change on Mac OS #93098

Closed
s-m-e opened this issue May 23, 2022 · 2 comments
Labels
expert-tkinter OS-mac type-bug An unexpected behavior, bug, or error

Comments

@s-m-e
Copy link

s-m-e commented May 23, 2022

Bug report

When geometries (e.g. an oval) on a tkinter Canvas widget are changed (e.g. moved), the Canvas is not redrawn on Mac OS. The following two code snippets reproduce the issue on Mac OS.

Expected behavior: One should see a circle moving from the top-left of the window/canvas to the right.

Actual behavior: In some cases, the circle is not even drawn in its initial position. In most cases, however, the circle is drawn in its initial position but does not "move" anywhere. While the Canvas does not change visually, the update function / _update method in both examples does in fact get called repeatedly as one would expect.

Variations: A call to the Canvas's update_idletasks method (as commented out in my examples) may cause (or actually prohibit) the circle being drawn in its initial position. In theory (and on other operating systems), this call should not be necessary.

"Workaround": The exact same code works on various flavors of Linux and Windows and apparently on "older" versions of Mac OS (see below).

Example 1:

from tkinter import Tk, Canvas

def update():
    "Update canvas (animation)"
    canvas.move(circle, 0.001, 0.0)
    # canvas.update_idletasks()
    window.after_idle(update)

if __name__ == '__main__':

    window = Tk()
    canvas = Canvas(window, width = 600, height = 400)
    canvas.pack()
    circle = canvas.create_oval(
        10, 10,
        60, 60,
    )

    window.after(20, update)
    window.mainloop()

Example 2:

from tkinter import Tk, Canvas

class App:
    "Minimal test application"
    def __init__(self):
        self._window = Tk()
        self._canvas = Canvas(self._window, width = 600, height = 400)
        self._canvas.pack()
        self._circle = self._canvas.create_oval(
            10, 10,
            60, 60,
        )
    def _update(self):
        "Update canvas (animation)"
        self._canvas.move(self._circle, 0.001, 0.0)
        # self._canvas.update_idletasks()
        self._window.after_idle(self._update)
    def run(self):
        "Run application"
        self._window.after(20, self._update)
        self._window.mainloop()

def main():
    "Entry point"
    app = App()
    app.run()

if __name__ == '__main__':
    main()

Your environment

Context: I first saw this issue with a bunch of university students and their Mac Books. I do not own a Mac Book so I had to gather this info (and confirmation of the above mentioned behavior) from various Mac Book owners.

  • Hardware: Mac Books, both M1-based and x86-based (dating as far back as 2017)
  • Operating System: Mac OS 12.3 definitely. It appears that Mac OS 11.x is not affected - still seeking confirmation on this one.
  • CPython versions: 3.8, 3.9, 3.10 (various micro-versions of each of them)
  • CPython distribution: conda-forge
  • CPython architectures: Recent (at least past ~2 months) x86-builds, both on x86 CPUs and on Rosetta on M1, plus recent ARM-builds on M1 definitely. It appears that x86 builds older than one year yield better (yet not completely deterministic) results - still seeking confirmation on this one, too.
  • tkinter version: 8.6.12 (also via conda-forge) definitely. Older 8.6.x releases appear to yield better (yet not completely deterministic) results - also still seeking confirmation on this one.

There might be a chance that this happens exclusively to conda-forge builds but I have not had the chance to test this hypothesis yet.

Additional context: On some affected systems (not narrowed down enough yet), even simple tkinter text inputs and buttons are not being refreshed / redrawn at all - so it is not the only the Canvas that might be affected. I do not see a pattern there yet, so once I see, I will probably file another issue and reference it here.

@s-m-e s-m-e added the type-bug An unexpected behavior, bug, or error label May 23, 2022
@Akuli
Copy link
Contributor

Akuli commented May 23, 2022

The problem occurs when a callback schedules itself to run again with after_idle(), presumably because it gets higher priority than updating the GUI. So every time the GUI is about to get updated, your callback function will run instead. I would recommend using something like .after(50, callback) instead of .after_idle(callback), because even if .after_idle() works, you will get 100% cpu usage as the event loop is never idle.

If you still believe this is a bug, we should report it to Tcl/Tk's bug tracker. That's what tkinter uses internally. You probably don't have experience with Tcl code, and I don't have a mac to reproduce the problem with, so we'd have to write the bug report together or let someone else do it.

@ronaldoussoren ronaldoussoren added invalid pending The issue will be closed if no feedback is provided labels May 26, 2022
@ronaldoussoren
Copy link
Contributor

ronaldoussoren commented May 26, 2022

From my, very, limited understanding of Tcl/Tk this is not a bug in Python or Tkinter, as @Akuli noted the code basically starves the Tcl/Tk event loop by making sure there's always work to do before updating the GUI.

.after_idle() is a binding for Tcl's "after idle ..." command as documented here: https://www.tcl.tk/man/tcl8.4/TclCmd/after.html#M9.

@ronaldoussoren ronaldoussoren closed this as not planned Won't fix, can't repro, duplicate, stale Jul 5, 2022
@erlend-aasland erlend-aasland removed the pending The issue will be closed if no feedback is provided label Jul 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
expert-tkinter OS-mac type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

4 participants
X Tutup