PyQt5表格修改单元格联动更新时触发RecursionError递归错误
问题根因
递归错误是信号连锁触发导致的:QTableWidget的itemChanged信号不会区分修改来源,不管是用户手动编辑单元格,还是代码调用setItem修改单元格内容,都会触发该信号。你的联动逻辑会形成无限调用闭环:
- 用户修改第3列→触发
changeIcon方法→代码主动修改第4列内容 - 第4列被代码修改→再次触发
changeIcon方法→代码主动修改第3列内容 - 上述流程无限循环,超过Python递归深度限制后抛出
RecursionError。
修复方案
在代码主动调用setItem修改联动单元格前,临时断开itemChanged信号与changeIcon方法的绑定,所有单元格修改操作完成后再重新连接信号,从根源上阻断信号连锁触发的死循环。
修复后的完整代码如下:
def tabledata(self): ..... self.tabella_registrazioni.itemChanged.connect(self.changeIcon) ..... def changeIcon(self, item): row = item.row() col = item.column() custcode_item = self.tabella_registrazioni.item(row, 3) custname_item = self.tabella_registrazioni.item(row, 4) # 单元格未初始化时直接返回,避免空对象报错 if not custcode_item or not custname_item: return custcode = custcode_item.text().strip() custname = custname_item.text().strip() # 临时断开信号,避免setItem触发递归 self.tabella_registrazioni.itemChanged.disconnect(self.changeIcon) try: if col == 3 and custcode: res = d.execute("SELECT 1 FROM CODES WHERE ANCODICE = ?", (custcode,)).fetchone() if res: cname = res[0] self.tabella_registrazioni.setItem(row, 4, QtWidgets.QTableWidgetItem(str(cname))) if col == 4 and custname: res = d.execute("SELECT 2 FROM CODES WHERE ANDESCRI = ?", (custname,)).fetchone() if res: ccode = res[0] self.tabella_registrazioni.setItem(row, 3, QtWidgets.QTableWidgetItem(str(ccode))) finally: # 无论执行是否报错,都恢复信号连接 self.tabella_registrazioni.itemChanged.connect(self.changeIcon)
注意事项
- 不要图省事儿省略
try/finally块,一旦SQL查询、单元格赋值过程中抛出异常,信号会永久断开,后续所有单元格编辑都不会再触发联动逻辑。 - 用
strip()处理单元格输入文本,可以一次性过滤首尾所有空格、换行等空白字符,替代原有重复的空值判断逻辑,可靠性更高。 - 不推荐用全局标记位(比如自定义布尔值判断是否为代码修改)的方案处理这类问题,多入口修改单元格时很容易漏改标记,稳定性不如临时断连信号的方案。
内容的提问来源于stack exchange,提问作者IT-SRL
相关产品推荐
相关产品推荐

