如何用PyQt5开发精准的工作计时秒表?
精准PyQt5计时器实现方案
问题根源分析
你之前的方案存在两个核心问题导致计时不准:
- 依赖
time.sleep(1)或计数器累加的方式,会因为代码执行耗时、系统调度延迟产生累计误差,运行越久偏差越大 - 直接使用
datetime.now()显示当前时间,无法实现从0开始的计时逻辑
正确实现思路
通过记录开始计时的时间戳,每次更新时计算当前时间与起始时间的差值,这种方式完全基于系统时间计算,不会产生累计误差。配合PyQt5的QTimer定时触发更新,既保证UI响应,又能维持计时精度。
完整代码实现
import sys from datetime import datetime from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QWidget) from PyQt5.QtCore import QTimer, Qt class TimeTracker(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle('工作时长记录器') self.setGeometry(300, 300, 400, 200) # 核心变量 self.start_time = None # 记录开始计时的时间 self.total_elapsed = 0 # 累计时长(用于暂停后继续计时) self.startWatch = False # UI组件 self.time_label = QLabel('<h1 style="color:black">00:00:00</h1>', self) self.time_label.setAlignment(Qt.AlignCenter) self.start_btn = QPushButton('开始计时', self) self.start_btn.clicked.connect(self.start_timer) self.pause_btn = QPushButton('暂停计时', self) self.pause_btn.clicked.connect(self.pause_timer) self.pause_btn.setEnabled(False) self.reset_btn = QPushButton('重置', self) self.reset_btn.clicked.connect(self.reset_timer) # 布局 layout = QVBoxLayout() layout.addWidget(self.time_label) layout.addWidget(self.start_btn) layout.addWidget(self.pause_btn) layout.addWidget(self.reset_btn) central_widget = QWidget() central_widget.setLayout(layout) self.setCentralWidget(central_widget) # 定时器,每秒触发一次更新 self.timer = QTimer(self) self.timer.timeout.connect(self.update_display) def start_timer(self): if not self.startWatch: self.start_time = datetime.now() self.startWatch = True self.timer.start(1000) # 每秒触发一次 self.start_btn.setEnabled(False) self.pause_btn.setEnabled(True) def pause_timer(self): if self.startWatch: # 计算当前已流逝的时间,累加到total_elapsed elapsed = datetime.now() - self.start_time self.total_elapsed += elapsed.total_seconds() self.startWatch = False self.timer.stop() self.start_btn.setEnabled(True) self.pause_btn.setEnabled(False) def reset_timer(self): self.startWatch = False self.timer.stop() self.start_time = None self.total_elapsed = 0 self.time_label.setText('<h1 style="color:black">00:00:00</h1>') self.start_btn.setEnabled(True) self.pause_btn.setEnabled(False) def update_display(self): if self.start_time and self.startWatch: # 计算总流逝时间:累计时长 + 当前会话的流逝时间 current_elapsed = (datetime.now() - self.start_time).total_seconds() total_seconds = int(self.total_elapsed + current_elapsed) # 转换为时分秒 hours = total_seconds // 3600 minutes = (total_seconds % 3600) // 60 seconds = total_seconds % 60 # 格式化显示,补零 time_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}" self.time_label.setText(f'<h1 style="color:black">{time_str}</h1>') # 后续扩展:实时计算收入 # 示例:假设时薪为50元 hourly_rate = 50 total_income = (total_seconds / 3600) * hourly_rate # 可添加QLabel显示收入: # self.income_label.setText(f'当前收入:{total_income:.2f}元') if __name__ == '__main__': app = QApplication(sys.argv) window = TimeTracker() window.show() sys.exit(app.exec_())
方案优势
- 无累计误差:每次通过系统时间差计算时长,不受代码执行延迟影响
- 支持暂停/继续:通过
total_elapsed记录累计时长,满足工作中中途休息的场景 - UI响应流畅:使用
QTimer触发更新,不会阻塞主线程 - 易扩展:只需基于
total_seconds计算收入,轻松实现实时薪资更新
内容的提问来源于stack exchange,提问作者nty51
相关产品推荐
相关产品推荐

