构建一个标注数据处理功能界面

将处理标注数据的功能脚本集成到一个简单的可视化界面。

目录

实现步骤

全部代码

界面展示


实现步骤

Step1:主窗口

包含一个功能选择按钮。

1
2
3
4
5
6
7
# ----------创建主窗口----------
self.setWindowTitle('数据处理平台')
self.resize(640, 480) # 窗口大小
# self.setGeometry(100, 100, 640, 480)

self.button_txt = QPushButton('功能选择', self)
self.button_txt.setGeometry(20, 20, 130, 30)

Step2:功能选择(多功能)

以下拉框的形式进行选择,通过点击选项触发对应功能窗口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ----------创建下拉菜单----------
# 创建下拉菜单
self.combobox_txt = QComboBox(self)
self.combobox_txt.addItems(['未选择', 'xml2txt', 'change xml label'])
# self.combobox_txt.hide() # 初始隐藏下拉菜单
# self.combobox_txt.setCurrentIndex(-1) # 设置初始索引为 -1, 必须在添加控件之前设置
self.combobox_txt.setGeometry(self.button_txt.x(), self.button_txt.y() + self.button_txt.height(), 130, 30)
self.combobox_txt.activated.connect(
lambda: self.switch_page(self.combobox_txt, self.stacked_widget)) # 绑定选择事件, activated会自动传输index,从0开始。


# ----------创建下拉菜单对应的切换界面----------
self.stacked_widget = QStackedWidget(self) # 创建叠加窗口
self.stacked_widget.setGeometry(50, 100, 600, 600) # 设置窗口位置

Step3:触发切换界面

activated槽函数switch_page,触发界面切换。

1
2
3
4
# -----下拉选项触发-----
def switch_page(self, combobox, stacked_widget):
index = combobox.currentIndex()
stacked_widget.setCurrentIndex(index)

Step4:不同功能界面

在对应界面添加文本框(QLabel类)、输入框控件(QLineEdit类)、按钮控件(QPushButton类),setPlaceholderText类表示在输入框中添加文字提示,提示输入参数格式示例。按钮控件点击触发功能函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# ----------切换界面示例----------
# page1 xml to txt
self.page1_xml = QWidget()

self.page1_label1_xml = QLabel('img_root:', self.page1_xml) # 在page1里面添加输入框控件
self.page1_label1_xml.setGeometry(25, 20, 100, 30)
self.page1_input_field1_xml = QLineEdit(self.page1_xml)
self.page1_input_field1_xml.setPlaceholderText("输入图片地址:./ImgFilePath")
self.page1_input_field1_xml.setGeometry(110, 25, 300, 20)

self.page1_label2_xml = QLabel('xml_root:', self.page1_xml)
self.page1_label2_xml.setGeometry(25, 50, 100, 30) # (x,y, h, w)
self.page1_input_field2_xml = QLineEdit(self.page1_xml)
self.page1_input_field2_xml.setPlaceholderText("输入xml地址:./XmlFilePath")
self.page1_input_field2_xml.setGeometry(110, 55, 300, 20)

self.page1_label3_xml = QLabel('classes:', self.page1_xml)
self.page1_label3_xml.setGeometry(25, 80, 100, 30)
self.page1_input_field3_xml = QLineEdit(self.page1_xml)
self.page1_input_field3_xml.setPlaceholderText("输入类别列表格式:[fg, a1], 字符也不用引号")
self.page1_input_field3_xml.setGeometry(110, 85, 300, 20)

self.page1_label4_xml = QLabel('save_txt_root:', self.page1_xml)
self.page1_label4_xml.setGeometry(10, 110, 120, 30) # (x,y, h, w)
self.page1_input_field4_xml = QLineEdit(self.page1_xml)
self.page1_input_field4_xml.setPlaceholderText("输入txt保存地址:./TxtFilePath")
self.page1_input_field4_xml.setGeometry(130, 115, 280, 20)

self.stacked_widget.addWidget(self.page1_xml)

Step5:参数接收

对输入框中的信息进行接收,获取数据为str类型。

1
2
3
4
5
6
def xml2txt_button_click(self):
img_root = self.page1_input_field1_xml.text() # 标注图片路径
xml_root = self.page1_input_field2_xml.text() # xml地址
input_classes = self.page1_input_field3_xml.text() # classes列表
classes = input_classes[1:-1].split(', ') # 获取为str类型数据,转为list
txt_root = self.page1_input_field4_xml.text() # txt保存地址

Step6:按钮触发函数

点击按钮触发槽函数,xml2txt_button_click替换为自己的功能函数。

1
2
3
4
# 该部分可添加到步骤3中
self.page1_submit_button_xml = QPushButton("运行", self.page1_xml)
self.page1_submit_button_xml.setGeometry(250, 200, 70, 30)
self.page1_submit_button_xml.clicked.connect(self.xml2txt_button_click) # 运行按钮调用函数

