Python 之 Qt Designer工具安装配置及打包
工具相关安装配置
一、pyqt5、pyqt5-tool、paramiko、pyInstaller安装
直接在线安装:
pip3 install PyQt5
pip3 install PyQt5-tools
pip3 install paramiko
pip3 install pyinstaller
镜像安装:(比直接在线安装快)
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple PyQt5
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple PyQt5-tools
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple paramiko
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller
配置环境变量:(正常情况安装后自动配置,无需手动配置)
控制面板 – 环境变量:
QT_QPA_PLATFORM_PLUGIN_PATH
C:\Python36\Lib\site-packages\PyQt5\Qt\plugins
二、pyqt5、pyqt5-tool、paramiko、pyInstaller安装
安装好pyqt5和pyqt5-tool后,还需要对pycharm进行配置,添加扩展工具(External Tools)
打开File(文件) – Settings(设置) – Tools (工具)– External Tools(外部工具)添加如下几个扩展工具:
1.QT Designed
用途:设计UI界面
name:QT Designed
tool settings:
Program: C:\Python36\Lib\site-pcakages\pyqt5-tools\designer.exe
woreking directory :$FileDir$
2.PyUIC
用途:将qt designed设计的ui文件,转换成py文件
name:PyUIC
tool settings:
Program:C:\Python36\Scripts\pyuic5.exe
Arguments: $FileName$ -o $FileNameWithoutExtension$.py
working directory: $FileDir$
3.PyInstall
用途:打包py文件为exe可执行文件
name: PyInstall
tool settings:
Program:C:\Python36\Scripts\pyinstaller.exe
Arguments: -F -w $FileNameWithoutExtension$.py
working directory:$FileDir$
4.Pyrcc
用途:将ico图片放在qrc文件中,再将qrc文件转换成py文件,用于小工具的图标
qrc文件格式大致如下:
<RCC>
<qresource prefix="/">
<file>python.ico</file>
<file>1.jpg</file>
</qresource>
</RCC>
name: pyrcc
tool setting:
program: C:\Python36\Scripts\pyrcc5.exe
Arguments: $FileName$ -o $FileNameWithoutExtension$.py
working directory: $FileDir$
配置完后,进入External Tools检查确认。
三、Qt Designer工具主界面
工具->External Tools->Qt Designer
利用Qt Designer封装控件
在PyCharm创建项目:文件-新建项目-创建
打开Qt Designer:工具->External Tools->Qt Designer
创建模板:选择Widget模板->创建
从Widget Box工具箱中拖拽2个TextLabel、1个line Edit、1个Text Browser以及2个Push Button。拖完后如下:
双击可以修改控件名称,也可以在属性编辑器中修改text;对象名称(objectname)同样需要修改,为了方便后续操作。
对象名称:
控件名称:
点击:窗体预览。字体大小、控件位置都可以调整。
保存文件,countImgs.ui,进入PyCharm,将.ui文件转换成.py文件。
方法一:右键External Tools–PyUIC或者tools–External Tools–PyUIC
方法二:直接使用命令行转换成.py文件。调用格式为pyuic5 -o {输出文件名} {输入designer设计好的.ui后缀界面文件}。
pyuic5 -o countImgs.py countImgs.ui
转换后的.py文件内容如下:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'countImgs.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(337, 421)
self.label1 = QtWidgets.QLabel(Form)
self.label1.setGeometry(QtCore.QRect(40, 30, 54, 12))
self.label1.setObjectName("label1")
self.label2 = QtWidgets.QLabel(Form)
self.label2.setGeometry(QtCore.QRect(40, 90, 54, 12))
self.label2.setObjectName("label2")
self.lineEdit = QtWidgets.QLineEdit(Form)
self.lineEdit.setGeometry(QtCore.QRect(40, 50, 113, 20))
self.lineEdit.setObjectName("lineEdit")
self.textBrowser = QtWidgets.QTextBrowser(Form)
self.textBrowser.setGeometry(QtCore.QRect(40, 110, 256, 192))
self.textBrowser.setObjectName("textBrowser")
self.pushButton1 = QtWidgets.QPushButton(Form)
self.pushButton1.setGeometry(QtCore.QRect(40, 340, 75, 23))
self.pushButton1.setObjectName("pushButton1")
self.pushButton2 = QtWidgets.QPushButton(Form)
self.pushButton2.setGeometry(QtCore.QRect(220, 340, 75, 23))
self.pushButton2.setObjectName("pushButton2")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "统计不重复标签"))
self.label1.setText(_translate("Form", "路径:"))
self.label2.setText(_translate("Form", "结果:"))
self.pushButton1.setText(_translate("Form", "打印"))
self.pushButton2.setText(_translate("Form", "退出"))
界面与业务逻辑
这一步主要实现业务逻辑,也就是点击“打印”和“退出”按钮后程序要执行的操作。为了后续维护方便,采用界面与业务逻辑相分离来实现。也就是通过创建主程序调用界面文件方式实现。这有2个好处。第1就是实现逻辑清晰。第2就是后续如果界面或者逻辑需要变更,好维护。新建countImgs_main.py文件程序,调用countImgs.py文件。
import sys
# PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中
from PyQt5.QtWidgets import QApplication, QMainWindow
# 导入designer工具生成的login模块
from countImgs import Ui_Form
class MyMainForm(QMainWindow, Ui_Form):
def __init__(self, parent=None):
super(MyMainForm, self).__init__(parent)
self.setupUi(self)
if __name__ == "__main__":
# 固定的,PyQt5程序都需要QApplication对象。sys.argv是命令行参数列表,确保程序可以双击运行
app = QApplication(sys.argv)
# 初始化
myWin = MyMainForm()
# 将窗口控件显示在屏幕上
myWin.show()
# 程序运行,sys.exit方法确保程序完整退出。
sys.exit(app.exec_())
运行结果:
到这里,界面实现和业务主程序已经写好了。但是现在具体业务功能逻辑还未实现。需要对登录和退出的按钮点击执行相对应的操作。
添加信号和槽,实现业务逻辑
实现部分见代码注释。这里主要添加如下两行命令配置信号和槽的关系。信号和槽的创建和原理下文描述。这里可以参照添加即可。
登录按钮:self.login_Button.clicked.connect(self.display)
退出按钮:self.cancel_Button.clicked.connect(self.close)
首先将功能函数.py文件放入utils文件夹下,并且文件中的函数必须是封装好的:
运行结果:测试结果不在控件中显示。
解决方法:Print重定向到组件。
运行展示:
相关完整代码:
countImg_main.py
import sys
# PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中
from PyQt5.QtWidgets import QApplication, QMainWindow
# 导入designer工具生成的login模块
from countImgs import Ui_Form
from utils.ReoeatFrames import RepeatFrames
from PyQt5 import QtCore, QtGui
#第一段:print重定向到组件 重定向1
class EmittingStr(QtCore.QObject):
textWritten = QtCore.pyqtSignal(str) # 定义一个发送str的信号
def write(self, text):
self.textWritten.emit(str(text))
class MyMainForm(QMainWindow, Ui_Form):
def __init__(self, parent=None):
super(MyMainForm, self).__init__(parent)
self.setupUi(self)
# 第二段:print重定向到组件 重定向2
sys.stdout = EmittingStr(textWritten=self.outputWritten)
sys.stderr = EmittingStr(textWritten=self.outputWritten)
# 添加登录按钮信号和槽。注意display函数不加小括号()
self.pushButton1.clicked.connect(self.display)
# 添加退出按钮信号和槽。调用close函数
self.pushButton2.clicked.connect(self.close)
# 第三段:print重定向到组件 重定向3 用到的控件textBrowser
def outputWritten(self, text):
cursor = self.textBrowser.textCursor()
cursor.movePosition(QtGui.QTextCursor.End)
cursor.insertText(text)
self.textBrowser.setTextCursor(cursor)
self.textBrowser.ensureCursorVisible()
def display(self):
# 初始化textBrowser
self.textBrowser.clear()
# 输入路径参数
path1 = self.lineEdit.text()
path2 = path1 + '/'
#调用函数
RepeatFrames(path2)
if __name__ == "__main__":
# 固定的,PyQt5程序都需要QApplication对象。sys.argv是命令行参数列表,确保程序可以双击运行
app = QApplication(sys.argv)
# 初始化
myWin = MyMainForm()
# 将窗口控件显示在屏幕上
myWin.show()
# 程序运行,sys.exit方法确保程序完整退出。
sys.exit(app.exec_())
RepeatFrames.py
import os
from unicodedata import name
import xml.etree.ElementTree as ET
import glob
import pandas as pd
import numpy as np
def RepeatFrames(indir):
os.chdir(indir)
annotations = os.listdir('.')
annotations = glob.glob(str(annotations) + '*.xml')
bndbox_xml = [] #存放重复节点
for i, file in enumerate(annotations):
in_file = open(file, encoding='utf-8')
tree = ET.parse(in_file)
root = tree.getroot()
listobj = []
for obj in root.iter('object'):
name = obj.find('name').text
listname1 = {}
for bndbox in obj.iter('bndbox'):
listname1['name'] = name
for xmin in bndbox.iter('xmin'):
xmin=xmin.text
listname1['xmin'] = xmin
for ymin in bndbox.iter('ymin'):
ymin = ymin.text
listname1['ymin'] = ymin
for xmax in bndbox.iter('xmax'):
xmax = xmax.text
listname1['xmax'] = xmax
for ymax in bndbox.iter('ymax'):
ymax = ymax.text
listname1['ymax'] = ymax
listobj.append(listname1)
n = len(listobj)
for i in range(n):
for j in range(i + 1, n):
if listobj[i] == listobj[j]:
listobj[j]['name'] = '重复标签(不统计)'
listobj[i]['name'] = '重复标签(不统计)'
name_cf = listobj[i]['name']
bndbox_xml.append(name_cf)
count_dict = {}
for num in bndbox_xml:
if num in count_dict:
count_dict[num] += 1
else:
count_dict[num] = 1
key1 = 0
print("统计*不重复*标签数量:")
for key in count_dict.keys():
key1 = count_dict[key] + key1
print(key + ':' + str(count_dict[key])+'个 ', '\n')
print("标签总数量:", key1, '个 ')
#判断是否有重复标签
element = '重复标签(不统计)'
if element in bndbox_xml:
print("有效标签数:", key1 - count_dict['重复标签(不统计)'], '个 ')
else:
print("有效标签数:", key1 - 0, '个 ')
print("标签种类数:", len(count_dict)-1, '个 ')
其他说明:控件自适应。后续完善。
作者:qq_34157747