Часы Tkinter не синхронизированы с часами Windows

#python #tkinter

#python #tkinter

Вопрос:

Я следил за этим руководством по созданию часов с помощью tkinter, и проблема, с которой я столкнулся, связана со строкой lbl.after(1000, time) , которая заставляет функцию ждать одну секунду, а затем повторно запускать функцию времени.

Если вы запустите свою программу в 12:00:00.600, программа подождет одну секунду, а затем отобразит новое время через 600 микросекунд после 12:00: 01, а не ровно в 12:00: 01. Если у вас есть часы Windows и программа, работающие параллельно, часы Windows всегда будут немного быстрее. Я не уверен, как они заставили это работать в своем видео, я скопировал и вставил их код, и у меня все еще была та же проблема.

Я также видел чужой код, с помощью lbl.after(100, time) которого функция перезапускается каждые .100 микросекунд, а не каждую секунду, и это вроде как работает, но время от времени все еще немного отключается.

В моей оригинальной программе, к которой я добавляю графический интерфейс с помощью tkinter, я использовал следующую функцию для отображения своего времени, и она была бы почти идеально синхронизирована с часами Windows.

 import datetime as dt


def wait_until_new_second():
    current_time = dt.datetime.now().time()
    previous_time = current_time

    while previous_time.second == current_time.second:
        current_time = dt.datetime.now().time()


def display_clock():
    while True:
        wait_until_new_second()
        print(dt.datetime.now().strftime('%H:%M:%S'))


display_clock()
 

Возможно ли, чтобы часы на tkinter были синхронизированы с часами Windows?

и / или

Есть ли способ сообщить tkinter подождать, используя мою wait_until_new_second() функцию, вместо ожидания 1 секунды, что-то вроде lbl.after(wait_until_new_second, time) ?

Ответ №1:

Использование потока может быть почти (не полностью) синхронизировано с системными часами:

 from datetime import datetime
import threading
import time
import tkinter as tk

root = tk.Tk()

clock = tk.StringVar()
tk.Label(root, textvariable=clock, font="Times 20 bold", fg='light green', bg="dark green").pack()

def tick():
    while True:
        now = datetime.now()
        clock.set(now.strftime("%T"))
        time.sleep(1-now.microsecond/1000000)

threading.Thread(target=tick, daemon=True).start()
root.mainloop()
 

Комментарии:

1. Спасибо! Это, вероятно, настолько близко, насколько я могу синхронизировать.

Ответ №2:

У меня была именно эта проблема: вот мое решение

 import time
import tkinter as tk
trys = 0


def clicker():
    global trys
    timenow = time.time()
    fraction = timenow % 1.0
    if fraction < 0.025 :
        root.after(950,clicker) #Tune here
        ts = time.localtime()
        milli = time.time() % 1.0
        string = f'{ts.tm_year}_{ts.tm_mon:02d}_{ts.tm_mday:02d} {ts.tm_hour:02d}:{ts.tm_min:02d}:{(ts.tm_sec milli):06.3f}'    
        TimeLabel.config(text = string)
        TrysLabel.config(text = f'{trys}')
        trys = 0
        ############
        ############
        ## Do your on the second stuff here
        ############
        ############
    else:
        root.after(10,clicker) #Tune here
        trys  = 1

root = tk.Tk()
TimeLabel = tk.Label(root,text = '*********')
TimeLabel.pack()
TrysLabel = tk.Label(root,text = '****')
TrysLabel.pack()
clicker()
root.mainloop()
 

Это позволит сохранить функцию clicker в пределах 25 миллисекунд от настенных часов.

Вы можете настроить вызовы .after, чтобы сделать его немного ближе.

На моей машине это удерживало все в пределах примерно 12 миллисекунд. Самое главное (для моего приложения), что он делал то, что ему нужно было делать ровно один раз в секунду, как можно ближе ко второму.

В моем приложении я изменил время .after так, чтобы обычно было только 1 промах, а затем ударил по времени 10 миллисекунд спустя.

Весь смысл здесь заключался в том, чтобы свести к минимуму количество обратных вызовов, которые не представляли интереса.

Ответ №3:

Используйте этот код :

 import sys
from tkinter import *
import time

def tick():
    global time1
    # get the current local time from the PC
    time2 = time.strftime('%H:%M:%S')
    # if time string has changed, update it
    if time2 != time1:
        time1 = time2
        clock.config(text=time2)
        # calls itself every 200 milliseconds
        # to update the time display as needed
        # could use >200 ms, but display gets jerky
    clock.after(200, tick)

root = Tk()
time1 = ''

clock = Label(root, font=('times', 20, 'bold'), bg='red') clock.grid(row=0, column=0)

tick()
root.mainloop()
 

Это обновляется каждые 200 мс

Комментарии:

1. Почему вы импортируете sys , но нигде не используете?