一、Web 网页中的级联选择器
在各类网页中,我们经常可以看到级联选择器。
比如在购物平台填写收获地址的时候,进行省市县的选择;
又比如在一些商品分类中的商品大类、商品子类的选择:
可以说,对于一个正常的Web框架而言,级联选择器都是必不可少的组件。
二、级联选择器原理
其实普通的级联选择器其构成并不复杂。
无非是选择一级的时候,唤起二级的渲染和显示,选择二级的时候,唤起三级的渲染和显示;
至于各级是用列表还是用下拉框,都是其次的。
下面,我们就使用 PyQt5 构建一个省市县的级联选择器。
最终的效果如下所示:
三、构建一个桌面应用的级联选择器
准备数据
要实现省市县的级联选择,省市县的数据必不可少,在这里,我们使用的是一个 JSON 格式嵌套的省市县数据,如下图所示:
数据来源于:https://www.cnblogs.com/bihuijia/p/15077207.html
大家可以自行复制。
最终以data.json
文件的形式提供给代码读取。
代码开发
首先,引入所需的模块:
代码语言:javascript复制from PyQt5 import QtWidgets,QtCore
from loguru import logger
import sys
import json
接着,编写其基础界面。
通过继承QtWidgets.QWidget
,定义一个Widget
:
class Widget(QtWidgets.QWidget):
def __init__(self):
super(Widget, self).__init__()
self.setWindowTitle("PyQt5 省市县级联选择器 - 州的先生")
self.init_data() # 初始化数据
self.init_ui() # 初始化UI
在Widget
初始化的时候,我们调用了两个方法,分别用于初始化数据和初始化UI界面。
初始化数据,通过读取data.json
文件进行 json 解析并赋值:
# 初始化数据
def init_data(self):
# 读取json数据
with open("./data.json", 'r', encoding='utf-8') as data:
self.data_json = json.loads(data.read(), encoding='utf-8')
print(self.data_json)
我们的级联选择器通过三个下拉选择器QComboBox()
来实现,然后三个下拉选择器用一个网格布局QGridLayout()
进行水平排列。
# 初始化UI
def init_ui(self):
# 省选择器
self.province = QtWidgets.QComboBox()
self.province.addItem("--请选择省")
self.province.currentTextChanged.connect(self.slot_province_click)
for data in self.data_json:
self.province.addItem(data['Name'])
# 市选择器
self.city = QtWidgets.QComboBox()
self.city.addItem("--请选择市")
self.city.currentTextChanged.connect(self.slot_city_click)
# 县选择器
self.county = QtWidgets.QComboBox()
self.county.addItem("--请选择县")
self.layout = QtWidgets.QGridLayout()
self.setLayout(self.layout)
self.layout.addWidget(self.province, 0, 0, 1, 1)
self.layout.addWidget(self.city, 0, 1, 1, 1)
self.layout.addWidget(self.county, 0, 2, 1, 1)
在这里,我们通过QComboBox()
的currentTextChanged
信号来捕获下拉框某个选项被选择,分别连接到了两个方法:
# 省选择器点击响应
def slot_province_click(self):
try:
current_province = self.province.currentText()
if current_province.startswith('--') is False:
for data in self.data_json:
if data['Name'] == current_province:
self.city.clear()
self.current_city_data = data['Cities']
for c in data['Cities']:
self.city.addItem(c['Name'])
else:
self.city.clear()
self.county.clear()
except:
logger.exception("加载市异常")
# 市选择器点击响应
def slot_city_click(self):
try:
current_city = self.city.currentText()
if current_city.startswith('--') is False:
for data in self.current_city_data:
if data['Name'] == current_city:
self.county.clear()
for c in data['Districts']:
self.county.addItem(c['Name'])
except:
logger.error("加载县区异常")
最后,完整代码如下所示:
代码语言:javascript复制# coding:utf-8
from PyQt5 import QtWidgets,QtCore
from loguru import logger
import sys
import json
class Widget(QtWidgets.QWidget):
def __init__(self):
super(Widget, self).__init__()
self.setWindowTitle("PyQt5 省市县级联选择器 - 州的先生")
self.init_data() # 初始化数据
self.init_ui() # 初始化UI
# 初始化数据
def init_data(self):
# 读取json数据
with open("./data.json", 'r', encoding='utf-8') as data:
self.data_json = json.loads(data.read(), encoding='utf-8')
print(self.data_json)
# 初始化UI
def init_ui(self):
# 省选择器
self.province = QtWidgets.QComboBox()
self.province.addItem("--请选择省")
self.province.currentTextChanged.connect(self.slot_province_click)
for data in self.data_json:
self.province.addItem(data['Name'])
# 市选择器
self.city = QtWidgets.QComboBox()
self.city.addItem("--请选择市")
self.city.currentTextChanged.connect(self.slot_city_click)
# 县选择器
self.county = QtWidgets.QComboBox()
self.county.addItem("--请选择县")
self.layout = QtWidgets.QGridLayout()
self.setLayout(self.layout)
self.layout.addWidget(self.province, 0, 0, 1, 1)
self.layout.addWidget(self.city, 0, 1, 1, 1)
self.layout.addWidget(self.county, 0, 2, 1, 1)
# 省选择器点击响应
def slot_province_click(self):
try:
current_province = self.province.currentText()
if current_province.startswith('--') is False:
for data in self.data_json:
if data['Name'] == current_province:
self.city.clear()
self.current_city_data = data['Cities']
for c in data['Cities']:
self.city.addItem(c['Name'])
else:
self.city.clear()
self.county.clear()
except:
logger.exception("加载市异常")
# 市选择器点击响应
def slot_city_click(self):
try:
current_city = self.city.currentText()
if current_city.startswith('--') is False:
for data in self.current_city_data:
if data['Name'] == current_city:
self.county.clear()
for c in data['Districts']:
self.county.addItem(c['Name'])
except:
logger.error("加载县区异常")
def main():
app = QtWidgets.QApplication(sys.argv)
gui = Widget()
gui.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()
四、最后
通过短短的不到100行代码,我们就在 PyQt5 上实现了一个完成的省市县级联选择器。如上述所说,级联的核心在于根据所选动态响应和渲染子级数据,至于用什么控件来实现,倒是次要的。
所以基于此,大家可以尝试使用别的控件来实现一下级联选择器,或者对这个级联选择器进行美化。