PyQt5 QTableWidget 欄位值(cell)自動轉大寫

稍微查一下PyQt5的語法,就會知道搭配Signal就可以讓cell被更動時觸發,並執行你要做的事

下列片段以本次主題:自動轉大寫為例

1
2
3
4
5
6
7
8
9
def __init__(self):
#...省略其他片段
self.ui.tableWidget.itemChanged.connect(self.upperText)
#...省略其他片段

def upperText(self):
item = self.ui.tableWidget.currentItem()
item.setText(item.text().upper())
self.ui.tableWidget.setItem(item.row(),item.column(),item)

確實,這樣寫並沒有問題 ── 只限於你的TABLE預設就有塞值在裡面

實務上,user倒入資料後(或是一啟動就直接連接資料庫取值),會發現程式直接崩潰

為什麼呢?

因為QTableWidget每次setItem時,都會觸發一次itemChanged!
而目前的table是空的,裡面沒有任何item,導致item.setText()這裡,找不到setText這個函數,於是程式就死掉了

解決方法就是

倒入資料到table時,暫停signal

在你放入資料的函數裡,頭尾分加入關閉、啟動signal就行了!

1
2
3
4
5
6
def putIntoTable(self):
+ self.ui.tableWidget.blockSignals(True)
for i in range(10):
self.ui.tableWidget.insertRow(i)
self.ui.tableWidget.setItem(i,0,QTableWidgetItem(str(i)))
+ self.ui.tableWidget.blockSignals(False)

如果有許多地方需要暫停的話,可以把他寫成裝飾器(decorator),就不用再每個頭尾都加開關嘍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from functools import wraps  # 使用裝飾器(decorator),記得要import

def _blockSignals(f):
@wraps(f)
def wrapper(self):
self.ui.tableWidget.blockSignals(True)
f(self)
self.ui.tableWidget.blockSignals(False)
return wrapper
@_blockSignals
def putIntoTable(self):
for i in range(10):
self.ui.tableWidget.insertRow(i)
self.ui.tableWidget.setItem(i,0,QTableWidgetItem(str(i)))

參考資料

How to know when a cell in a QTableWidget has been edited