小知识------QT Designer中TreeWidget、TableWidget等控件添加复选框+常用数据校验功能校验,以PySide6中实现数据校验工具为案例进行讲解
概述
在进行数据分析或者数据挖掘、机器学习、深度学习之时,数据的正确性十分重要,因此在数据分析之前,进行数据正确性校验是十分必要的,基于此,本文实现了一款批量数据校验工具,可以完成:身份证校验、座机电话校验、手机号码校验、日期时间校验、邮箱校验、IP地址校验、邮编格式校验、MAC地址校验、非空校验、数字校验、域名校验、URL地址校验、统一社会信用代码校验、全国组织机构代码校验、特殊字符校验等多类校验功能。
本文代码实现基于Python + PySide6实现,主要应用到的控件是TreeWidget、TableWidget、CheckBox几类控件,通过本文的案例,读者除了可以了解到python是如何进行各类数据校验外,还能了解到TreeWidget+CheckBox如何实现多文件列表选择,TableWidget+CheckBox控件如何实现校验功能选择。
工具设计与实现
工具最终效果呈现
功能设计
工具主要包括以下功能点:
- 点击打开,可以将选择文件夹中的所有xlsx文件全部列出,形成文件列表,并且可以点击复选框同时选中多个文件
- 点击文件列表会将选中的excel文件显示到表格控件之中,同时会动态生成数据校验配置表
- 在数据校验配置表中,勾选指定功能,便可以对选中的excel文件进行对应数据正确性校验
- 保存校验设置,可以将多个文件的校验配置进行存储
- 加载校验设置,可以将之前保存的校验设置加载
界面设计
界面设计见下图:
界面代码如下:
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'dv_mainwindow.ui'
##
## Created by: Qt User Interface Compiler version 6.6.0
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
QCursor, QFont, QFontDatabase, QGradient,
QIcon, QImage, QKeySequence, QLinearGradient,
QPainter, QPalette, QPixmap, QRadialGradient,
QTransform)
from PySide6.QtWidgets import (QAbstractItemView, QApplication, QFrame, QGridLayout,
QGroupBox, QHBoxLayout, QHeaderView, QLabel,
QLineEdit, QMainWindow, QMenu, QMenuBar,
QPushButton, QSizePolicy, QStatusBar, QTableView,
QTableWidget, QTableWidgetItem, QTreeWidget, QTreeWidgetItem,
QWidget)
class Ui_dv_MainWindow(object):
def setupUi(self, dv_MainWindow):
if not dv_MainWindow.objectName():
dv_MainWindow.setObjectName(u"dv_MainWindow")
dv_MainWindow.resize(1280, 760)
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(dv_MainWindow.sizePolicy().hasHeightForWidth())
dv_MainWindow.setSizePolicy(sizePolicy)
self.actionopendir = QAction(dv_MainWindow)
self.actionopendir.setObjectName(u"actionopendir")
self.action_config = QAction(dv_MainWindow)
self.action_config.setObjectName(u"action_config")
self.centralwidget = QWidget(dv_MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.groupBox = QGroupBox(self.centralwidget)
self.groupBox.setObjectName(u"groupBox")
self.groupBox.setGeometry(QRect(9, 9, 431, 701))
self.gridLayout_2 = QGridLayout(self.groupBox)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.searchEdit = QLineEdit(self.groupBox)
self.searchEdit.setObjectName(u"searchEdit")
self.gridLayout_2.addWidget(self.searchEdit, 0, 0, 1, 1)
self.pushButton = QPushButton(self.groupBox)
self.pushButton.setObjectName(u"pushButton")
self.gridLayout_2.addWidget(self.pushButton, 0, 1, 1, 1)
self.treeWidget = QTreeWidget(self.groupBox)
self.treeWidget.setObjectName(u"treeWidget")
self.treeWidget.setFrameShape(QFrame.WinPanel)
self.treeWidget.setLineWidth(0)
self.treeWidget.setSelectionMode(QAbstractItemView.SingleSelection)
self.treeWidget.setSelectionBehavior(QAbstractItemView.SelectItems)
self.gridLayout_2.addWidget(self.treeWidget, 1, 0, 1, 2)
self.groupBox_2 = QGroupBox(self.groupBox)
self.groupBox_2.setObjectName(u"groupBox_2")
self.gridLayout = QGridLayout(self.groupBox_2)
self.gridLayout.setObjectName(u"gridLayout")
self.lineEdit_StartCol = QLineEdit(self.groupBox_2)
self.lineEdit_StartCol.setObjectName(u"lineEdit_StartCol")
self.gridLayout.addWidget(self.lineEdit_StartCol, 1, 1, 1, 1)
self.label = QLabel(self.groupBox_2)
self.label.setObjectName(u"label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.label_5 = QLabel(self.groupBox_2)
self.label_5.setObjectName(u"label_5")
self.gridLayout.addWidget(self.label_5, 1, 2, 1, 1)
self.label_4 = QLabel(self.groupBox_2)
self.label_4.setObjectName(u"label_4")
self.gridLayout.addWidget(self.label_4, 0, 2, 1, 1)
self.lineEdit_EndCol = QLineEdit(self.groupBox_2)
self.lineEdit_EndCol.setObjectName(u"lineEdit_EndCol")
self.gridLayout.addWidget(self.lineEdit_EndCol, 1, 3, 1, 1)
self.pushButton_load_dv = QPushButton(self.groupBox_2)
self.pushButton_load_dv.setObjectName(u"pushButton_load_dv")
self.gridLayout.addWidget(self.pushButton_load_dv, 4, 2, 1, 2)
self.pushButton_save_config = QPushButton(self.groupBox_2)
self.pushButton_save_config.setObjectName(u"pushButton_save_config")
self.gridLayout.addWidget(self.pushButton_save_config, 3, 0, 1, 4)
self.lineEdit_StartRow = QLineEdit(self.groupBox_2)
self.lineEdit_StartRow.setObjectName(u"lineEdit_StartRow")
self.gridLayout.addWidget(self.lineEdit_StartRow, 0, 1, 1, 1)
self.lineEdit_dv_save_dir = QLineEdit(self.groupBox_2)
self.lineEdit_dv_save_dir.setObjectName(u"lineEdit_dv_save_dir")
self.gridLayout.addWidget(self.lineEdit_dv_save_dir, 2, 0, 1, 4)
self.label_2 = QLabel(self.groupBox_2)
self.label_2.setObjectName(u"label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.lineEdit_EndRow = QLineEdit(self.groupBox_2)
self.lineEdit_EndRow.setObjectName(u"lineEdit_EndRow")
self.gridLayout.addWidget(self.lineEdit_EndRow, 0, 3, 1, 1)
self.pushButton_save_dv = QPushButton(self.groupBox_2)
self.pushButton_save_dv.setObjectName(u"pushButton_save_dv")
self.gridLayout.addWidget(self.pushButton_save_dv, 4, 0, 1, 2)
self.gridLayout_2.addWidget(self.groupBox_2, 2, 0, 1, 2)
self.tableView_view = QTableView(self.centralwidget)
self.tableView_view.setObjectName(u"tableView_view")
self.tableView_view.setGeometry(QRect(448, 9, 821, 331))
sizePolicy.setHeightForWidth(self.tableView_view.sizePolicy().hasHeightForWidth())
self.tableView_view.setSizePolicy(sizePolicy)
self.tableView_view.setFrameShape(QFrame.Box)
self.tableView_view.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.tableView_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.tableView_view.setSelectionMode(QAbstractItemView.SingleSelection)
self.groupBox_3 = QGroupBox(self.centralwidget)
self.groupBox_3.setObjectName(u"groupBox_3")
self.groupBox_3.setGeometry(QRect(450, 670, 821, 41))
self.horizontalLayout = QHBoxLayout(self.groupBox_3)
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.pushButton_start = QPushButton(self.groupBox_3)
self.pushButton_start.setObjectName(u"pushButton_start")
self.horizontalLayout.addWidget(self.pushButton_start)
self.groupBox_4 = QGroupBox(self.centralwidget)
self.groupBox_4.setObjectName(u"groupBox_4")
self.groupBox_4.setGeometry(QRect(450, 350, 821, 311))
self.tableWidget_dv_config = QTableWidget(self.groupBox_4)
self.tableWidget_dv_config.setObjectName(u"tableWidget_dv_config")
self.tableWidget_dv_config.setGeometry(QRect(10, 20, 797, 281))
self.tableWidget_dv_config.setFrameShape(QFrame.Box)
dv_MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(dv_MainWindow)
self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 1280, 22))
self.menu = QMenu(self.menubar)
self.menu.setObjectName(u"menu")
self.menu_2 = QMenu(self.menubar)
self.menu_2.setObjectName(u"menu_2")
dv_MainWindow.setMenuBar(self.menubar)
self.statusbar = QStatusBar(dv_MainWindow)
self.statusbar.setObjectName(u"statusbar")
dv_MainWindow.setStatusBar(self.statusbar)
self.menubar.addAction(self.menu.menuAction())
self.menubar.addAction(self.menu_2.menuAction())
self.menu.addAction(self.actionopendir)
self.menu_2.addAction(self.action_config)
self.retranslateUi(dv_MainWindow)
QMetaObject.connectSlotsByName(dv_MainWindow)
# setupUi
def retranslateUi(self, dv_MainWindow):
dv_MainWindow.setWindowTitle(QCoreApplication.translate("dv_MainWindow", u"\u8868\u683c\u6570\u636e\u6821\u9a8c\u5de5\u5177", None))
self.actionopendir.setText(QCoreApplication.translate("dv_MainWindow", u"\u9009\u62e9\u6587\u4ef6\u5939", None))
#if QT_CONFIG(tooltip)
self.actionopendir.setToolTip(QCoreApplication.translate("dv_MainWindow", u"<html><head/><body><p>\u9009\u62e9\u5f85\u8fdb\u884c\u6570\u636e\u6821\u9a8c\u6587\u4ef6\u6240\u5728\u6587\u4ef6\u5939</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
self.action_config.setText(QCoreApplication.translate("dv_MainWindow", u"\u6821\u9a8c\u9879\u76ee\u914d\u7f6e", None))
self.groupBox.setTitle("")
self.pushButton.setText(QCoreApplication.translate("dv_MainWindow", u"\u6536\u7d22", None))
___qtreewidgetitem = self.treeWidget.headerItem()
___qtreewidgetitem.setText(0, QCoreApplication.translate("dv_MainWindow", u"\u8bf7\u9009\u62e9\u6587\u4ef6\u5939", None));
self.groupBox_2.setTitle(QCoreApplication.translate("dv_MainWindow", u"\u57fa\u7840\u914d\u7f6e", None))
self.lineEdit_StartCol.setText(QCoreApplication.translate("dv_MainWindow", u"0", None))
self.label.setText(QCoreApplication.translate("dv_MainWindow", u"\u6570\u636e\u8d77\u59cb\u884c", None))
self.label_5.setText(QCoreApplication.translate("dv_MainWindow", u"\u6570\u636e\u7ed3\u5c3e\u5217", None))
self.label_4.setText(QCoreApplication.translate("dv_MainWindow", u"\u6570\u636e\u7ed3\u5c3e\u884c", None))
self.lineEdit_EndCol.setText(QCoreApplication.translate("dv_MainWindow", u"0", None))
self.pushButton_load_dv.setText(QCoreApplication.translate("dv_MainWindow", u"\u52a0\u8f7d\u6821\u9a8c\u8bbe\u7f6e", None))
self.pushButton_save_config.setText(QCoreApplication.translate("dv_MainWindow", u"\u6821\u9a8c\u62a5\u544a\u5b58\u50a8\u5730\u5740\u9009\u62e9", None))
self.lineEdit_StartRow.setText(QCoreApplication.translate("dv_MainWindow", u"0", None))
self.lineEdit_dv_save_dir.setText(QCoreApplication.translate("dv_MainWindow", u"./config_output", None))
self.label_2.setText(QCoreApplication.translate("dv_MainWindow", u"\u6570\u636e\u8d77\u59cb\u5217", None))
self.lineEdit_EndRow.setText(QCoreApplication.translate("dv_MainWindow", u"0", None))
self.pushButton_save_dv.setText(QCoreApplication.translate("dv_MainWindow", u"\u4fdd\u5b58\u6821\u9a8c\u8bbe\u7f6e", None))
self.groupBox_3.setTitle("")
self.pushButton_start.setText(QCoreApplication.translate("dv_MainWindow", u"\u5f00\u59cb\u6821\u9a8c", None))
self.groupBox_4.setTitle(QCoreApplication.translate("dv_MainWindow", u"\u6570\u636e\u6821\u9a8c\u914d\u7f6e", None))
self.menu.setTitle(QCoreApplication.translate("dv_MainWindow", u"\u6253\u5f00", None))
self.menu_2.setTitle(QCoreApplication.translate("dv_MainWindow", u"\u8bbe\u7f6e", None))
# retranslateUi
TreeWidget+CheckBox实现文件列表
TreeWidget+CheckBox实现文件列表+复选框如何实现?由于TreeWidget实际上是由多个TreeWidgetItem构成,所以新增复选框,应该考虑在TreeWidgetItem上进行设置,此处设置较为简单,因为TreeWidgetItem本身自带setCheckState设置,所以我们只需要对其进行设置后,便可以在TreeWidget上显示复选框了,这个功能,我们在打开按钮功能中实现。具体代码如下:
# 打开文件夹
def open_dirs(self):
self._open_dirs = QFileDialog.getExistingDirectory(None, '选取文件夹', '')
self._open_dirs_list.append(self._open_dirs)
# self._model = QFileSystemModel()
# 清空treeWidget的数据
self.treeWidget.clear()
# QTreeWidgets列数和列名设置
self.treeWidget.setColumnCount(1)
self.treeWidget.setHeaderLabels(['文件名'])
# root节点设置
self._root = QTreeWidgetItem(self.treeWidget)
self._root.setText(0, self._open_dirs)
self._root.setCheckState(0, Qt.Unchecked)
# 获取文件列表
self._file_path_list = self.get_file_path(self._open_dirs)
# 遍历文件名,添加到列表之中
self._item_list = []
for file in self._file_path_list:
file_name = os.path.split(file)[1]
child = QTreeWidgetItem(self._root)
child.setText(0, file_name)
child.setCheckState(0, Qt.Unchecked)
self._item_list.append(child)
TableWidget+CheckBox实现动态数据校验配置表
TableWidget+CheckBox如何实现动态数据校验配置表呢?思路和上文结束类似,TableWidget其每个单元格也是由QTableWidgetItem构成的,而QTableWidgetItem控件是可以通过setCheckState设置选中状态的。该功能在构造数据校验配置表函数中实现,具体代码如下:
# 构造数据校验配置表
def construct_config_dv(self):
# 存储数据校验配置表
self._df_dv = pd.DataFrame(columns=config.df_dv_col)
columns = self.df.columns.tolist()
first_row = self.df.iloc[0]
# 遍历构造校验配置表
for i, col in enumerate (columns):
self._df_dv.loc[i, '列编号'] = columns[i]
self._df_dv.loc[i, '第一列内容'] = first_row[i]
self.tableWidget_dv_config.clear()
# 获取表格行数与列数
rows = self._df_dv.shape[0]
cols = self._df_dv.shape[1]
# 给tableWidget设置行表头
self.tableWidget_dv_config.setColumnCount(cols)
self.tableWidget_dv_config.setRowCount(rows)
self.tableWidget_dv_config.setHorizontalHeaderLabels(config.df_dv_col)
# 遍历数据校验配置表,加载到tableWidget中
for i in range(rows):
rows_values = self._df_dv.iloc[[i]]
rows_values_array = np.array(rows_values)
rows_values_list = rows_values_array.tolist()[0]
for j in range(cols):
items_list = str(rows_values_list[j])
if (items_list == 'nan') and (j != 1):
newItem = QTableWidgetItem('是否校验')
else:
newItem = QTableWidgetItem(items_list)
if j not in [0, 1]:
newItem.setCheckState(Qt.Unchecked)
newItem.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
self.tableWidget_dv_config.setItem(i, j, newItem)
工具完整代码下载
在本案例中,还实现了诸多其他功能,想要深入学习的同学可以下载源码进行研究,源码下载地址如下: