Python Tkinter标签实时更新时间失败及AttributeError问题求助
Hey there! Let's work through the issues you're hitting with your time display app, plus a few tweaks to make it run smoothly.
First: Why the while True Loop Broke Things
Tkinter relies on its own mainloop() to handle all events—like rendering the window, updating elements, and responding to user actions. When you added a while True at the start, it completely blocked this loop. Your app couldn't draw the initial window until that infinite loop stopped (which only happened when you closed the stuck window), hence the delayed new window pop-up. We’ll ditch this loop entirely and use Tkinter’s built-in after() method for updates, which plays nicely with the event loop.
Second: The AttributeError: 'NoneType' object has no attribute 'config'
This is a super common gotcha! When you wrote:
cadran = Label(window, textvariable=hour).pack(padx = 300, pady = 20)
The pack() method returns None, so cadran ended up pointing to None instead of your actual Label widget. To fix this, split the widget creation and layout into two separate lines:
cadran = Label(window, textvariable=hour) cadran.pack(padx=300, pady=20)
Now cadran references the Label object, so you can modify it later (though we’ll use a cleaner approach by updating the bound StringVar directly).
Third: Updating the Time Properly
Your original hour_after() function reused the initial actualTime variable—this only stored the time once when the app started. We need to re-fetch the current Montreal time every second and update the StringVar that’s linked to the Label.
Corrected Full Code
Here’s the fixed version with comments explaining each change:
from datetime import datetime, timedelta, tzinfo from tkinter import Tk, Label, StringVar # Remove the while True loop entirely—it blocks Tkinter's event loop window = Tk() window.title('Hour') # Fixed: title is a method, not an attribute to assign # Your custom Montreal timezone class (kept as-is, works correctly) class Montréal(tzinfo): _offset = timedelta(seconds=-18000) _name = "-0500" _dst = timedelta(0) def utcoffset(self, dt): return self.__class__._offset def tzname(self, dt): return self.__class__._name def dst(self, dt): return self.__class__._dst def fromutc(self, dt): dtoff = dt.utcoffset() dtdst = dt.dst() delta = dtoff - dtdst if delta: dt += delta dtdst = dt.dst() if dtdst: return dt + dtdst else: return dt tz = Montréal() hour = StringVar() # Split Label creation and packing to keep a valid reference to the widget cadran = Label(window, textvariable=hour, font=('Arial', 24)) # Added font for better readability cadran.pack(padx=300, pady=20) def update_time(): # Fetch the current Montreal time EVERY time this function runs actual_time = datetime.now(tz) # Format to clean HH:MM:SS string formatted_time = actual_time.strftime('%H:%M:%S') # Update the StringVar (this automatically refreshes the Label) hour.set(formatted_time) # Schedule the next update in 1000ms (1 second) window.after(1000, update_time) # Start the automatic update loop update_time() window.mainloop()
Bonus Tips
- I fixed
window.title = ('Hour')towindow.title('Hour')—titleis a method you call, not an attribute to assign directly. - If you’re using Python 3.9 or newer, you can simplify timezone handling with the built-in
zoneinfomodule (it even handles daylight saving time automatically):from zoneinfo import ZoneInfo tz = ZoneInfo("America/Montreal")
内容的提问来源于stack exchange,提问作者Louis Couture