Step7:函数运行反馈

运行成功提示success,运行失败提示错误详情。

1
2
3
4
5
6
7
8
9
# -----异常处理,运行反馈-----
try:
# 功能函数xml2txt替换为自己的函数
xml2txt(xml_root, xml_name, txt_save_path, classes, img_root)
# 成功运行提示
QMessageBox.information(self, 'Success', 'Your program has run successfully!', QMessageBox.Ok)
except Exception as e:
# 捕获异常并显示错误消息
QMessageBox.critical(self, 'Error', f"An error occurred: {str(e)}")

Step8:主程序

1
2
3
4
5
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())

全部代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import os
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QLineEdit, QStackedWidget, \
QComboBox, QMessageBox
from utils.label_utils import xml2txt, change_xml_label


# 主界面
class MyWindow(QWidget):
def __init__(self):
super().__init__()

# ----------创建界面----------
self.setWindowTitle('数据处理平台')
self.resize(640, 480)
# self.setGeometry(100, 100, 640, 480)

self.button_txt = QPushButton('功能选择', self)
self.button_txt.setGeometry(20, 20, 130, 30)
self.button_txt.clicked.connect(self.show_combobox) # 传入自定义参数

# ----------创建下拉菜单----------
# 创建txt下拉菜单
self.combobox_txt = QComboBox(self)
self.combobox_txt.addItems(['未选择', 'xml2txt', 'change xml label'])
# self.combobox_txt.hide() # 初始隐藏下拉菜单
# self.combobox_txt.setCurrentIndex(-1) # 设置初始索引为 -1, 必须在添加控件之前设置
self.combobox_txt.setGeometry(self.button_txt.x(), self.button_txt.y() + self.button_txt.height(), 130, 30)
# self.combobox_txt.move(self.button_txt.x(), self.button_txt.y() + self.button_txt.height()) # 移动控件到下(x,y)位置
self.combobox_txt.activated.connect(
lambda: self.switch_page(self.combobox_txt, self.stacked_widget)) # 绑定选择事件, activated会自动传输index

# ----------创建下拉菜单对应的切换界面----------
# -----界面切换模块-----
self.stacked_widget = QStackedWidget(self) # 创建叠加窗口
self.stacked_widget.setGeometry(50, 100, 600, 600) # 设置窗口位置

# page0 默认空界面
self.page0_xml = QWidget()
self.stacked_widget.addWidget(self.page0_xml)

# -----创建处理界面-----
# page1 xml to txt
self.page1_xml = QWidget()

self.page1_label1_xml = QLabel('img_root:', self.page1_xml) # 在page1里面添加输入框控件
self.page1_label1_xml.setGeometry(25, 20, 100, 30)
self.page1_input_field1_xml = QLineEdit(self.page1_xml)
self.page1_input_field1_xml.setPlaceholderText("输入图片地址:./ImgFilePath")
self.page1_input_field1_xml.setGeometry(110, 25, 300, 20)

self.page1_label2_xml = QLabel('xml_root:', self.page1_xml)
self.page1_label2_xml.setGeometry(25, 50, 100, 30) # (x,y, h, w)
self.page1_input_field2_xml = QLineEdit(self.page1_xml)
self.page1_input_field2_xml.setPlaceholderText("输入xml地址:./XmlFilePath")
self.page1_input_field2_xml.setGeometry(110, 55, 300, 20)

self.page1_label3_xml = QLabel('classes:', self.page1_xml)
self.page1_label3_xml.setGeometry(25, 80, 100, 30)
self.page1_input_field3_xml = QLineEdit(self.page1_xml)
self.page1_input_field3_xml.setPlaceholderText("输入类别列表格式:[fg, a1], 字符也不用引号")
self.page1_input_field3_xml.setGeometry(110, 85, 300, 20)

self.page1_label4_xml = QLabel('save_txt_root:', self.page1_xml)
self.page1_label4_xml.setGeometry(10, 110, 120, 30) # (x,y, h, w)
self.page1_input_field4_xml = QLineEdit(self.page1_xml)
self.page1_input_field4_xml.setPlaceholderText("输入txt保存地址:./TxtFilePath")
self.page1_input_field4_xml.setGeometry(130, 115, 280, 20)

self.page1_submit_button_xml = QPushButton("运行", self.page1_xml)
self.page1_submit_button_xml.setGeometry(250, 200, 70, 30)
self.page1_submit_button_xml.clicked.connect(self.xml2txt_button_click) # 运行按钮调用函数

self.stacked_widget.addWidget(self.page1_xml)

# page2 change xml label
self.page2_xml = QWidget()

