在 GUI 應用程式中,定時更新介面元素是常見需求——例如即時時鐘、進度條輪詢、動畫幀更新等。wxPython 提供 wx.Timer 類別,讓開發者能以事件驅動方式輕鬆實作週期性任務。本文將透過一個完整的「即時時鐘」範例,詳細說明 wx.Timer 的建立、綁定、啟動與停止流程。
| 方法/事件 | 用途 |
|---|---|
wx.Timer(owner) | 建立定時器,指定事件接收者 |
Bind(wx.EVT_TIMER, handler, timer) | 將定時器事件綁定至處理函式 |
timer.Start(interval, oneShot=False) | 啟動定時器,interval 以毫秒為單位 |
timer.Stop() | 停止定時器 |
wx.EVT_TIMER | 定時器觸發事件 |
# -*- coding: utf-8 -*-
import wx
import time
class MyFrame(wx.Frame):
def __init__(self, parent):
super().__init__(parent, id=wx.ID_ANY, title="即時時鐘示範",
pos=wx.DefaultPosition, size=wx.Size(483, 155),
style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTIONTEXT))
# 版面配置:兩顆按鈕並排
gSizer = wx.GridSizer(0, 2, 0, 0)
self.btn_start = wx.Button(self, wx.ID_ANY, "啟動定時器")
self.btn_stop = wx.Button(self, wx.ID_ANY, "停止定時器")
gSizer.Add(self.btn_start, 0, wx.ALL, 5)
gSizer.Add(self.btn_stop, 0, wx.ALL, 5)
self.SetSizer(gSizer)
self.Layout()
# 狀態列:兩欄分別顯示日期與時間
self.status_bar = self.CreateStatusBar(2, wx.ST_SIZEGRIP)
self.Centre(wx.BOTH)
# 事件綁定
self.btn_start.Bind(wx.EVT_BUTTON, self.on_start)
self.btn_stop.Bind(wx.EVT_BUTTON, self.on_stop)
# 建立並綁定定時器
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.on_timer, self.timer)
def on_start(self, event):
"""啟動定時器,間隔 1000 ms(1 秒)"""
self.timer.Start(1000)
def on_stop(self, event):
"""停止定時器"""
self.timer.Stop()
def on_timer(self, event):
"""定時器觸發:更新狀態列日期與時間"""
t = time.localtime()
date_str = time.strftime("%Y-%B-%d", t) # 例:2025-January-15
time_str = time.strftime("%I:%M:%S", t) # 例:03:45:20
self.SetStatusText(date_str, 0)
self.SetStatusText(time_str, 1)
def __del__(self):
pass
if __name__ == '__main__':
app = wx.App() # wx.PySimpleApp() 在新版已棄用
frame = MyFrame(None)
frame.Show()
app.MainLoop()
self.timer = wx.Timer(self) # self 為事件接收者
self.Bind(wx.EVT_TIMER, self.on_timer, self.timer) # 指定處理函式
採用 Bind 而非舊式 EVT_TIMER 巨集,符合現代 wxPython 風格,且支援多定時器共存。
self.timer.Start(1000) # 每 1000 ms 觸發一次
若需單次觸發,可傳入 oneShot=True。
def on_timer(self, event):
t = time.localtime()
self.SetStatusText(time.strftime("%Y-%B-%d", t), 0)
self.SetStatusText(time.strftime("%I:%M:%S", t), 1)
在事件處理函式中直接操作 UI 元件是安全的,因為 wxPython 事件迴圈運行於主執行緒。

wx.Timer 實例,分別綁定不同處理函式,互不干擾。threading.Timer 或 asyncio 搭配 wx.CallAfter 回主執行緒更新 UI。timer.Stop(),避免殘留事件導致例外。| 現象 | 可能原因 | 解決方案 |
|---|---|---|
| 定時器不觸發 | 未呼叫 Start() 或間隔設為 0 | 確認 Start(interval>0) |
| UI 凍結 | 在 on_timer 執行耗時運算 | 將耗時工作移至背景執行緒,用 wx.CallAfter 更新 UI |
| 重複觸發 | 多次呼叫 Start() 未先 Stop() | 啟動前先檢查 timer.IsRunning() |