检查Qt项目的 .ui 文件引用图标资源是否存在的脚本程序
一个项目中遇到一个问题,项目更新升级过程中,有一些模块比较长时间没有维护了,其中.ui
文件引用的.qrc
中的图标资源已经不存在了,就会导致程序运行的过程中无法显示图标。因为一个个排查太费时间,也容易漏,所有写了一个 Python 脚本来检查这个是不是有问题,将有问题的图标引用进行输出。
检查流程如下:
graph LR
A([开始])-->B[输入要检查的目录]
B-->C[扫描目录]
C-->D{ui文件?}
subgraph check
F[0.解析UI文件]-->M[1.迭代iconset节点]
M-->G[2.读取resource属性]
G-->I[3.解析指向的qrc文件]
M-->H[4.读取normaloff标签节点]
I-->J{{5.normaloff<br>指向的资源文件<br>在qrc文件中?}}
H-->J
J--是<7.检查下一个>-->M
J--否-->N[6.打印不存在的引用]
M--8.没有iconset节点了-->L(9.结束)
end
D--是-->F
L-->D
D--否<下一个>-->D
代码实现很简单,只是检查了引用的图标是否在qrc
文件中,没有进一步检查图标文件是否存在,这是不完善的地方。因为Qt的代码中也可以通过setIcon(const QIcon& icon)
接口来设置图标,所以这里也检查不到。要解决这个问题,需要检查所有代码文件。
代码如下:
import os
import xml.etree.ElementTree as ET
def get_iconset_path(ui_file, resource):
ui_dir = os.path.dirname(ui_file)
qrc_file = os.path.join(ui_dir, resource)
return os.path.normpath(qrc_file)
def parse_qrc(qrc_file):
# 使用 cache 缓存已经解析过的文件
if hasattr(parse_qrc, 'cache') == False:
setattr(parse_qrc, 'cache', dict())
if qrc_file in parse_qrc.cache:
return parse_qrc.cache[qrc_file]
# 解析 qrc 文件
try:
tree = ET.parse(qrc_file)
except IOError as err:
print('\033[95m解析出错:{}\033[0m'.format(err))
return []
except BaseException as err:
print('\033[95m解析异常:{}\033[0m'.format(err))
return []
root = tree.getroot()
result = []
for qresource in root.iter('qresource'):
# 获取 prefix 属性
prefix = qresource.get('prefix', '/')
for file in qresource.iter('file'):
rc_file = os.path.join(prefix, file.text).replace('\\', '/')
# print(rc_file)
result.append(':'+rc_file)
# 存入缓存
parse_qrc.cache[qrc_file] = result
return result
def check_iconset(dir, ui_file):
""" 对 ui 文件进行检查,输出图标不存在的部分
:param dir: 遍历的目录,以便只输出文件名时候截取前面部分
:param ui_file: 要检查的 ui 文件
"""
print('check file:', os.path.relpath(ui_file, dir))
tree = ET.parse(ui_file)
root = tree.getroot()
# 遍历所有iconset标签节点
for iconset in root.iter('iconset'):
# 获取resource属性并打印
resource = iconset.get('resource')
if resource is None:
# print(iconset.text)
continue
qrc_file = get_iconset_path(ui_file, resource)
# print('Resource:', qrc_file)
result = parse_qrc(qrc_file)
# print(result)
# 判断节点下是否有normaloff标签节点
normaloff = iconset.find('normaloff')
if normaloff is not None:
# 输出normaloff标签节点的内容
# print('Normaloff:', normaloff.text)
# 判断是否存在,如果不存在就输出
if normaloff.text not in result:
print('\033[31m\tnot found:{}\033[0m'.format(normaloff.text))
def walk_dir(directory):
""" 对文件夹进行遍历处理
"""
for root, _, files in os.walk(directory):
for file in files:
if file.endswith(".ui"):
ui_file = os.path.join(root, file)
check_iconset(directory, ui_file)
# 指定目录作为参数调用方法
directory = input("请输入目录路径:")
walk_dir(directory)