部署到gitlab的方法跟放到github上差不多,若曾經做過的話,應該很快就可以上手!

閱讀全文 »

Python除了寫爬蟲、小工具方便又快速之外,其中最有名的,就是做為網頁後端使用的django了!跟著官方的tutorial試做一次,記錄自己容易忘記的地方

閱讀全文 »

在QTableWidget中,呈現TABLE的方式是從1開始
但實際儲存方式,則是從0開始
也就是要刪除看到的第一列,參數要給0

self.ui.tableWidget.removeRow(0) #刪除看到的第一列
self.ui.tableWidget.removeRow(1) #刪除看到的第二列
self.ui.tableWidget.removeRow(N-1) #刪除看到的第N列

但是要多選刪除時
就不是簡單的跑一個迴圈就行了

items = self.ui.tableWidget.selectedIndexes()
wannaDelRows = [item.row() for item in items]

for row in wannaDelRows:
    self.ui.tableWidget.removeRow(row)

實際運行會發現,只有第一列正確被刪除,其他列似乎全都不對了?!

錯誤的原因是因為第一列被刪除後,該列後方的所有位置也跟著減-1了!
也就是當你只是單純地使用selectedIndexes()取得多選的列來刪除的話,從第2筆開始的指到row,已經不在是當初user選到要刪除的row了!

那該怎麼解決呢?

從後面開始刪除就行了!

為避免user選的item是同一個row不同column
造成同一個row取到2次,導致跑迴圈時刪除到不應該被刪掉的
因此還需要搭配set確保要刪除的row只會被執行一次
將原本的程式碼修改如下

items = self.ui.tableWidget.selectedIndexes()
wannaDelRows = [item.row() for item in items]
wannaDelRowsReverse = sorted(set(wannaDelRows),reverse=True)

for row in wannaDelRowsReverse:
    self.ui.tableWidget.removeRow(row)

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

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

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就行了!

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),就不用再每個頭尾都加開關嘍

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