在PyQt
開發中,時常需要對控制元件的值進行校驗,如需要校驗QCheckBox
是否被選中,QLabel
是否校驗值是否為空等等。在複雜的業務場景下,這類控制元件如果數量很多,逐個校驗就顯得麻煩,需要一一獲得控制元件名稱,再呼叫對應的方法來判斷是否被選中、是否為空等。而且開發過程中如果多控制元件做了增減,還需要增減校驗的邏輯,那會要了老命。
此篇文章,推薦使用__dict__
屬性 + 字典對映來快速校驗控制元件值,並且無視後面控制元件的增減,無需調整程式碼。
__dict__
是什麼?做python
開發的,或多或少都接觸過該屬性,它是類
獨有的一個特性,用來儲存類
的一些屬性,關於這個屬性的相關文章,網上一抓一大把,此處不作贅述,需要說明的是,類範例
也有自己的__dict__
屬性,而且和類
的__dict
不同,``類範例的
dict只儲存了通過
self.xxx`所宣告的屬性和方法。
接下來的演示中,僅使用QCheckBox
(為了省事),同時要保持這些控制元件的名稱要具備同樣的特徵,下面的截圖中,所有的控制元件名稱都以checkbox
結尾。
1、使用.ui
檔案生成.py
檔案
2、簡單寫個入口程式
繼承剛才生成的.py
檔案,在這裡可以實現自己的方法,在自定義類中,先列印__dict__
,看看有哪些值。
{
'centralwidget': <PyQt6.QtWidgets.QWidget object at 0x00000231DD4E9D30>,
'gridLayout': <PyQt6.QtWidgets.QGridLayout object at 0x00000231DD4E9DC0>,
'c_checkbox': <PyQt6.QtWidgets.QCheckBox object at 0x00000231DD4E9E50>,
'd_checkbox': <PyQt6.QtWidgets.QCheckBox object at 0x00000231DD4E9EE0>,
'a_checkbox': <PyQt6.QtWidgets.QCheckBox object at 0x00000231DD4E9F70>,
'b_checkbox': <PyQt6.QtWidgets.QCheckBox object at 0x00000231DD9A3040>,
'f_checkbox': <PyQt6.QtWidgets.QCheckBox object at 0x00000231DD9A30D0>,
'e_checkbox': <PyQt6.QtWidgets.QCheckBox object at 0x00000231DD9A3160>,
'menubar': <PyQt6.QtWidgets.QMenuBar object at 0x00000231DD9A31F0>,
'statusbar': <PyQt6.QtWidgets.QStatusBar object at 0x00000231DD9A3280>
}
可以看到,它是一個字典,它包含了介面上所有的控制元件的名稱和範例物件,這裡就體現出了控制元件名稱命名時遵守統一特徵的好處了,即能望文生義,也方便處理。
3、提取所有QCheckBox
的控制元件名稱,構建一個校驗的通用邏輯
import sys
from PyQt6.QtWidgets import QMainWindow, QApplication, QCheckBox
from ui_main import Ui_MainWindow
class MainWindow(Ui_MainWindow, QMainWindow):
def __init__(self):
super().__init__()
super().setupUi(self)
self.show()
self.checkboxs()
def checkboxs(self):
# print(self.__dict__)
# 增加這個字典對映是為了可以自動處理更多型別的控制元件值校驗
widget_mapping = {
'QCheckBox': QCheckBox.isChecked
}
# 獲取所有QCheckBox的控制元件名稱
boxs = [
item for item in self.__dict__ \
if item.endswith('_checkbox')
]
# 用來儲存未被勾選的控制元件
un_checked = []
for item in boxs:
widget_instance = self.__dict__.get(item)
widget_method = widget_mapping.get(
self.__dict__.get(item).__class__.__name__
)
# 如果該QCheckBox處於未選中,則被新增到列表中
if not widget_method(widget_instance):
un_checked.append(item)
print(un_checked)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec())
4、邏輯分析
(1)
在程式碼
boxs = [
item for item in self.__dict__ \
if item.endswith('_checkbox')
]
中,通過__dict__
提取了所有以_checkbox
結尾的控制元件名稱,注意,這只是字串而已,並非控制元件本身。
(2)構建一個通用的控制元件名稱和控制元件方法的字典對映
# 增加這個字典對映是為了可以自動處理更多型別的控制元件值校驗
widget_mapping = {
'QCheckBox': QCheckBox.isChecked
}
這麼做的目的是為了讓這個邏輯更具通用性,讓這個邏輯相容其他控制元件,簡單來說,可以通過控制元件的名稱(boxs列表)找到該控制元件對應的方法,因為每個控制元件獲取值所用的方法不盡相同。
(3)遍歷boxs
列表,逐個去widget_mapping
找對應的方法,假如這裡要較多種控制元件的話,字典對映的優勢就體現出來了。widget_method
就是該控制元件獲取值所要用的方法了,QCheckBox
控制元件,就用isChecked
方法來獲取控制元件是否被選中。
(4)呼叫所找到的方法widget_method
。這裡之所以要把控制元件範例widget_instance
傳入方法中,是因為控制元件方法isChecked
是單獨呼叫的,它預設要傳入self引數
即範例本身。
執行程式碼看看效果
可以看到6個選項均為選中,列印結果符合該事實。
在qt desinger
中預設勾選兩個,再試試效果
有4個未選中,列印結果符合事實。
上面的僅為演示程式碼,只是演示處理此類問題的邏輯,剛構建邏輯時會顯得很繞,但是構建起來後就很好用了,如果再漸增控制元件,只要遵守控制元件名稱命名規範,那麼所增加的控制元件校驗也無需增加校驗程式碼,減少控制元件也一樣。
如果一個介面中有很多控制元件需要填寫數值或清空數值,如:
一樣可以使用這個邏輯進行處理,只要前期構建好,程式碼複用完全不是問題。