Portal: software de gráficos PyQt (aprendizaje basado en proyectos)
análisis de la demanda
Software de cuantificación para pruebas de detección del desarrollo en un hospital
ingresar
Información básica del paciente
Formulario de prueba de detección (formulario de plantilla ya disponible)
producción
Varios puntajes brutos para deportes, adaptación social e inteligencia;
varios puntajes calculados para
las sugerencias correspondientes de IQ EQ
Formato de informe: fijo
Guardar en local (PDF/Word), considere reemplazar la plantilla
diseño del marco
Basado en Python 3.6 + QT
Capa de interfaz - QtDesigner
Estilo general
Debido a que la tabla de cuantificación tiene tres categorías principales y hay muchos indicadores de parámetros en cada parte, se adopta un diseño apilado.La
interfaz principal se compone de dos marcos.
cuadro de texto de varias líneas
https://blog.csdn.net/qq_28077617/article/details/121876632
Subpágina
información
Cuando hay varios cuadros de entrada (edición de línea), puede considerar la introducción de la tecla de método abreviado Tabulador Para configuraciones específicas, consulte este artículo;
fecha de anidamiento
Desplegable del calendario para seleccionar la hora
https://blog.csdn.net/weixin_39626452/article/details/86700178?spm=1001.2014.3001.5506
interfaz de usuario
self.dateEdit = QtWidgets.QDateEdit(self.gridLayoutWidget)
self.dateEdit.setObjectName("dateEdit")
# 设置日期显示格式
self.dateEdit.setDisplayFormat('yyyy-MM-dd')
# 设置允许日历控件弹出
self.dateEdit.setCalendarPopup(True)
# 当日期改变时触发槽函数
self.dateEdit.dateChanged.connect(self.onTimeChanged)
Código comercial
def onTimeChanged(self,time):
birthtime = time
print(birthtime)
Obtener la hora actual y mostrarla
# 获取当前时间
testTime = datetime.datetime.now().strftime('%Y-%m-%d')
# 回传子页面 setText设置输入框显示值
self.lineEdit_TestTime.setText(testTime)
print(testTime)
Establecer rango de fechas para la selección del calendario
# 设置日期范围
self.dateEdit.setMinimumDate(QDate.currentDate().addDays(-365*10))
self.dateEdit.setMaximumDate(QDate.currentDate().addDays(0))
diseño de pila
Widget apilado, y luego consulte el artículo anterior, las siguientes son las principales precauciones;
Señales y tragamonedas
# 建立堆叠布局信号与槽连接
self.pushButton_Sports.clicked.connect(self.frameController)
self.pushButton_Social.clicked.connect(self.frameController)
self.pushButton_Iq.clicked.connect(self.frameController)
Si el código para la creación de la señal y la ranura se coloca antes del código de creación del botón, se producirá
AttributeError: 'AppMainWindow' object has no attribute 'pushButton_Sports'
un error.
Tamaño de pantalla adaptable a la ventana
Con respecto al diseño de la cuadrícula, las líneas de la cuadrícula no se generan automáticamente
qt-designer agrega imágenes personalizadas
Consulte este artículo
para convertir,
pyrcc5 -o re_rc.py, su propio nombre de archivo de recursos.qrc
Capa empresarial
Atravesar para obtener el estado de la casilla de verificación y convertirlo en cálculo de puntuación
Reproducción de escena: Como se muestra arriba, tengo muchas casillas de verificación, y quiero obtener el estado de selección de las casillas de verificación a su vez; cabe señalar que cada casilla de verificación tiene un nombre único , y su formato generalmente es checkBox_XXX ( xxx es el número). Este método de nomenclatura proporciona comodidad para nuestro recorrido;
consulte esta respuesta , el bucle for tradicional + cadenas de objeto de empalme no es factible, porque obtiene una cadena en lugar de un nombre de objeto; **Usamos el getattr ()** método para generar el nombre del objeto checkBOX
# 这里的self是页面父类-主窗口
try:
# 针对运动表,判断其最后一个得分项
for i in range(1, 31):
# 遍历checkBox对象
m = getattr(self, "checkBox_%d" % i)
if m.isChecked():
# print("checked" + m)
print("num" + str(i) + ": " + str(m.isChecked()))
sports_pass = i
print("the final score is:" + str(sports_pass))
except Exception as e:
print(e)
Lo que quiero explicar aquí es que si desea print(m)
escribir el nombre del objeto, se informará un error. El mensaje de error probablemente debería ser:
debe ser str, no QCheckBox (esta es también la razón por la cual se detecta la excepción ).
La m aquí puede considerarse como una referencia de objeto, la función de impresión solo puede imprimir cadenas, por lo que no hay nada de malo en informar un error aquí. Creo que esta es también la razón por la que algunas personas informarán un error en la respuesta anterior ;
si insiste en imprimir m, puede usar str(m), entonces encontrará que es un objeto, ¿debería imprimirse la dirección?
docx generar plantilla de informe
dict (zip)
Se utiliza principalmente para generar un diccionario de palabras clave para comparar y reemplazar
biblioteca de tres partes py-docx
Guarde el archivo en la ubicación especificada (aparecerá el cuadro de diálogo Guardar archivo)
pyqt5 ya proporciona un cuadro de diálogo de recursos de archivo, a saber, getSaveFileName;
filepath, type = QFileDialog.getSaveFileName(self, '报告保存', '/'+ '%s_报告单.docx' % model, 'docx(*.docx)')
# '报告保存' 是对话框的标题,中间那一长串是保存的路径,后面是默认保存位置
# 这里我是根据患者测试时间和姓名 默认给出了文件名字,使用%s 占位符 将字符串model和 路径以及后缀名拼接
doc_t.save(filepath)
# 再使用doc_t.save将文件保存至指定filepath
Genere un informe y guarde el código completo en la ruta especificada
Precauciones
Después de abrir el cuadro de diálogo Guardar, si se cancela el guardado, el programa devolverá una ruta vacía ('') y se informará un error en este momento, por lo que es necesario determinar si la ruta del programa está vacía.
import datetime
import docx
from PyQt5.QtWidgets import QFileDialog
def createReport(self,list):
try:
# 需制作缴费通知单数据
report_data = list
# print(list)
# 模板内设置的标志:
tags_1 = ['name','id','gender','birthday','preweek','testdate','months','sports',
'social','intel','min','mi','dqn','dq','advice']
# print(report_data)
# 生成字典类型的数据集
notice_dict = dict(zip(tags_1, report_data))
# print(notice_dict)
doc_t, runs_t = get_runs('报告模板.docx')
# 遍历模板run对象 和 notice_dict key 匹配
# 匹配成功则替换 run 内容
for run_t in runs_t:
if run_t.text in notice_dict.keys():
run_t.text = str(notice_dict[run_t.text])
#生成格式化文件名
model = datetime.datetime.now().strftime('%Y%m%d') + '_'+ list[0]
# 文件保存路径
save_doc(self,doc_t,model)
except Exception as e:
print(e)
# 定义获取 word 模板正文段落、表格 run 对象函数
def get_runs(path):
doc = docx.Document(path)
runs_g = []
# 获取段落 run 对象
# print(doc.paragraphs)
for par_g in doc.paragraphs:
for run_g in par_g.runs:
runs_g.append(run_g)
# print(run_g.text)
# # 获取表格 run 对象
# table_g = doc.tables[0]
# for cell_g in table_g._cells:
# for cell_par_g in cell_g.paragraphs:
# for cell_run_g in cell_par_g.runs:
# runs_g.append(cell_run_g)
# print(cell_run_g.text)
return doc, runs_g
# 文件保存路径
def save_doc(self,doc_t,model):
filepath, type = QFileDialog.getSaveFileName(self, '文件保存', '/'+ '%s_报告单.docx' % model, 'docx(*.docx)')
print(filepath)
doc_t.save(filepath)
#
Haga clic en la barra de menú para abrir el documento de ayuda
def trigger_helpDoc(self):
webbrowser.open('Help.pdf', new=1)
Abrir ruta guardada recientemente
Use software externo de word/WPS para obtener una vista previa de los documentos generados
Busqué mucho en Internet, la mayoría de los cuales llaman a la palabra interfaz y luego muestran el documento en el marco Pyqt; mi requisito aquí es usar python para llamar a un software externo para abrir el documento en el software correspondiente; use la biblioteca
pywin32compip install -i https://pypi.tuna.tsinghua.edu.cn/simple pypiwin32
from win32com.client import Dispatch
# 这里定义了打开的程序接口
app = Dispatch('Word.Application')
# 这里是打开文件的路径
app.Documents.Open(self.pathtemp)
# 设置word文件可见
app.Visible = True
time.sleep(0.5)
Aquí hay un problema, es decir, mi informe solo se puede obtener una vista previa después de generarlo y guardarlo. Quiero obtener una vista previa del informe antes de guardarlo, pero falla.
# 具体过程参见前面的 docx文件生成并保存
doc_t, runs_t = get_runs('报告模板.docx')
app.Documents.Open(doc_t)
empaquetado de software
Acerca del archivo de configuración de especificaciones
UPX no está disponible
Convierta su archivo '.png' a '.ico' y vuelva a intentarlo.
exe.notaxejecutable
generar no ejecutable
No se puede abrir el archivo de icono \image\logo.ico
1. Se entiende que el tamaño del icono es incorrecto 16*16
2. La ruta del archivo ico es image\logo.ico en lugar de \image\logo.ico
el icono desaparece
Debe copiar el archivo del icono en el archivo de ejecución exe,
El archivo del paquete pyinstaller es demasiado grande
usar pipenv
Este artículo es la sugerencia de yyds de usar el archivo de configuración pyinstaller XXX.spec para generar el programa
en el entorno pipenv.Mi software se ha reducido de los 200M originales a 40M;
Error al instalar PyQt5
Instale directamente pip install PyQt5-sip== 12.9.1
y luego instale PyQt5 con éxito
Empaquetado secundario de archivos de recursos y exe
Se puede ver que los archivos de recursos antes del empaquetamiento están todos dispersos debajo de la carpeta, que se ve muy baja.Después
del segundo empaquetamiento con Winrar, los archivos se vuelven un todo:
Use Winrar
para consultar el artículo 2
, pero el icono no se puede cambiar después del empaquetado Más tarde, descubrí que era un problema con mi versión de Winrar y que no había ninguna opción para cambiar el icono.
Resumen de preguntas Q
Problema de Python: el objeto 'Nonetype' no es iterable
Aquí, la función generalmente se define pero no se proporciona el valor de retorno
Error al tokenizar datos. Error de C: se esperaban 1 campos en la línea 3, vio 2
Esto no funciona
Más tarde descubrí que esa fue la razón por la que cambié directamente el documento .xlsx a .csv
ModuleNotFoundError: ningún módulo llamado 'excepciones'
Acerca de atravesar párrafos con pydocx, pero se omiten algunas partes
El campo de consejos de la sugerencia de capacitación en la figura a continuación debe reemplazarse lógicamente
def get_runs(path):
doc = docx.Document(path)
runs_g = []
# 获取段落 run 对象
print(doc.paragraphs)
for par_g in doc.paragraphs:
for run_g in par_g.runs:
runs_g.append(run_g)
print(run_g.text)
# 获取表格 run 对象
# table_g = doc.tables[0]
# for cell_g in table_g._cells:
# for cell_par_g in cell_g.paragraphs:
# for cell_run_g in cell_par_g.runs:
# runs_g.append(cell_run_g)
return doc, runs_g
Para encontrar el problema, imprima el proceso transversal. Tenga en cuenta que necesita usar el método run_g.text para imprimir el contenido específico, de lo contrario, simplemente imprima la dirección del objeto; después de imprimir, encontrará que lo
último lo que obtienes es un consejo, es decir, el consejo está separado, entonces en el reemplazo final, no encontré las palabras clave correspondientes,
la solución es escribir el consejo y las palabras clave en la plantilla y el programa nuevamente, no sé porque hay este problema? ? ? ¿metafísica? ? ?