Як створити таймер за допомогою tkinter?


78

Мені потрібно програмувати програму за допомогою бібліотеки tkinter Python.

Моя основна проблема полягає в тому, що я не знаю, як створити таймер або годинник, як hh:mm:ss.

Мені потрібно, щоб оновити себе (це те, що я не знаю, як робити).


Відповіді:


124

У кореневих вікнах Tkinter існує метод, afterякий може бути використаний для планування виклику функції через певний проміжок часу. Якщо ця функція сама викликає, afterви встановили автоматично повторювану подію.

Ось робочий приклад:

# for python 3.x use 'tkinter' rather than 'Tkinter'
import Tkinter as tk
import time

class App():
    def __init__(self):
        self.root = tk.Tk()
        self.label = tk.Label(text="")
        self.label.pack()
        self.update_clock()
        self.root.mainloop()

    def update_clock(self):
        now = time.strftime("%H:%M:%S")
        self.label.configure(text=now)
        self.root.after(1000, self.update_clock)

app=App()

Майте на увазі, що afterне гарантує, що функція працюватиме точно вчасно. Він планує виконувати роботу лише через певний проміжок часу. Якщо програма зайнята, перед викликом може виникнути затримка, оскільки Tkinter однопоточний. Затримка зазвичай вимірюється в мікросекундах.


1
Чи рекурсивні виклики до себе не спричинять помилку "максимальна кількість рекурсій для досягнутого об'єкта python"?
stochastic13

3
@SatwikPasani: ні, бо це не рекурсивний дзвінок. Це просто ставить роботу в чергу.
Bryan Oakley

як запустити func лише один раз із затримкою?
user924

1
@ User924: self.root.after(delay, func).
Bryan Oakley,

12

Приклад годинника Python3 з використанням frame.after (), а не програми верхнього рівня. Також відображається оновлення мітки за допомогою StringVar ()

#!/usr/bin/env python3

# Display UTC.
# started with https://docs.python.org/3.4/library/tkinter.html#module-tkinter

import tkinter as tk
import time

def current_iso8601():
    """Get current date and time in ISO8601"""
    # https://en.wikipedia.org/wiki/ISO_8601
    # https://xkcd.com/1179/
    return time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

    def createWidgets(self):
        self.now = tk.StringVar()
        self.time = tk.Label(self, font=('Helvetica', 24))
        self.time.pack(side="top")
        self.time["textvariable"] = self.now

        self.QUIT = tk.Button(self, text="QUIT", fg="red",
                                            command=root.destroy)
        self.QUIT.pack(side="bottom")

        # initial time display
        self.onUpdate()

    def onUpdate(self):
        # update displayed time
        self.now.set(current_iso8601())
        # schedule timer to call myself after 1 second
        self.after(1000, self.onUpdate)

root = tk.Tk()
app = Application(master=root)
root.mainloop()

1
Це хороша відповідь, з однією важливою річчю - відображений час - це справді системний час, а не якийсь накопичений час помилки (якщо ви зачекаєте "приблизно 1000 мс" 60 разів, ви отримаєте "близько хвилини", а не 60 секунд, і помилка зростає з часом). Однак - ваш годинник може пропускати секунди на дисплеї - ви можете накопичувати помилки в секунду, а потім, наприклад, пропускати 2 с вперед. Я хотів би запропонувати: self.after(1000 - int(1000 * (time.time() - int(time.time()))) or 1000, self.onUpdate). Можливо, краще зберегти time.time()у змінну перед цим виразом.
Томаш Гандор,

3
Я прагну бути достатньо дивовижним, щоб вбудовувати xkcd в свої коментарі :)
bitsmack

У чому перевага використання frame.after () замість root.after ()?
Kai Wang

6
from tkinter import *
import time
tk=Tk()
def clock():
    t=time.strftime('%I:%M:%S',time.localtime())
    if t!='':
        label1.config(text=t,font='times 25')
    tk.after(100,clock)
label1=Label(tk,justify='center')
label1.pack()
clock()
tk.mainloop()

4
Було б корисно, якщо б ви могли додати якийсь опис. Просто скопіювати / вставити код рідко буває корисним ;-)
Мартін Турной

3
цей код вказує точний час місцевості. він також служить таймером.
Равікіран Д

Мені здається, було б краще використовувати "% H" замість "% I", тому що "% I" відображає лише години з 0 до 12 і не показує, чи час AM або PM. Або інший спосіб - використовувати як "% I", так і "% p" ("% p" означає AM / PM).
Demian Wolf

1

Я щойно створив простий таймер, використовуючи шаблон MVP (однак для цього простого проекту це може бути надмірним). У ньому є вихід, старт / пауза та кнопка зупинки. Час відображається у форматі HH: MM: SS. Підрахунок часу здійснюється за допомогою потоку, який працює кілька разів на секунду, і різниці між часом запуску таймера та поточним часом.

Вихідний код на github


1

У мене є проста відповідь на цю проблему. Я створив ланцюжок для оновлення часу. У потоці я запускаю цикл while, який отримує час і оновлюю його. Перевірте наведений нижче код і не забудьте позначити його як правильну відповідь.

from tkinter import *
from tkinter import *
import _thread
import time


def update():
    while True:
      t=time.strftime('%I:%M:%S',time.localtime())
      time_label['text'] = t



win = Tk()
win.geometry('200x200')

time_label = Label(win, text='0:0:0', font=('',15))
time_label.pack()


_thread.start_new_thread(update,())

win.mainloop()

Цей код має безліч проблем. Цикл while у функції update () є зайнятим циклом. Доступ до глобальної змінної time_label з декількох потоків не є чудовим.
Кенджі Ногучі,

але я відчуваю, що це найкращий спосіб це зробити. оскільки це не знижує продуктивність програми.
Хардіп Сінгх,

1

Root.after (ms, func) - метод, який потрібно використовувати. Просто зателефонуйте йому один раз перед запуском mainloop і переплануйте його всередині зв'язаної функції кожного разу, коли він буде викликаний. Ось приклад:

from tkinter import *
import time


def update_clock():
    timer_label.config(text=time.strftime('%H:%M:%S',time.localtime()),
                  font='Times 25')  # change the text of the time_label according to the current time
    root.after(100, update_clock)  # reschedule update_clock function to update time_label every 100 ms

root = Tk()  # create the root window
timer_label = Label(root, justify='center')  # create the label for timer
timer_label.pack()  # show the timer_label using pack geometry manager
root.after(0, update_clock)  # schedule update_clock function first call
root.mainloop()  # start the root window mainloop

0
from tkinter import *

from tkinter import messagebox

root = Tk()

root.geometry("400x400")

root.resizable(0, 0)

root.title("Timer")

seconds = 21

def timer():

    global seconds
    if seconds > 0:
        seconds = seconds - 1
        mins = seconds // 60
        m = str(mins)

        if mins < 10:
            m = '0' + str(mins)
        se = seconds - (mins * 60)
        s = str(se)

        if se < 10:
            s = '0' + str(se)
        time.set(m + ':' + s)
        timer_display.config(textvariable=time)
        # call this function again in 1,000 milliseconds
        root.after(1000, timer)

    elif seconds == 0:
        messagebox.showinfo('Message', 'Time is completed')
        root.quit()


frames = Frame(root, width=500, height=500)

frames.pack()

time = StringVar()

timer_display = Label(root, font=('Trebuchet MS', 30, 'bold'))

timer_display.place(x=145, y=100)

timer()  # start the timer

root.mainloop()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.