Bagaimana cara menjadwalkan pembaruan (f/e, untuk memperbarui jam) di tkinter?

Saya sedang menulis program dengan perpustakaan tkinter Python.

Masalah utama saya adalah saya tidak tahu cara membuat timer atau jam seperti hh:mm:ss.

Saya membutuhkannya untuk memperbarui dirinya sendiri (itulah yang saya tidak tahu caranya); ketika saya menggunakan time.sleep() dalam satu lingkaran, seluruh GUI membeku.


person Diego Castro    schedule 08.03.2010    source sumber
comment


Jawaban (6)


Jendela root Tkinter memiliki metode yang disebut after yang dapat digunakan untuk menjadwalkan pemanggilan suatu fungsi setelah jangka waktu tertentu. Jika fungsi itu sendiri memanggil after Anda telah menyiapkan acara berulang secara otomatis.

Berikut adalah contoh yang berfungsi:

# 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()

Ingatlah bahwa after tidak menjamin fungsi tersebut akan berjalan tepat waktu. Ini hanya menjadwalkan pekerjaan untuk dijalankan setelah jangka waktu tertentu. Jika aplikasi sedang sibuk mungkin ada penundaan sebelum dipanggil karena Tkinter adalah single-threaded. Penundaan biasanya diukur dalam mikrodetik.

person Bryan Oakley    schedule 08.03.2010
comment
Bukankah panggilan rekursif ke dirinya sendiri akan menyebabkan kesalahan rekursi maksimum untuk objek python tercapai? - person stochastic13; 29.12.2017
comment
@SatwikPasani: tidak, karena ini bukan panggilan rekursif. Itu hanya menempatkan pekerjaan dalam antrian. - person Bryan Oakley; 29.12.2017
comment
bagaimana cara menjalankan fungsi hanya sekali dengan penundaan? - person user924; 17.04.2018
comment
@ pengguna924: self.root.after(delay, func). - person Bryan Oakley; 17.04.2018

Contoh jam Python3 menggunakan frame.after() daripada aplikasi tingkat atas. Juga menunjukkan pembaruan label dengan 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
Ini adalah jawaban yang bagus, dengan satu hal penting - waktu yang ditampilkan benar-benar waktu sistem, dan bukan waktu kesalahan yang terakumulasi (jika Anda menunggu sekitar 1000 ms 60 kali, Anda mendapatkan sekitar satu menit, bukan 60 detik, dan kesalahan bertambah seiring waktu). Namun - jam Anda dapat melewati beberapa detik pada tampilan - Anda dapat mengakumulasi kesalahan sub-detik, dan misalnya. lewati 2 detik ke depan. Saya menyarankan: self.after(1000 - int(1000 * (time.time() - int(time.time()))) or 1000, self.onUpdate). Mungkin lebih baik menyimpan time.time() ke variabel sebelum ekspresi ini. - person Tomasz Gandor; 12.06.2017
comment
Saya bercita-cita menjadi cukup hebat untuk menyematkan xkcd ke dalam komentar saya :) - person bitsmack; 21.06.2017
comment
Apa keuntungan menggunakan frame.after() daripada root.after()? - person Kai Wang; 04.09.2019

root.after(ms, func) adalah metode yang perlu Anda gunakan. Panggil saja sekali sebelum mainloop dimulai dan jadwalkan ulang di dalam fungsi terikat setiap kali dipanggil. Berikut ini contohnya:

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
... hanya catatan tambahan, after adalah metode widget universal, sehingga dapat dipanggil di timer_label juga. - person Wolf; 04.05.2021

Saya baru saja membuat pengatur waktu sederhana menggunakan pola MVP (namun ini mungkin berlebihan untuk proyek sederhana itu). Ia telah berhenti, mulai/jeda dan tombol berhenti. Waktu ditampilkan dalam format HH:MM:SS. Penghitungan waktu diimplementasikan menggunakan thread yang berjalan beberapa kali per detik dan perbedaan antara waktu penghitung waktu dimulai dan waktu saat ini.

Kode sumber di github

person Community    schedule 03.06.2017

Saya punya jawaban sederhana untuk masalah ini. Saya membuat thread untuk memperbarui waktu. Di utas saya menjalankan loop sementara yang mendapatkan waktu dan memperbaruinya. Periksa kode di bawah ini dan jangan lupa menandainya sebagai jawaban yang benar.

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
Kode ini memiliki banyak masalah. Perulangan while pada fungsi update() adalah perulangan sibuk. Mengakses variabel global time_label dari beberapa thread tidaklah bagus. - person Kenji Noguchi; 01.10.2019
comment
tapi menurutku, inilah cara terbaik untuk melakukannya. karena hal ini tidak mengurangi kinerja aplikasi. - person Hardeep Singh; 12.10.2019

person    schedule
comment
Akan sangat membantu jika Anda dapat menambahkan beberapa deskripsi. Hanya menyalin/menempelkan kode jarang berguna ;-) - person Martin Tournoij; 26.09.2017
comment
Kode ini memberikan waktu yang tepat di lokasi tersebut. Kode ini juga berfungsi sebagai pengatur waktu. - person Ravikiran D; 26.09.2017
comment
Menurut saya, akan lebih baik menggunakan %H daripada %I, karena %I hanya menampilkan jam dari 0 hingga 12 dan tidak menunjukkan apakah waktunya AM atau PM. Atau cara lain adalah dengan menggunakan %I dan %p (%p menunjukkan AM/PM). - person Demian Wolf; 19.02.2020