如何在PyQt5中实现多计时器并行运行的GUI?
Let's break down exactly what's causing your weird timer behavior and fix it step by step.
What's Going Wrong
Shared Variable Conflict
YourshowTimemethod relies onself.num, which gets overwritten every time you start a new timer. When multiple timers fire theirtimeoutsignals, all of them callshowTime—but they all use the latestself.numvalue. That's why:- Older timers stop updating (their corresponding name is no longer stored in
self.num) - The newest timer speeds up (multiple timers are incrementing the same row's time every second)
- Older timers stop updating (their corresponding name is no longer stored in
No Connection Between Timers and Table Rows
There's no way forshowTimeto know which timer actually triggered it. So it can't map back to the correct row in your TableWidget or the right time entry intime_dict.
Step-by-Step Solution
We need to tie each timer to its unique identifier (name and row index) so showTime knows exactly which entry to update. Here are two solid approaches:
Approach 1: Use Lambda to Pass Context
This is the simplest fix—we'll capture the timer's name and row index when connecting the timeout signal.
Update start_timer Method
Replace your existing start_timer with this:
def start_timer(self): self.num_index = self.comboBox1.currentIndex() current_num = self.comboBox1.currentText() # Use a local var instead of overwriting self.num if current_num: self.comboBox1.removeItem(self.num_index) # Add timer name to the table self.newItem = QTableWidgetItem(current_num) self.newItem.setTextAlignment(Qt.AlignCenter) self.tablewidget.setItem(self.x, 0, self.newItem) # Initialize timer and time for this specific entry self.timer_dict[current_num] = QTimer() self.time_dict[current_num] = QTime(0, 0, 0) # Connect timeout with context using lambda self.timer_dict[current_num].timeout.connect(lambda: self.showTime(current_num, self.x)) self.timer_dict[current_num].start(1000) self.x += 1
Update showTime Method
Modify it to accept the timer name and row index as parameters:
def showTime(self, timer_name, row): # Update the time for this specific timer self.time_dict[timer_name] = self.time_dict[timer_name].addSecs(1) timeDisplay = self.time_dict[timer_name].toString("mm:ss") # Update the correct row in the table self.newItem2 = QTableWidgetItem(timeDisplay) self.newItem2.setTextAlignment(Qt.AlignCenter) self.tablewidget.setItem(row, 1, self.newItem2)
Approach 2: Use QTimer Properties (Cleaner for Complex Setups)
If you might add more properties to timers later, storing context directly on the QTimer object is better.
Update start_timer Method
def start_timer(self): self.num_index = self.comboBox1.currentIndex() current_num = self.comboBox1.currentText() current_row = self.x # Capture the row index for this timer if current_num: self.comboBox1.removeItem(self.num_index) self.newItem = QTableWidgetItem(current_num) self.newItem.setTextAlignment(Qt.AlignCenter) self.tablewidget.setItem(current_row, 0, self.newItem) self.timer_dict[current_num] = QTimer() self.time_dict[current_num] = QTime(0, 0, 0) # Store context as properties on the timer self.timer_dict[current_num].setProperty("timer_name", current_num) self.timer_dict[current_num].setProperty("row", current_row) self.timer_dict[current_num].timeout.connect(self.showTime) self.timer_dict[current_num].start(1000) self.x += 1
Update showTime Method
Use self.sender() to get the timer that triggered the signal, then retrieve its properties:
def showTime(self): timer = self.sender() if not timer: # Guard against cases where sender isn't a timer return timer_name = timer.property("timer_name") row = timer.property("row") # Update the time and table row self.time_dict[timer_name] = self.time_dict[timer_name].addSecs(1) timeDisplay = self.time_dict[timer_name].toString("mm:ss") self.newItem2 = QTableWidgetItem(timeDisplay) self.newItem2.setTextAlignment(Qt.AlignCenter) self.tablewidget.setItem(row, 1, self.newItem2)
Why This Works
- Each timer now carries its own context (name and row index) when it fires.
showTimeno longer relies on a shared variable, so each timer updates its own row independently.- No more overlapping updates causing speedups or stopped timers.
内容的提问来源于stack exchange,提问作者Link




