在PyQt開發中,時常需要對控制項的值進行校驗,如需要校驗QCheckBox是否被選中,QLabel是否校驗值是否為空等等。在複雜的業務場景下,這類控制項如果數量很多,逐個校驗就顯得麻煩,需要一一獲得控制項名稱,再調用對應的方法來判斷是否被選中、是否為空等。而且開發過程中如果多控制項做了增減,還需要增減校驗 ...
在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個未選中,列印結果符合事實。
總結
上面的僅為演示代碼,只是演示處理此類問題的邏輯,剛構建邏輯時會顯得很繞,但是構建起來後就很好用了,如果再漸增控制項,只要遵守控制項名稱命名規範,那麼所增加的控制項校驗也無需增加校驗代碼,減少控制項也一樣。
延申用法
如果一個界面中有很多控制項需要填寫數值或清空數值,如:
- 提交表單後,控制項數值初始化
- 校驗不通過,需要在控制項中做信息提示(諸如placeholder)
一樣可以使用這個邏輯進行處理,只要前期構建好,代碼復用完全不是問題。