Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Avoid timer drift during long callbacks#29023

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
Closed
Changes from1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
NextNext commit
FIX: Avoid drift in Tk's repeating timer
The Tk timer would reset itself after the callback had processedto add a new interval. This meant that if a long callback was beingadded we would get a drift in the timer. We need to manually trackthe original firing time and intervals based on that.
  • Loading branch information
@greglucas
greglucas committedOct 30, 2024
commit9c8300d5790fd85fbff1351bd39c8712dd90e2ec
22 changes: 21 additions & 1 deletionlib/matplotlib/backends/_backend_tk.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,6 +6,7 @@
import os.path
import pathlib
import sys
import time
import tkinter as tk
import tkinter.filedialog
import tkinter.font
Expand DownExpand Up@@ -132,21 +133,40 @@ def __init__(self, parent, *args, **kwargs):
def _timer_start(self):
self._timer_stop()
self._timer = self.parent.after(self._interval, self._on_timer)
# Keep track of the firing time for repeating timers since
# we have to do this manually in Tk
self._timer_start_count = time.perf_counter_ns()

def _timer_stop(self):
if self._timer is not None:
self.parent.after_cancel(self._timer)
self._timer = None

def _on_timer(self):
# We want to measure the time spent in the callback, so we need to
# record the time before calling the base class method.
timer_fire_ms = (time.perf_counter_ns() - self._timer_start_count) // 1_000_000
super()._on_timer()
# Tk after() is only a single shot, so we need to add code here to
# reset the timer if we're not operating in single shot mode. However,
# if _timer is None, this means that _timer_stop has been called; so
# don't recreate the timer in that case.
if not self._single and self._timer:
if self._interval > 0:
self._timer = self.parent.after(self._interval, self._on_timer)
# We want to adjust our fire time independent of the time
# spent in the callback and not drift over time, so reference
# to the start count.
after_callback_ms = ((time.perf_counter_ns() - self._timer_start_count)
// 1_000_000)
if after_callback_ms - timer_fire_ms < self._interval:
next_interval = self._interval - after_callback_ms % self._interval
# minimum of 1ms
next_interval = max(1, next_interval)
else:
# Account for the callback being longer than the interval, where
# we really want to fire the next timer as soon as possible.
next_interval = 1
self._timer = self.parent.after(next_interval, self._on_timer)
else:
# Edge case: Tcl after 0 *prepends* events to the queue
# so a 0 interval does not allow any other events to run.
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp