diff --git "a/IMPETOM-Cl\303\255nico/Interfaz.py" "b/IMPETOM-Cl\303\255nico/Interfaz.py" new file mode 100644 index 0000000000000000000000000000000000000000..15d7e0249d058019b4d116ba782754727b8c4ab1 --- /dev/null +++ "b/IMPETOM-Cl\303\255nico/Interfaz.py" @@ -0,0 +1,1162 @@ +import threading +import time +import tkinter.ttk +from tkinter import * +from tkinter import messagebox +from PIL import Image, ImageTk +from _datetime import date +import re +from ImpetomC import ImpetomC +from ImpetomCError import ImpetomCError +from ImpetomCElectrodeError import ImpetomCElectrodeError +from datetime import datetime +import winsound + +""" +Clase que genera la interfaz gráfica de la aplicación +""" + +""" +Variables globales de la aplicación +""" + +arduinoImpetom = 0 # 0 indica arduinoImpetom desconectado, 1 indica que esta conectado +Reconstruir = False +mode = "Setup" +img = Image.open('imagenInicial.jpg') +sclRangeEnable = False + +""" +Funciones para validación de datos de entrada +""" + +def validateName(): + """ + Funcion que valida el nombre del paciente ingresado + :return: 0 si existe algun error, 1 si el nombre es correcto (el campo lblNameError no esta vacio) + """ + + ret=0 + patName = txtName.get("1.0", END) + if len(patName) <=1 : + lblNameError.config(text="Este campo no puede estar vacÃo") + else: + ret=1 + lblNameError.config(text="") + return ret + +def validateCI(): + """ + Funcion que valida la CI del paciente ingresado + :return: 0 si existe algun error, 1 si la CI es correcta (el campo lblNameError no esta vacio) + """ + + ret = 0 + patCi = txtCi.get("1.0", END).strip("\n") + lenCI=len(patCi) + if not re.match('^[0-9]*$',patCi): + lblCiError.config(text="La CI solo puede contener números") + elif lenCI <= 6 or lenCI > 8: + lblCiError.config(text="CI inválida") + else: + ret = 1 + lblCiError.config(text="") + return ret + +def arduinoImpetomConected(): + """ + Funcion que verifica que el dispositivoImpetomC esta conectado + :return: 0 si existe algun error, 1 si no + """ + + ret = 1 + global arduinoImpetom + if arduinoImpetom == 0: + try: # Verifico que haya un arduino conectado al equipo al iniciar y si es el arduino de ImpetomC + ImpetomC.startUp() + arduinoImpetom = 1 # indicador que arduino Impetom está conectado + lblError.config(text="", bg='white') + except ImpetomCError as e: + lblError.config(text=str(e), bg='white') + arduinoImpetom = 0 + ret = 0 + return ret + +def validateSexoBiologico(): + """ + Funcion que valida el sexp biologico del paciente ingresado + :return: 0 si existe algun error, 1 si no + """ + + ret = 0 + patSex = cmbBioSex.get().lower() + if patSex == "seleccionar": + lblBioSexError.config(text="Seleccione una opción válida") + else: + lblBioSexError.config(text="") + ret = 1 + return ret + +def validateBirthDate(): + """ + Funcion que valida la fecha de nacimiento del paciente ingresado + :return: 0 si existe algun error, 1 si no + """ + + ret = 0 + txtBDate = str(txtBirthDate.get("1.0", 'end-1c')) + try: + datetime.strptime(txtBDate, "%d-%m-%Y") + lblBirthDateError.config(text="") + ret = 1 + except ValueError: + lblBirthDateError.config(text="La fecha debe ser dd-mm-yyyy") + finally: + return ret + +def validateMedida(): + """ + Función que valida la entrada de los datos de medida de circunferencia del tórax, + El dato debe ser un número entre 100 y 2000mm + """ + + ret = 0 + fantomaMed = txtMedida.get("1.0", END).strip("\n") + lenFantomaMed = len(fantomaMed) + if not re.match('^[0-9]*$', fantomaMed): + lblMedidaError.config(text="Este campo solo puede contener números positivos") + elif lenFantomaMed <= 2: # Verifico que el número sea mayor que 100 mm + lblMedidaError.config(text="El perÃmetro debe ser mayor o igual a 100 mm") + elif lenFantomaMed >= 5: + lblMedidaError.config(text="El perÃmetro es demasiado grande") + else: + ret = 1 + lblMedidaError.config(text="") + if lenFantomaMed == 4: + intFantomaMed = int(fantomaMed) + if intFantomaMed >= 2000: + lblMedidaError.config(text="El perÃmetro es demasiado grande") + ret = 0 + + return ret + +def validateMedidaZ(): + """ + Función que valida la altura de colocación del cinturon, debe estar entre 10 mm y 999mm + """ + + ret = 0 + fantomaMedZ = txtMedidaZ.get("1.0", END).strip("\n") + fantomaMedZ = fantomaMedZ.strip("-") # Para validar ints > 0 y < 0 con la misma regExp + lenFantomaMedZ = len(fantomaMedZ) + lblMedidaZError.place(x=(265 / 1200) * screenWidth, y=(560 / 750) * screenHeight) + if not re.match('^[0-9]*$', fantomaMedZ): + lblMedidaZError.config( + text="La altura de colocación del cinturón debe ser un número entero medido desde la apófisis del esternón") + elif lenFantomaMedZ < 1 or lenFantomaMedZ > 3: # + lblMedidaZError.config(text="La referencia de altura no es válida") + else: + ret = 1 + lblMedidaZError.config(text="") + return ret + +""" +Eventos para botones Start y Stop +""" + +def btnStartClicked(): + """ + Evento del botón start + """ + + global Reconstruir, arduinoImpetom + if validateName() +validateCI() + arduinoImpetomConected() + validateSexoBiologico() + validateBirthDate() + validateMedida() + validateMedidaZ() == 7: + Reconstruir = True + txtMedida.config(state='disable') + txtMedidaZ.config(state='disable') + txtName.config(state='disable') + txtCi.config(state='disable') + btnIncTime.config(state='disable') + btnIncTime2.config(state='disable') + btnDecTime.config(state='disable') + btnDecTime2.config(state='disable') + btnStart.config(state='disable') + lblTimeError.config(text="Presione Stop para cambiar esta opción") + btnReconstruccion.config(state='disable') + btnSetup.config(state='disable') + cmbModel.config(state='disable') + lblModeMessage.config(text='Presione Stop para cambiar esta opción') + btnCalibrar.config(state='disable') + btnReset.config(state='disable') + threading.Thread(target=reloadImage).start() + + +def btnStopClicked(): + """ + Evento del botón Stop + """ + + global Reconstruir + Reconstruir = False + time.sleep(4) + txtMedida.config(state='normal') + txtMedidaZ.config(state='normal') + txtName.config(state='normal') + txtCi.config(state='normal') + btnIncTime.config(state='normal') + btnIncTime2.config(state='normal') + btnDecTime.config(state='normal') + btnDecTime2.config(state='normal') + btnStart.config(state='normal') + btnStop.config(state='disable') + lblTimeError.config(text="") + lblModeMessage.config(text='') + btnCalibrar.config(state='normal') + btnReset.config(state='normal') + if mode == "Setup": + btnReconstruccion.config(state='normal') + else: + btnSetup.config(state='normal') + cmbModel.config(state='readonly') + +def btnResetClicked(): + """ + Evento para el botón reset + """ + + global img, photo + lblDate.config(text="Fecha: " + str(date.today().strftime("%b-%d-%Y"))) + btnReset.config(state='disable') + ImpetomC.reset() + img = Image.open('imagenInicial.jpg') + photo = ImageTk.PhotoImage(img) + lblImg.config(text="", image=photo, width=(700 / 1200) * screenWidth, height=(500 / 750) * screenHeight) + cmbModel.current(0) + lblpRangeValue.config(text=initialPValue) + lblGananciaValue.config(text=initialGValue) + lblVmaxValue.config(text=initialVmaxValue) + lblVminValue.config(text=initialVminValue) + lblSaveTimeValue.config(text=initialSaveTimeValue) + lblError.config(text="", bg="white") + btnSetupClicked() + rbtnSclOptionsDisable.select() + if tkinter.messagebox.askyesno("Reset", "Desea también eliminar los datos del paciente?"): + txtName.delete("1.0", "end") + txtCi.delete("1.0", "end") + txtMedida.delete("1.0", "end") + txtMedidaZ.delete("1.0", "end") + txtBirthDate.delete("1.0", "end") + cmbBioSex.current(0) + +""" +Esta función se encarga de actualizar las imágenes en lblImg +""" + +def reloadImage(): + """ + Esta funcion es la encargada de actualizar las imagenes en la etiqueta lblImg + """ + + global img, photo, arduinoImpetom, Reconstruir, bpWeight, screenWidth, sclRangeEnable, mode + ti = time.time() + while Reconstruir: + try: + medida = txtMedida.get("1.0", END).strip("\n") + medidaZ = txtMedidaZ.get("1.0", END).strip("\n") + vmax = float(lblVmaxValue.cget("text")) + vmin = float(lblVminValue.cget("text")) + pvalue = round(float(lblpRangeValue.cget("text")), 2) + frecValue = str(30000 - int(lblGananciaValue.cget("text")) * 100) + shape = cmbModel.get().lower() + pacBDate = str(datetime.strptime(txtBirthDate.get("1.0", 'end-1c'), "%d-%m-%Y").strftime("%Y%m%d")) + pacSex = cmbBioSex.get() + ImpetomC.generarImagenTomografica(vmax=vmax, screenWidth=screenWidth, sclEnable=sclRangeEnable, vmin=vmin, + mode=mode, shape=shape, p=pvalue, frecuenciaDDS=frecValue) + tf = time.time() + elapsedTime = int(tf - ti) + img = Image.open('IMG.jpg') + photo = ImageTk.PhotoImage(img) + lblImg.config(text="", image=photo) + lblError.config(text="", bg='#2b70e4') + if elapsedTime > int(float(lblSaveTimeValue.cget('text')) * 60): # Conversión de minutos a segundos + ImpetomC.guardarImagenEnHistoriaClinica(pacientName=txtName.get("1.0", END), + pacientCi=txtCi.get("1.0", END), p=pvalue, pacSex=pacSex, + pacBirthDate=pacBDate, medida=medida, shape=shape, + medidaZ=medidaZ, mode=mode) + ti = time.time() + if Reconstruir: + btnStop.config(state='normal') + except ImpetomCError as e: # errores por problemas de conexion del dispositivo Arduino + lblError.config(text=str(e) + " Por favor verifique la conexión y presione start nuevamente", bg='white') + winsound.Beep(440, 500) + Reconstruir = False + arduinoImpetom = 0 # arduino ImpetomC no está conectado + btnStopClicked() + ImpetomC.guardarImagenEnHistoriaClinica(pacientName=txtName.get("1.0", END), + pacientCi=txtCi.get("1.0", END), p=pvalue, pacSex=pacSex, + pacBirthDate=pacBDate, medida=medida, shape=shape, medidaZ=medidaZ, + mode=mode) + except ImpetomCElectrodeError as e: # Errores detectados sobre los electrodos + lblError.config(text=str(e), bg='white', fg='#f00') + tf = time.time() + elapsedTime = int(tf - ti) + img = Image.open('IMG.jpg') + photo = ImageTk.PhotoImage(img) + lblImg.config(text="", image=photo) + if e.regularGanancia and elapsedTime > int(float(lblSaveTimeValue.cget( + 'text')) * 60): # Para errores de regular ganancia se guarda la imágen, si son errores de falso contacto no se guarda la imágen + ImpetomC.guardarImagenEnHistoriaClinica(pacientName=txtName.get("1.0", END), + pacientCi=txtCi.get("1.0", END), p=pvalue, pacSex=pacSex, + pacBirthDate=pacBDate, medida=medida, shape=shape, + medidaZ=medidaZ, mode=mode) + ti = time.time() + elif not e.regularGanancia: + winsound.Beep(440, 500) + if Reconstruir: + btnStop.config(state='normal') + except RuntimeError: # Se esta recontruyendo la imagen y se presiona el botón de salir + time.sleep(5) + root.destroy() + +""" +Funciones botones p del jac +""" +maxPValue = 0.9 +minPValue = 0.05 +def incPRange(): + """ + Evento del boton ">" de p + """ + + enableDecpRange() + pRangeValue = float(lblpRangeValue.cget("text")) + pRangeValue += 0.01 + if pRangeValue >= maxPValue: + pRangeValue = maxPValue + disbleIncpRange() + lblpRangeValue.config(text=str(round(pRangeValue,2))) + +def incPRange2(): + """ + Evento del boton ">>" de p + """ + + enableDecpRange() + pRangeValue = float(lblpRangeValue.cget("text")) + pRangeValue += 0.1 + if pRangeValue >= maxPValue: + pRangeValue = maxPValue + disbleIncpRange() + lblpRangeValue.config(text=str(round(pRangeValue,2))) + +def decPRange(): + """ + Evento del boton "<" de p + """ + + enableIncpRange() + pRangeValue = float(lblpRangeValue.cget("text")) + pRangeValue -= 0.01 + if pRangeValue <= minPValue: + pRangeValue = minPValue + disableDecpRange() + lblpRangeValue.config(text=str(round(pRangeValue,2))) + +def decPRange2(): + """ + Evento del boton "<<" de p + """ + + enableIncpRange() + pRangeValue = float(lblpRangeValue.cget("text")) + pRangeValue -= 0.1 + if pRangeValue <= minPValue: + pRangeValue = minPValue + disableDecpRange() + lblpRangeValue.config(text=str(round(pRangeValue,2))) + +def enableIncpRange(): + """ + Permite habilitar los botones ">>" y ">" de p + """ + + btnIncpRange.config(state="normal") + btnIncpRange2.config(state="normal") + +def enableDecpRange(): + """ + Permite habilitar los botones "<" y "<<" de p + """ + + btnDecpRange.config(state="normal") + btnDecpRange2.config(state="normal") + +def disbleIncpRange(): + """ + Permite deshabilitar los botones ">>" y ">" de p + """ + + btnIncpRange.config(state="disable") + btnIncpRange2.config(state="disable") + +def disableDecpRange(): + """ + Permite deshabilitar los botones "<" y "<<" de p + """ + + btnDecpRange.config(state="disable") + btnDecpRange2.config(state="disable") + +""" +Eventos de los botones para el manejo de la ganancia +""" + +maxGananciaValue = 5 +minGananciaValue = -20 + +def incGanancia(): + """ + Evento del boton ">" de la ganancia del sistema + """ + + enableDecGanancia() + gananciaValue = int(lblGananciaValue.cget("text")) + gananciaValue += 1 + if gananciaValue >= maxGananciaValue: + gananciaValue = maxGananciaValue + disableIncGanancia() + lblGananciaValue.config(text=gananciaValue) + +def incGanancia2(): + """ + Evento del boton ">>" de la ganancia del sistema + """ + + enableDecGanancia() + gananciaValue = int(lblGananciaValue.cget("text")) + gananciaValue += 5 + if gananciaValue >= maxGananciaValue: + gananciaValue = maxGananciaValue + disableIncGanancia() + lblGananciaValue.config(text=gananciaValue) + +def decGanancia(): + """ + Evento del boton "<" de la ganancia del sistema + """ + + enableIncGanancia() + gananciaValue = int(lblGananciaValue.cget("text")) + gananciaValue -= 1 + if gananciaValue <= minGananciaValue: + gananciaValue =minGananciaValue + disableDecGanancia() + lblGananciaValue.config(text=gananciaValue) + +def decGanancia2(): + """ + Evento del boton "<<" de la ganancia del sistema + """ + + enableIncGanancia() + gananciaValue = int(lblGananciaValue.cget("text")) + gananciaValue -= 5 + if gananciaValue <= minGananciaValue: + gananciaValue = minGananciaValue + disableDecGanancia() + lblGananciaValue.config(text=gananciaValue) + +def enableIncGanancia(): + """ + Permite habilitar los botones ">>" y ">" de ganancia + """ + + btnIncGanancia.config(state="normal") + btnIncGanancia2.config(state="normal") + +def enableDecGanancia(): + """ + Permite habilitar los botones "<<" y "<" de ganancia + """ + + btnDecGanancia.config(state="normal") + btnDecGanancia2.config(state="normal") + +def disableIncGanancia(): + """ + Permite deshabilitar los botones ">>" y ">" de ganancia + """ + + btnIncGanancia.config(state="disable") + btnIncGanancia2.config(state="disable") + +def disableDecGanancia(): + """ + Permite deshabilitar los botones "<<" y "<" de ganancia + """ + + btnDecGanancia.config(state="disable") + btnDecGanancia2.config(state="disable") + +""" +Funciones botones para el valor de Vmax +""" + +maxVMAXvalue = 5 +minVMAXvalue = -20 + +def incVmax(): + """ + Evento del boton ">" de vmax + """ + + enableDecVmax() + vmaxValue = float(lblVmaxValue.cget("text")) + vmaxValue += 0.1 + if vmaxValue >= maxVMAXvalue: + vmaxValue = maxVMAXvalue + disableIncVmax() + lblVmaxValue.config(text=str(round(vmaxValue,1))) + +def incVmax2(): + """ + Evento del boton ">>" de vmax + """ + + enableDecVmax() + vmaxValue = float(lblVmaxValue.cget("text")) + vmaxValue += 1 + if vmaxValue >= maxVMAXvalue: + vmaxValue = maxVMAXvalue + disableIncVmax() + lblVmaxValue.config(text=str(round(vmaxValue,1))) + +def decVmax(): + """ + Evento del boton "<" de vmax + """ + enableIncVmax() + vmaxValue = float(lblVmaxValue.cget("text")) + vmaxValue -= 0.1 + if vmaxValue <= minVMAXvalue: + vmaxValue = minVMAXvalue + disableDecVmax() + if vmaxValue > float(lblVminValue.cget("text")): + lblVmaxValue.config(text=str(round(vmaxValue,1))) + +def decVmax2(): + """ + Evento del boton "<<" de vmax + """ + + enableIncVmax() + vmaxValue = float(lblVmaxValue.cget("text")) + vmaxValue -= 1 + if vmaxValue <= minVMAXvalue: + vmaxValue = minVMAXvalue + disableDecVmax() + if vmaxValue > float(lblVminValue.cget("text")): + lblVmaxValue.config(text=str(round(vmaxValue,1))) + +def enableIncVmax(): + """ + Permite habilitar los botones ">>" y ">" de vmax + """ + + btnIncVmax.config(state="normal") + btnIncVmax2.config(state="normal") + +def enableDecVmax(): + """ + Permite habilitar los botones "<<" y "<" de vmax + """ + + btnDecVmax.config(state="normal") + btnDecVmax2.config(state="normal") + +def disableIncVmax(): + """ + Permite deshabilitar los botones ">>" y ">" de vmax + """ + + btnIncVmax.config(state="disable") + btnIncVmax2.config(state="disable") + +def disableDecVmax(): + """ + Permite deshabilitar los botones "<<" y "<" de vmax + """ + + btnDecVmax.config(state="disable") + btnDecVmax2.config(state="disable") + +""" +Funciones botones para el valor de Vmin +""" + +maxVMINValue = 0 +minVMINValue = -40 + +def incVmin(): + """ + Evento del boton ">" de vmin + """ + + enableDecVmin() + VminValue = float(lblVminValue.cget("text")) + VminValue += 0.1 + if VminValue >= maxVMINValue: + VminValue = maxVMINValue + disableIncVmin() + if VminValue < float(lblVmaxValue.cget("text")): + lblVminValue.config(text=str(round(VminValue,1))) + +def incVmin2(): + """ + Evento del boton ">>" de vmin + """ + + enableDecVmin() + VminValue = float(lblVminValue.cget("text")) + VminValue += 1 + if VminValue >= maxVMINValue: + VminValue = maxVMINValue + disableIncVmin() + if VminValue < float(lblVmaxValue.cget("text")): + lblVminValue.config(text=str(round(VminValue,1))) + +def decVmin(): + """ + Evento del boton "<" de vmin + """ + + enableIncVmin() + VminValue = float(lblVminValue.cget("text")) + VminValue -= 0.1 + if VminValue <= minVMINValue: + VminValue = minVMINValue + disableDecVmin() + lblVminValue.config(text=str(round(VminValue,1))) + +def decVmin2(): + """ + Evento del boton "<<" de vmin + """ + + enableIncVmin() + VminValue = float(lblVminValue.cget("text")) + VminValue -= 1 + if VminValue <= minVMINValue: + VminValue = minVMINValue + disableDecVmin() + lblVminValue.config(text=str(round(VminValue,1))) + +def enableIncVmin(): + """ + Permite habilitar los botones ">>" y ">" de vmin + """ + + btnIncVmin.config(state="normal") + btnIncVmin2.config(state="normal") + +def enableDecVmin(): + """ + Permite habilitar los botones "<<" y "<" de vmin + """ + + btnDecVmin.config(state="normal") + btnDecVmin2.config(state="normal") + +def disableIncVmin(): + """ + Permite deshabilitar los botones ">>" y ">" de vmin + """ + + btnIncVmin.config(state="disable") + btnIncVmin2.config(state="disable") + +def disableDecVmin(): + """ + Permite deshabilitar los botones "<<" y "<" de vmin + """ + + btnDecVmin.config(state="disable") + btnDecVmin2.config(state="disable") + + +""" +Funciones para actualizar el modo (Reconstruction o Setup) en pantalla +""" + +def btnReconstruccionClicked(): + """ + Evento del boton modo Reconstruccion + """ + + global mode + mode = "Reconstruccion" + lblModeValue.config(text="Reconstrucción") + btnReconstruccion.config(state='disabled') + btnSetup.config(state='normal') + +def btnSetupClicked(): + """ + Evento del boton modo Setup + """ + global mode + mode = "Setup" + lblModeValue.config(text=mode) + btnReconstruccion.config(state='normal') + btnSetup.config(state='disabled') + +""" +Funciones para obtener el vector de datos homogéneo +""" + +def calibrar(): + """ + Evento del boton calibrar + """ + ImpetomC.actualizarVectorDeDatosHomogeneo() + btnReset.config(state="normal") + +""" +Funciones botones Saved Timed +""" + +maxTimeValue= 120 +minTimeValue = 0.5 +def incTime(): + """ + Evento del boton ">" de tiempo entre imagenes guardadas + """ + + enableDecTime() + timeValue = float(lblSaveTimeValue.cget("text")) + if timeValue == minTimeValue: + timeValue = 1 + else: + timeValue += 1 + if timeValue >= maxTimeValue: + timeValue = maxTimeValue + disbleIncTime() + lblSaveTimeValue.config(text=str(round(timeValue))) + +def incTime2(): + """ + Evento del boton ">>" de tiempo entre imagenes guardadas + """ + + enableDecTime() + timeValue = float(lblSaveTimeValue.cget("text")) + if timeValue == minTimeValue: + timeValue = 5 + else: + timeValue += 5 + if timeValue >= maxTimeValue: + timeValue = maxTimeValue + disbleIncTime() + lblSaveTimeValue.config(text=str(round(timeValue))) + +def decTime(): + """ + Evento del boton "<" de tiempo entre imagenes guardadas + """ + + enableIncTime() + timeValue = float(lblSaveTimeValue.cget("text")) + timeValue -= 1 + if timeValue < minTimeValue: + timeValue = minTimeValue + lblSaveTimeValue.config(text=str(round(timeValue,1))) + disableDecTime() + else: + lblSaveTimeValue.config(text=str(round(timeValue))) + +def decTime2(): + """ + Evento del boton "<<" de tiempo entre imagenes guardadas + """ + + enableIncTime() + timeValue = float(lblSaveTimeValue.cget("text")) + timeValue -= 5 + if timeValue < minTimeValue: + timeValue = minTimeValue + lblSaveTimeValue.config(text=str(round(timeValue,1)))#redondea para colocar 0.5 en pantalla + disableDecTime() + else: + lblSaveTimeValue.config(text=str(round(timeValue))) + +def enableIncTime(): + """ + Permite habilitar los botones ">>" y ">" del tiempo entre imagenes guardadas + """ + + btnIncTime.config(state="normal") + btnIncTime2.config(state="normal") + +def enableDecTime(): + """ + Permite habilitar los botones "<<" y "<" del tiempo entre imagenes guardadas + """ + + btnDecTime.config(state="normal") + btnDecTime2.config(state="normal") + +def disbleIncTime(): + """ + Permite deshabilitar los botones ">>" y ">" del tiempo entre imagenes guardadas + """ + btnIncTime.config(state="disable") + btnIncTime2.config(state="disable") + +def disableDecTime(): + """ + Permite deshabilitar los botones "<<" y "<" del tiempo entre imagenes guardadas + """ + + btnDecTime.config(state="disable") + btnDecTime2.config(state="disable") + + +""" +Funciones de los radioButtons de BP +""" + +def enableScaleOptions(): + """ + Evento del radio button para habilitar las opciones del rango de escala + """ + + global sclRangeEnable + sclRangeEnable = True + enableIncVmin() + enableIncVmax() + enableDecVmin() + enableDecVmax() + + +def disableScaleOptions(): + """ + Evento del radio button para deshabilitar las opciones del rango de escala + """ + + global sclRangeEnable + sclRangeEnable = False + disableDecVmin() + disableDecVmax() + disableIncVmax() + disableIncVmin() + +""" +Función para el control del evento de cierre de la aplicación +""" + +def onClose(): + """ + Evento de cierre de la aplicacion + """ + if tkinter.messagebox.askyesno("Salir","Está seguro que desea salir?"): + global Reconstruir + if Reconstruir: + Reconstruir=False + time.sleep(5)# esto es para que pueda finalizar el programa sin tirar error. Es por si se cierra el programa, con el programa updeteando la imagen + root.destroy() + +""" +Armado de la interfaz +Como nota general, se uso para la escala de la pantalla 1200 (width) y 750 (height), por eso se ven esos números en todo el código de aquà en más. +Esto es porque para la versión incial de la interfaz se utilizó una con ese tamaño y se logró colocar todos los widgets quedando la interfaz agradable a la vista +""" + +if __name__ == '__main__': + + root = Tk() + root.title("Impetom-C app") + screenWidth = root.winfo_screenwidth() + screenHeight = root.winfo_screenheight() + rootSize = str(screenWidth) + "x" + str(screenHeight) + root.geometry(rootSize) + + root.protocol("WM_DELETE_WINDOW", onClose) # manejo del evento de cierre por la cruz de la interfaz + root.resizable(width=False, height=False) # el usuario no puede cambiar el tamaño de la ventana + + """ + Info Impetom + logo fing + """ + + # Se agrega imagen de fondo de la app + bg = PhotoImage(file="fondo_Impetom.png") # color azul fondo #2b70e4 amarillo #eccc6e + # Create Canvas + canvas1 = Canvas(root, width=screenWidth, height=screenHeight) + canvas1.place(x=0, y=0) + canvas1.create_image((0 / 1200) * screenWidth, 0, image=bg, anchor="nw") + + """ + Datos del paciente + #f00 es el color rojo para cualquier SO + """ + lblPatient = Label(root, text="Datos del paciente", bg='#2b70e4', fg='white', font=("Helvetica", 12, "bold")) + lblPatient.place(x=(30 / 1200) * screenWidth, y=(20 / 750) * screenHeight) + + lblDate = Label(root, text="Fecha: " + str(date.today().strftime("%b-%d-%Y")), bg='#2b70e4', fg='white', + font=("Helvetica", 10, "bold")) + lblDate.place(x=(330 / 1200) * screenWidth, y=(20 / 750) * screenHeight) + + lblName = Label(root, text="Nombre:", bg='#2b70e4', fg='white', font=("Helvetica", 10, "bold")) + lblName.place(x=(50 / 1200) * screenWidth, y=(50 / 750) * screenHeight) + txtName = Text(root, width=30, height=1) + txtName.place(x=(105 / 1200) * screenWidth, y=(50 / 750) * screenHeight) + lblNameError = Label(root, fg='red', text="Este campo es obligatorio", bg='#2b70e4', font=("Helvetica", 8, "bold")) + lblNameError.place(x=(100 / 1200) * screenWidth, y=(75 / 750) * screenHeight) + + lblCi = Label(root, text="CI:", bg='#2b70e4', fg='white', font=("Helvetica", 10, "bold")) + lblCi.place(x=(50 / 1200) * screenWidth, y=(100 / 750) * screenHeight) + txtCi = Text(root, width=15, height=1) + txtCi.place(x=(100 / 1200) * screenWidth, y=(100 / 750) * screenHeight) + lblCiError = Label(root, fg='red', text="Este campo es obligatorio", bg='#2b70e4', font=("Helvetica", 8, "bold")) + lblCiError.place(x=(100 / 1200) * screenWidth, y=(125 / 750) * screenHeight) + + lblSexoBiologico = Label(root, text="Sexo:", bg='#2b70e4', fg='white', font=("Helvetica", 10, "bold")) + lblSexoBiologico.place(x=(310 / 1200) * screenWidth, y=(50 / 750) * screenHeight) + cmbBioSex = tkinter.ttk.Combobox(root, values=['Seleccionar', 'M', 'F', 'Otro'], state='readonly', width=10) + cmbBioSex.place(x=(350 / 1200) * screenWidth, y=(50 / 750) * screenHeight) + lblBioSexError = Label(root, text="Este campo es obligatorio", fg='red', bg='#2b70e4', font=("Helvetica", 8, "bold")) + lblBioSexError.place(x=(315 / 1200) * screenWidth, y=(75 / 750) * screenHeight) + cmbBioSex.current(0) + + lblBirthDate = Label(root, text="Fecha de nacimiento:", bg='#2b70e4', fg='white', font=("Helvetica", 10, "bold")) + lblBirthDate.place(x=(215 / 1200) * screenWidth, y=(100 / 750) * screenHeight) + txtBirthDate = Text(root, width=10, height=1) + txtBirthDate.place(x=(350 / 1200) * screenWidth, y=(100 / 750) * screenHeight) + lblBirthDateError = Label(root, text="Formato : dd-mm-yyyy", fg='red', bg='#2b70e4', font=("Helvetica", 8, "bold")) + lblBirthDateError.place(x=(315 / 1200) * screenWidth, y=(125 / 750) * screenHeight) + + """ + Imagen inicial en la app + """ + + photo = ImageTk.PhotoImage(img) + lblImg = Label(root, image=photo, width=(700 / 1200) * screenWidth, height=(500 / 750) * screenHeight) + lblImg.place(x=(445 / 1200) * screenWidth, y=(175 / 750) * screenHeight) + + """ + botones Start, Stop, Calibrar y Reset + """ + + btnStart = Button(root, text="Start", padx=15, pady=2, command=btnStartClicked) + btnStart.place(x=(1030 / 1200) * screenWidth, y=(690 / 750) * screenHeight) + + btnStop = Button(root, text="Stop", padx=10, pady=2, command=btnStopClicked, state='disable') + btnStop.place(x=(1090 / 1200) * screenWidth, y=(690 / 750) * screenHeight) + + btnCalibrar = Button(root, text="Calibrar", command=calibrar) + btnCalibrar.place(x=(400 / 1200) * screenWidth, y=(690 / 750) * screenHeight) + + btnReset = Button(root, text="Reset", command=btnResetClicked, state='disable') + btnReset.place(x=(1100 / 1200) * screenWidth, y=(145 / 750) * screenHeight) + + """ + Control de modo de cambio de modo + """ + + lblMode = Label(root, text="Modo: ", bg='#2b70e4', font=("Helvetica", 12, "bold")) + lblMode.place(x=(140 / 1200) * screenWidth, y=(170 / 750) * screenHeight) + lblModeValue = Label(root, text=mode, bg='#2b70e4', font=("Helvetica", 12)) + lblModeValue.place(x=(190 / 1200) * screenWidth, y=(170 / 750) * screenHeight) + + btnReconstruccion = Button(root, text="Reconstrucción", command=btnReconstruccionClicked, + font=("Helvetica", 10, "bold")) + btnReconstruccion.place(x=(110 / 1200) * screenWidth, y=(195 / 750) * screenHeight) + + btnSetup = Button(root, text="Setup", padx=10, command=btnSetupClicked, state='disable', font=("Helvetica", 10, "bold")) + btnSetup.place(x=(210 / 1200) * screenWidth, y=(195 / 750) * screenHeight) + + lblModeMessage = Label(root, fg='#f00', bg='white') + lblModeMessage.place(x=(80 / 1200) * screenWidth, y=(225 / 750) * screenHeight) + + """ + Opciones para la reconstrucción + Primero el valor p + """ + lblImgOptions = Label(root, text="Opciones de imagen", font=("Helvetica", 10, "bold"), bg='white') + lblImgOptions.place(x=(130 / 1200) * screenWidth, y=(245 / 750) * screenHeight) + + lblp = Label(root, text="p", bg='white') + lblp.place(x=(177 / 1200) * screenWidth, y=(270 / 750) * screenHeight) + initialPValue = "0.2" + lblpRangeValue = Label(root, text=initialPValue, bg='white') # p=0.25 para setup + lblpRangeValue.place(x=(175 / 1200) * screenWidth, y=(295 / 750) * screenHeight) + + btnIncpRange = Button(root, text=">", command=incPRange) + btnIncpRange.place(x=(250 / 1200) * screenWidth, y=(295 / 750) * screenHeight) + + btnIncpRange2 = Button(root, text=">>", command=incPRange2) + btnIncpRange2.place(x=(275 / 1200) * screenWidth, y=(295 / 750) * screenHeight) + + btnDecpRange = Button(root, text="<", command=decPRange) + btnDecpRange.place(x=(100 / 1200) * screenWidth, y=(295 / 750) * screenHeight) + + btnDecpRange2 = Button(root, text="<<", command=decPRange2) + btnDecpRange2.place(x=(67 / 1200) * screenWidth, y=(295 / 750) * screenHeight) + + """ + Control para la frecuencia (ganancia) + """ + lblGanancia = Label(root, text="Ganancia", bg='white') + lblGanancia.place(x=(160 / 1200) * screenWidth, y=(330 / 750) * screenHeight) + initialGValue = "-10" + lblGananciaValue = Label(root, text=initialGValue, bg='white') + lblGananciaValue.place(x=(175 / 1200) * screenWidth, y=(355 / 750) * screenHeight) + + btnIncGanancia = Button(root, text=">", command=incGanancia) + btnIncGanancia.place(x=(250 / 1200) * screenWidth, y=(355 / 750) * screenHeight) + + btnIncGanancia2 = Button(root, text=">>", command=incGanancia2) + btnIncGanancia2.place(x=(275 / 1200) * screenWidth, y=(355 / 750) * screenHeight) + + btnDecGanancia = Button(root, text="<", command=decGanancia) + btnDecGanancia.place(x=(100 / 1200) * screenWidth, y=(355 / 750) * screenHeight) + + btnDecGanancia2 = Button(root, text="<<", command=decGanancia2) + btnDecGanancia2.place(x=(67 / 1200) * screenWidth, y=(355 / 750) * screenHeight) + + """ + Control del rango de escala + """ + + lblSclRangeOptions = Label(root, text="Control de rango de escala", font=("Helvetica", 10, "bold"), bg='white') + lblSclRangeOptions.place(x=(110 / 1200) * screenWidth, y=(400 / 750) * screenHeight) + + rbtnSclOptionsEnable = Radiobutton(root, text="On", variable=0, value=1, command=enableScaleOptions, bg='white') + rbtnSclOptionsEnable.place(x=(280 / 1200) * screenWidth, y=(400 / 750) * screenHeight) + + rbtnSclOptionsDisable = Radiobutton(root, text="Off", variable=0, value=2, command=disableScaleOptions, bg='white') + rbtnSclOptionsDisable.place(x=(320 / 1200) * screenWidth, y=(400 / 750) * screenHeight) + rbtnSclOptionsDisable.select() + """ + Control Vmax + """ + + lblVmax = Label(root, text=" Valor máximo", bg='white') + lblVmax.place(x=(145 / 1200) * screenWidth, y=(425 / 750) * screenHeight) + initialVmaxValue = "0.5" + lblVmaxValue = Label(root, text=initialVmaxValue, bg='white') + lblVmaxValue.place(x=(175 / 1200) * screenWidth, y=(450 / 750) * screenHeight) + + btnIncVmax = Button(root, text=">", command=incVmax) + btnIncVmax.place(x=(250 / 1200) * screenWidth, y=(450 / 750) * screenHeight) + + btnIncVmax2 = Button(root, text=">>", command=incVmax2) + btnIncVmax2.place(x=(275 / 1200) * screenWidth, y=(450 / 750) * screenHeight) + + btnDecVmax = Button(root, text="<", command=decVmax) + btnDecVmax.place(x=(100 / 1200) * screenWidth, y=(450 / 750) * screenHeight) + + btnDecVmax2 = Button(root, text="<<", command=decVmax2) + btnDecVmax2.place(x=(67 / 1200) * screenWidth, y=(450 / 750) * screenHeight) + + """ + Control Vmin + """ + + lblVmin = Label(root, text=" Valor mÃnimo", bg='white') + lblVmin.place(x=(145 / 1200) * screenWidth, y=(480 / 750) * screenHeight) + initialVminValue = "-5.5" + lblVminValue = Label(root, text=initialVminValue, bg='white') + lblVminValue.place(x=(175 / 1200) * screenWidth, y=(510 / 750) * screenHeight) + + btnIncVmin = Button(root, text=">", command=incVmin) + btnIncVmin.place(x=(250 / 1200) * screenWidth, y=(510 / 750) * screenHeight) + + btnIncVmin2 = Button(root, text=">>", command=incVmin2) + btnIncVmin2.place(x=(275 / 1200) * screenWidth, y=(510 / 750) * screenHeight) + + btnDecVmin = Button(root, text="<", command=decVmin) + btnDecVmin.place(x=(100 / 1200) * screenWidth, y=(510 / 750) * screenHeight) + + btnDecVmin2 = Button(root, text="<<", command=decVmin2) + btnDecVmin2.place(x=(67 / 1200) * screenWidth, y=(510 / 750) * screenHeight) + + """ + Control del Modelo + """ + + lblContorno = Label(root, text="Especificaciones de contorno", font=("Helvetica", 10, "bold"), bg='white') + lblContorno.place(x=(110 / 1200) * screenWidth, y=(550 / 750) * screenHeight) + + lblModel = Label(root, text="Forma", bg='white') + lblModel.place(x=(160 / 1200) * screenWidth, y=(575 / 750) * screenHeight) + + cmbModel = tkinter.ttk.Combobox(root, values=['Thorax', 'Circle'], state='readonly') + cmbModel.place(x=(120 / 1200) * screenWidth, y=(600 / 750) * screenHeight) + cmbModel.current(0) # el valor inicial de comboBox es Thorax + + """ + Control de Medida + """ + + lblMedida = Label(root, text="PerÃmetro (mm)", bg='white') + lblMedida.place(x=(260 / 1200) * screenWidth, y=(575 / 750) * screenHeight) + + txtMedida = Text(root, width=4, height=1) + txtMedida.place(x=(280 / 1200) * screenWidth, y=(600 / 750) * screenHeight) + + lblMedidaError = Label(root, text="Campo obligatorio", fg='#f00', bg='white') + lblMedidaError.place(x=(265 / 1200) * screenWidth, y=(620 / 750) * screenHeight) + + """ + Control de Medida_Z + """ + + lblMedidaZ = Label(root, text="Altura (mm)", bg='white') + lblMedidaZ.place(x=(350 / 1200) * screenWidth, y=(575 / 750) * screenHeight) + + txtMedidaZ = Text(root, width=4, height=1) + txtMedidaZ.place(x=(360 / 1200) * screenWidth, y=(600 / 750) * screenHeight) + + lblMedidaZError = Label(root, text="Campo obligatorio", fg='#f00', bg='white') + lblMedidaZError.place(x=(345 / 1200) * screenWidth, y=(550 / 750) * screenHeight) + + """ + Control de tiempos para guardado de imágenes para historia clÃnica + """ + + lblSaveTime = Label(root, text="Tiempo de guardado (min)", font=("Helvetica", 10, "bold"), bg='white') + lblSaveTime.place(x=(100 / 1200) * screenWidth, y=(635 / 750) * screenHeight) + initialSaveTimeValue = "5" + lblSaveTimeValue = Label(root, text=initialSaveTimeValue, bg='white') + lblSaveTimeValue.place(x=(175 / 1200) * screenWidth, y=(665 / 750) * screenHeight) + + btnIncTime = Button(root, text=">", command=incTime) + btnIncTime.place(x=(250 / 1200) * screenWidth, y=(665 / 750) * screenHeight) + + btnIncTime2 = Button(root, text=">>", command=incTime2) + btnIncTime2.place(x=(275 / 1200) * screenWidth, y=(665 / 750) * screenHeight) + + btnDecTime = Button(root, text="<", command=decTime) + btnDecTime.place(x=(100 / 1200) * screenWidth, y=(665 / 750) * screenHeight) + + btnDecTime2 = Button(root, text="<<", command=decTime2) + btnDecTime2.place(x=(67 / 1200) * screenWidth, y=(665 / 750) * screenHeight) + + lblTimeError = Label(root, text="", fg='#f00', bg='white') + lblTimeError.place(x=(100 / 1200) * screenWidth, y=(700 / 750) * screenHeight) + + """ + Por problemas con Arduino al inicio de la aplicación + #2b70e4es el color azul de la imagen del banner + """ + + lblError = Label(root, text="", bg='#2b70e4', font=("Helvetica", 10, "bold"), fg="red") + lblError.place(x=(440 / 1200) * screenWidth, y=(150 / 750) * screenHeight) + disableScaleOptions() # Comienzo el programa con la escala deshabilitada + try: + ImpetomC.startUp() + arduinoImpetom = 1 # Indicador que arduinoImpetom esta conectado + except ImpetomCError as e: + lblError.config(text=str(e) + " Revise la conexión al dispositivo y presione Start", bg='white') + arduinoImpetom = 0 + + root.mainloop()