ฉันจะกำหนดเวลาการอัปเดต (f/e เพื่ออัปเดตนาฬิกา) ใน tkinter ได้อย่างไร

ฉันกำลังเขียนโปรแกรมด้วยไลบรารี tkinter ของ Python

ปัญหาหลักของฉันคือฉันไม่รู้วิธีสร้าง ตัวจับเวลา หรือ นาฬิกา เช่น hh:mm:ss

ฉันต้องการให้มันอัปเดตตัวเอง (นั่นคือสิ่งที่ฉันไม่รู้ว่าต้องทำอย่างไร) เมื่อฉันใช้ time.sleep() ในการวนซ้ำ GUI ทั้งหมดค้าง


person Diego Castro    schedule 08.03.2010    source แหล่งที่มา


คำตอบ (6)


หน้าต่างรูทของ 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 เป็นแบบเธรดเดียว โดยทั่วไปความล่าช้าจะวัดเป็นไมโครวินาที

person Bryan Oakley    schedule 08.03.2010
comment
การเรียกซ้ำกับตัวเองจะไม่ทำให้เกิดการเรียกซ้ำสูงสุดสำหรับข้อผิดพลาดถึงวัตถุหลามหรือไม่ - person stochastic13; 29.12.2017
comment
@SatwikPasani: ไม่ เพราะมันไม่ใช่การโทรซ้ำ มันแค่ทำให้งานอยู่ในคิวเท่านั้น - person Bryan Oakley; 29.12.2017
comment
วิธีการรัน func เพียงครั้งเดียวโดยมีความล่าช้า? - person user924; 17.04.2018
comment
@user924: self.root.after(delay, func). - person Bryan Oakley; 17.04.2018

ตัวอย่างนาฬิกา 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()
person David Poole    schedule 01.12.2015
comment
นี่เป็นคำตอบที่ดี โดยมีสิ่งสำคัญอย่างหนึ่ง - เวลาที่แสดงเป็นเวลาของระบบจริงๆ และไม่ใช่เวลาข้อผิดพลาดสะสม (หากคุณรอประมาณ 1,000 มิลลิวินาที 60 ครั้ง คุณจะได้รับประมาณหนึ่งนาทีไม่ใช่ 60 วินาที และข้อผิดพลาดก็เพิ่มขึ้นตาม เวลา). อย่างไรก็ตาม - นาฬิกาของคุณสามารถข้ามวินาทีบนจอแสดงผลได้ - คุณสามารถสะสมข้อผิดพลาดในเสี้ยววินาทีได้ และเช่น ข้ามไปข้างหน้า 2 วินาที ฉันอยากจะแนะนำ: self.after(1000 - int(1000 * (time.time() - int(time.time()))) or 1000, self.onUpdate) อาจดีกว่าถ้าบันทึก time.time() ลงในตัวแปรก่อนนิพจน์นี้ - person Tomasz Gandor; 12.06.2017
comment
ฉันปรารถนาที่จะยอดเยี่ยมพอที่จะฝัง xkcd ลงในความคิดเห็นของฉัน :) - person bitsmack; 21.06.2017
comment
การใช้ frame.after() แทน root.after() มีประโยชน์อย่างไร? - person Kai Wang; 04.09.2019

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
person Demian Wolf    schedule 19.02.2020
comment
... หมายเหตุด้านข้าง after คือ วิธีการวิดเจ็ตสากล ดังนั้นจึงสามารถเรียกใช้บน timer_label ได้เช่นกัน - person Wolf; 04.05.2021

ฉันเพิ่งสร้างตัวจับเวลาอย่างง่ายโดยใช้รูปแบบ MVP (แต่อาจเกินความจำเป็นสำหรับโปรเจ็กต์ง่ายๆ นั้น) มีปุ่มออก เริ่ม/หยุดชั่วคราว และปุ่มหยุด เวลาจะแสดงในรูปแบบ HH:MM:SS การนับเวลาดำเนินการโดยใช้เธรดที่ทำงานหลายครั้งต่อวินาที และความแตกต่างระหว่างเวลาที่เริ่มจับเวลากับเวลาปัจจุบัน

ซอร์สโค้ดบน github

person Community    schedule 03.06.2017

ฉันมีคำตอบง่ายๆสำหรับปัญหานี้ ฉันสร้างกระทู้เพื่ออัปเดตเวลา ในเธรด ฉันเรียกใช้ while loop ซึ่งรับเวลาและอัปเดต ตรวจสอบโค้ดด้านล่างและอย่าลืมทำเครื่องหมายว่าเป็นคำตอบที่ถูกต้อง

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()
person Hardeep Singh    schedule 28.09.2019
comment
รหัสนี้มีปัญหามากมาย การวนซ้ำ while ในฟังก์ชัน update() เป็นการวนซ้ำไม่ว่าง ในการเข้าถึงตัวแปรทั่วโลก time_label จากหลายเธรดนั้นไม่ดีนัก - person Kenji Noguchi; 01.10.2019
comment
แต่ฉันรู้สึกว่านี่เป็นวิธีที่ดีที่สุดที่จะทำ เพราะไม่ทำให้ประสิทธิภาพของแอพพลิเคชั่นลดลง - person Hardeep Singh; 12.10.2019

person    schedule
comment
มันจะมีประโยชน์ถ้าคุณสามารถเพิ่มคำอธิบายได้ แค่คัดลอก/วางโค้ดไม่ค่อยมีประโยชน์ ;-) - person Martin Tournoij; 26.09.2017
comment
รหัสนี้ให้เวลาที่แน่นอนของท้องที่ และยังทำหน้าที่เป็นตัวจับเวลาด้วย - person Ravikiran D; 26.09.2017
comment
สำหรับฉัน ดูเหมือนว่าจะดีกว่าถ้าใช้ %H แทน %I เพราะ %I แสดงเฉพาะชั่วโมงตั้งแต่ 0 ถึง 12 ชั่วโมง และไม่แสดงว่าเวลาเป็น AM หรือ PM หรืออีกวิธีหนึ่งคือใช้ทั้ง %I และ %p (%p หมายถึง AM/PM) - person Demian Wolf; 19.02.2020