self.page2_label1_xml = QLabel('xml root:', self.page2_xml)
self.page2_label1_xml.setGeometry(25, 20, 100, 30) # 设置输入框1的位置和大小 (x,y, w, h)
self.page2_input_field1_xml = QLineEdit(self.page2_xml) # 在窗口里面添加输入框控件
self.page2_input_field1_xml.setPlaceholderText("输入xml存放地址:./XmlFilePath")
self.page2_input_field1_xml.setGeometry(110, 25, 300, 20)

self.page2_label2_xml = QLabel('ori cla:', self.page2_xml)
self.page2_label2_xml.setGeometry(25, 50, 100, 30) # 设置输入框1的位置和大小 (x,y, w, h)
self.page2_input_field2_xml = QLineEdit(self.page2_xml) # 在窗口里面添加输入框控件
self.page2_input_field2_xml.setPlaceholderText("输入需要修改的标签名:car or person...")
self.page2_input_field2_xml.setGeometry(110, 55, 300, 20)

self.page2_label3_xml = QLabel('mod cla:', self.page2_xml)
self.page2_label3_xml.setGeometry(25, 80, 100, 30) # 设置输入框1的位置和大小 (x,y, w, h)
self.page2_input_field3_xml = QLineEdit(self.page2_xml) # 在窗口里面添加输入框控件
self.page2_input_field3_xml.setPlaceholderText("输入修改后的标签名:car or person...")
self.page2_input_field3_xml.setGeometry(110, 85, 300, 20)

self.page2_label4_xml = QLabel('param:', self.page2_xml)
self.page2_label4_xml.setGeometry(25, 110, 100, 30) # 设置输入框1的位置和大小 (x,y, w, h)
self.page2_input_field4_xml = QLineEdit(self.page2_xml) # 在窗口里面添加输入框控件
self.page2_input_field4_xml.setPlaceholderText("是否执行不为ori都修改为mod参数:0(否) or 1(是)")
self.page2_input_field4_xml.setGeometry(110, 115, 330, 20)

self.page2_submit_button_xml = QPushButton("运行", self.page2_xml) # 在窗口里面添加按钮控件
self.page2_submit_button_xml.setGeometry(250, 200, 70, 30)
self.page2_submit_button_xml.clicked.connect(self.change_xml_label_button_click)

self.stacked_widget.addWidget(self.page2_xml)

# ----------方法----------
def show_combobox(self, custom_param):
if self.combobox_txt.isHidden():
self.combobox_txt.show()
else:
self.combobox_txt.hide()

# -----下拉选项触发-----
def switch_page(self, combobox, stacked_widget):
index = combobox.currentIndex()
stacked_widget.setCurrentIndex(index)

def xml2txt_button_click(self):
img_root = self.page1_input_field1_xml.text() # 标注图片路径
xml_root = self.page1_input_field2_xml.text() # xml地址
input_classes = self.page1_input_field3_xml.text() # classes列表
classes = input_classes[1:-1].split(', ') # 获取为str类型数据,转为list
txt_root = self.page1_input_field4_xml.text() # txt保存地址
try:
for xml_name in os.listdir(xml_root):
print(xml_name)
txt_save_path = os.path.join(txt_root, xml_name.replace('xml', 'txt'))
xml2txt(xml_root, xml_name, txt_save_path, classes, img_root)
# 成功运行提示
QMessageBox.information(self, 'Success', 'Your program has run successfully!', QMessageBox.Ok)
except Exception as e:
# 捕获异常并显示错误消息
QMessageBox.critical(self, 'Error', f"An error occurred: {str(e)}")
# self.page1_input_field1_xml.clear()
# self.page1_input_field2_xml.clear()
# self.page1_input_field3_xml.clear()
# self.page1_input_field4_xml.clear()

def change_xml_label_button_click(self):
xml_root = self.page2_input_field1_xml.text()
origin = self.page2_input_field2_xml.text()
modify = self.page2_input_field3_xml.text()
input_param = self.page2_input_field4_xml.text()
if input_param == '1':
reverse_param = True
else:
reverse_param = False
try:
change_xml_label(xml_root, origin, modify, reverse_param)
# 成功运行
QMessageBox.information(self, 'Success', 'Your program has run successfully!', QMessageBox.Ok)
except Exception as e:
# 捕获异常并显示错误消息
QMessageBox.critical(self, 'Error', f"An error occurred: {str(e)}")


if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())

界面展示:

下拉框可选择2个功能,存在2个切换界面,根据输入框文字提示输入参数格式,点击运行,运行成功返回成功提示,运行失败返回失败提示。

主界面

成功提示

错误提示

版本历史

  • 2024-02-25: 初版文档
  • 2025-01-06:完善文档结构