You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在PyQt5中实现多计时器并行运行的GUI?

Fixing Parallel Timer Issues in PyQt5 TableWidget

Let's break down exactly what's causing your weird timer behavior and fix it step by step.

What's Going Wrong

  1. Shared Variable Conflict
    Your showTime method relies on self.num, which gets overwritten every time you start a new timer. When multiple timers fire their timeout signals, all of them call showTime—but they all use the latest self.num value. 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)
  2. No Connection Between Timers and Table Rows
    There's no way for showTime to know which timer actually triggered it. So it can't map back to the correct row in your TableWidget or the right time entry in time_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.
  • showTime no 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

火山引擎 最新活动