class Aplicacion: def __init__(self): #************************************************************************* #Crea un objeto TK #************************************************************************* self.raiz = Tk() self.raiz.title ("Mantenimiento de Personas") self.raiz.geometry('900x600') #************************************************************************* #crea el menu de la pantalla #************************************************************************* menubar = Menu(self.raiz) self.raiz.config(menu=menubar) filemenu = Menu(menubar, tearoff=0) filemenu.add_command(label="Acerca de..") filemenu.add_separator() filemenu.add_command(label="Salir", command=self.raiz.quit) mantmenu = Menu(menubar, tearoff=0) mantmenu.add_command(label="Personas") mantmenu.add_command(label="Teléfonos") mantmenu.add_command(label="Direcciones") menubar.add_cascade(label="Archivo", menu=filemenu) menubar.add_cascade(label="Mantenimiento", menu=mantmenu) #************************************************************************* #crea un objeto tipo fuenta #************************************************************************* self.fuente = font.Font(weight="bold") #************************************************************************* #se crean atributos de la clase #************************************************************************* self.t_gustos = Gustos.Gustos() #se crea el objeto de dominio para guardar la información self.insertando = True #************************************************************************* #se crean los campos de la pantalla #************************************************************************* #Se coloca un label del titulo self.lb_tituloPantalla = Label(self.raiz, text = "MANTENIMIENTO DE GUSTOS", font = self.fuente) self.lb_tituloPantalla.place(x = 320, y = 20) #colocar por medio de espacion en pixeles de la parte superior de la pantalla considerando un eje x y un eje y #coloca en el formulario el campo y el label de idNombre Gustos self.lb_cedula = Label(self.raiz, text = "id Nombre Gustos:") self.lb_cedula.place(x = 240, y = 60) self.txt_cedula = Entry(self.raiz, textvariable=self.t_gustos.idNombreGustos, justify="right") self.txt_cedula.place(x = 370, y = 60) #coloca en el formulario el campo y el label de descripcion gustos self.lb_nombre = Label(self.raiz, text = "Descripcion de los Gustos:") self.lb_nombre.place(x = 240, y = 90) self.txt_nombre = Entry(self.raiz, textvariable=self.t_gustos.descripcionGustos, justify="right", width=30) self.txt_nombre.place(x = 370, y = 90) #coloca en el formulario el campo y el label de idUsuario _TGustos self.lb_apellido1 = Label(self.raiz, text = "id Usuario_TGustos:") self.lb_apellido1.place(x = 240, y = 120) self.txt_apellido1 = Entry(self.raiz, textvariable=self.t_gustos.idUsuario_TGustos, justify="right", width=30) self.txt_apellido1.place(x = 370, y = 120) #coloca en el formulario el campo y el label de nombre gustos self.lb_apellido2 = Label(self.raiz, text = "Nombre gustos:") self.lb_apellido2.place(x = 240, y = 150) self.txt_apellido2 = Entry(self.raiz, textvariable=self.t_gustos.nombreGustos, justify="right", width=30) self.txt_apellido2.place(x = 370, y = 150) #coloca los botones enviar y borrar self.bt_borrar = Button(self.raiz, text="Limpiar", width=15, command = self.limpiarInformacion) self.bt_borrar.place(x = 370, y = 330) self.bt_enviar = Button(self.raiz, text="Enviar", width=15, command = self.enviarInformacion) self.bt_enviar.place(x = 510, y = 330) #Se coloca un label del informacion self.lb_tituloPantalla = Label(self.raiz, text = "INFORMACIÓN INCLUIDA", font = self.fuente) self.lb_tituloPantalla.place(x = 350, y = 360) #colocar por medio de espacion en pixeles de la parte superior de la pantalla considerando un eje x y un eje y #************************************************************************* #tabla con informacion #************************************************************************* self.sheet = Sheet(self.raiz, page_up_down_select_row = True, #empty_vertical = 0, column_width = 120, startup_select = (0,1,"rows"), #row_height = "4", #default_row_index = "numbers", #default_header = "both", #empty_horizontal = 0, #show_vertical_grid = False, #show_horizontal_grid = False, #auto_resize_default_row_index = False, #header_height = "3", #row_index_width = 100, #align = "center", #header_align = "w", #row_index_align = "w", #data = [[f"Row {r}, Column {c}\nnewline1\nnewline2" for c in range(50)] for r in range(1000)], #to set sheet data at startup headers = ['idNombreGustos', 'nombreGstos', 'DescripcionGustos','idUsuario','nombreGustos'], #row_index = [f"Row {r}\nnewline1\nnewline2" for r in range(2000)], #set_all_heights_and_widths = True, #to fit all cell sizes to text at start up #headers = 0, #to set headers as first row at startup #headers = [f"Column {c}\nnewline1\nnewline2" for c in range(30)], #theme = "light green", #row_index = 0, #to set row_index as first column at startup #total_rows = 2000, #if you want to set empty sheet dimensions at startup #total_columns = 30, #if you want to set empty sheet dimensions at startup height = 195, #height and width arguments are optional width = 720 #For full startup arguments see DOCUMENTATION.md ) #self.sheet.hide("row_index") #self.sheet.hide("header") #self.sheet.hide("top_left") self.sheet.enable_bindings(("single_select", #"single_select" or "toggle_select" "column_select", "row_select", "column_width_resize", "double_click_column_resize", #"row_width_resize", #"column_height_resize", "arrowkeys", "row_height_resize", "double_click_row_resize", "right_click_popup_menu", "rc_select", "rc_insert_column", "rc_delete_column", "rc_insert_row", "rc_delete_row")) #self.sheet.disable_bindings() #uses the same strings #self.sheet.enable_bindings() self.sheet.place(x = 20, y = 390) #coloca los botones cargar y eliminar self.bt_cargar = Button(self.raiz, text="Cargar", width=15, command = self.cargarInformacion) self.bt_cargar.place(x = 750, y = 385) self.bt_eliminar = Button(self.raiz, text="Eliminar", width=15, command = self.eliminarInformacion) self.bt_eliminar.place(x = 750, y = 425) self.cargarTodaInformacion() #************************************************************************* #se inicial el main loop de la pantalla #************************************************************************* self.raiz.mainloop() #************************************************************************* #Metodo para consultar la información de la base de datos para #cargarla en la tabla #************************************************************************* def cargarTodaInformacion(self): try: self.gustosBo = GustosBO.GustosBO() #se crea un objeto de logica de negocio resultado = self.gustosBo.consultar() self.sheet.set_sheet_data(resultado) except Exception as e: msg.showerror("Error", str(e)) #si se genera algun tipo de error muestra un mensache con dicho error #************************************************************************* #Metodo para cargar informacion #************************************************************************* def cargarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() idNombreGustos = (self.sheet.get_cell_data(datoSeleccionado[0],0)) self.t_gustos.idNombreGustos.set(idNombreGustos) self.gustosBo = GustosBO.GustosBO() #se crea un objeto de logica de negocio self.gustosBo.consultarGustos(self.t_gustos) #se envia a consultar self.insertando = False msg.showinfo("Acción: Consultar el gusto", "La información del gusto ha sido consultada correctamente") # Se muestra el mensaje de que todo esta correcto except Exception as e: msg.showerror("Error", str(e)) #si se genera algun tipo de error muestra un mensache con dicho error #************************************************************************* #Metodo para cargar eliminar la informacion #************************************************************************* def eliminarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() idNombreGustos = (self.sheet.get_cell_data(datoSeleccionado[0],0)) gusto = (self.sheet.get_cell_data(datoSeleccionado[0],1)) resultado = msg.askquestion("Eliminar", "¿Desear eliminar a "+gusto+" de la base de datos?") if resultado == "yes": self.t_gustos.idNombreGustos.set(idNombreGustos) self.gustosBo = GustosBO.GustosBO() #se crea un objeto de logica de negocio self.gustosBo.eliminar(self.t_gustos) #se envia a consultar self.cargarTodaInformacion() self.t_gustos.limpiar() except Exception as e: msg.showerror("Error", str(e)) #si se genera algun tipo de error muestra un mensache con dicho error #************************************************************************* #Metodo para enviar la información a la base de datos #************************************************************************* def enviarInformacion(self): try: self.gustosBo = GustosBO.GustosBO() #se crea un objeto de logica de negocio if(self.insertando == True): self.gustosBo.guardar(self.t_gustos) else: self.gustosBo.modificar(self.t_gustos) self.cargarTodaInformacion() self.t_gustos.limpiar() #se limpia el formulario if(self.insertando == True): msg.showinfo("Acción: Agregar el gusto", "La información de los gustos ha sido incluida correctamente") # Se muestra el mensaje de que todo esta correcto else: msg.showinfo("Acción: Agregar modificar", "La información de los gustos ha sido modificada correctamente") # Se muestra el mensaje de que todo esta correcto except Exception as e: msg.showerror("Error", str(e)) #si se genera algun tipo de error muestra un mensache con dicho error #************************************************************************* #Metodo para limpiar el formulario #************************************************************************* def limpiarInformacion(self): self.t_gustos.limpiar() #llama al metodo de la clase gustos para limpiar los atritudos de la clase self.insertando = True msg.showinfo("Acción del sistema", "La información del formulario ha sido eliminada correctamente") # muestra un mensaje indicando que se limpio el formulario #************************************************************************* #Metodo para mostrar un contro tipo datepicker #************************************************************************* def mostrarDatePicker(self): self.top = Toplevel(self.raiz) self.cal = Calendar(self.top, font="Arial 14", selectmode='day', locale='en_US', cursor="hand", year=2019, month=6, day=16) self.cal.pack(fill="both", expand=True) ttk.Button(self.top, text="Seleccionar").pack()
class Directorio_F: def __init__(self): #Pantalla self.raiz = Tk() self.raiz.title("Mantenimiento de Factura") self.raiz.geometry('600x730') #Barra menu menubar = Menu(self.raiz) self.raiz.config(menu=menubar) filemenu = Menu(menubar, tearoff=0) filemenu.add_command(label="Salir", command=self.raiz.quit) mantmenu = Menu(menubar, tearoff=0) mantmenu.add_command(label="Clientes", command=self.abrir_C) mantmenu.add_command(label="Articulos", command=self.abrir_A) mantmenu.add_command(label="Proveedores", command=self.abrir_p) mantmenu.add_command(label="Conexion", command=self.abrir_R) menubar.add_cascade(label="Archivo", menu=filemenu) menubar.add_cascade(label="Mantenimiento", menu=mantmenu) #Objeto Factura self.fuente = font.Font(weight="bold") self.factura = Factura.Factura() self.insertando = True #Titulo self.lb_tituloPantalla = Label(self.raiz, text="MANTENIMIENTO DE FACTURA", font=self.fuente) self.lb_tituloPantalla.place(x=190, y=20) #Formulario #ID factura self.lb_cedula = Label(self.raiz, text="ID factura:") self.lb_cedula.place(x=150, y=60) self.txt_cedula = Entry(self.raiz, textvariable=self.factura.PK_N_FACTURA, justify="right") self.txt_cedula.place(x=300, y=60) #Cedula self.lb_nombre = Label(self.raiz, text="Cedula:") self.lb_nombre.place(x=150, y=90) self.txt_nombre = Entry(self.raiz, textvariable=self.factura.FK_CEDULA, justify="right") self.txt_nombre.place(x=300, y=90) #Tiempo self.lb_apellido2 = Label(self.raiz, text="Tiempo utilizado") self.lb_apellido2.place(x=150, y=120) self.txt_apellido2 = Entry(self.raiz, textvariable=self.factura.TIEMPO_USO, justify="right", width=30) self.txt_apellido2.place(x=300, y=120) #Monto self.lb_apellido2 = Label(self.raiz, text="Monto Total:") self.lb_apellido2.place(x=150, y=150) self.txt_apellido2 = Entry(self.raiz, textvariable=self.factura.MONTO, justify="right", width=30) self.txt_apellido2.place(x=300, y=150) #Articulos asociados self.lb_apellido2 = Label(self.raiz, text="ID Articulo asociado:") self.lb_apellido2.place(x=150, y=180) self.txt_apellido2 = Entry(self.raiz, textvariable=self.factura.FK_ID_ART, justify="right") self.txt_apellido2.place(x=300, y=180) #Asociado #Se coloca un label del informacion self.lb_tituloPantalla = Label(self.raiz, text="INFORMACIÓN ASOCIADA", font=self.fuente) self.lb_tituloPantalla.place(x=200, y=270) #Nombre-cedula self.lb_apellido2 = Label(self.raiz, text="Nombre asociado:") self.lb_apellido2.place(x=150, y=310) self.txt_apellido2 = Entry(self.raiz, textvariable=self.factura.CLIENTE, justify="right", state="readonly", width=30) self.txt_apellido2.place(x=300, y=310) #Primer Apellido-cedula self.lb_apellido2 = Label(self.raiz, text="1.ª Apellido asociado:") self.lb_apellido2.place(x=150, y=340) self.txt_apellido2 = Entry(self.raiz, textvariable=self.factura.APELLIDO_1, justify="right", state="readonly", width=30) self.txt_apellido2.place(x=300, y=340) #Segundo Apellido-cedula self.lb_apellido2 = Label(self.raiz, text="2.ª Apellido asociado:") self.lb_apellido2.place(x=150, y=370) self.txt_apellido2 = Entry(self.raiz, textvariable=self.factura.APELLIDO_2, justify="right", state="readonly", width=30) self.txt_apellido2.place(x=300, y=370) #Nombre-articulo self.lb_apellido2 = Label(self.raiz, text="Nombre Articulo:") self.lb_apellido2.place(x=150, y=400) self.txt_apellido2 = Entry(self.raiz, textvariable=self.factura.ARTICULO, justify="right", state="readonly", width=30) self.txt_apellido2.place(x=300, y=400) #Botones #Boton Limpiar self.bt_borrar = Button(self.raiz, text="Limpiar", width=15, command=self.limpiarInformacion) self.bt_borrar.place(x=190, y=220) #Boton Enviar self.bt_enviar = Button(self.raiz, text="Enviar", width=15, command=self.enviarInformacion) self.bt_enviar.place(x=310, y=220) #Boton Cargar self.bt_borrar = Button(self.raiz, text="Cargar", width=15, command=self.cargarInformacion) self.bt_borrar.place(x=430, y=220) #Boton Eliminar self.bt_enviar = Button(self.raiz, text="Eliminar", width=15, command=self.eliminarInformacion) self.bt_enviar.place(x=550, y=220) self.bt_reporte = Button(self.raiz, text="Reporte", width=15, command=self.generarPDFListado) self.bt_reporte.place(x=670, y=220) #Se coloca un label del informacion self.lb_tituloPantalla = Label(self.raiz, text="INFORMACIÓN INCLUIDA", font=self.fuente) self.lb_tituloPantalla.place(x=200, y=440) self.sheet = Sheet(self.raiz, page_up_down_select_row=True, column_width=120, startup_select=(0, 1, "rows"), headers=[ 'Factura', 'Cedula', 'Tiempo uso', 'Monto', 'ID articulo' ], height=170, width=560) self.sheet.enable_bindings( ("single_select", "column_select", "row_select", "column_width_resize", "double_click_column_resize", "arrowkeys", "row_height_resize", "double_click_row_resize", "right_click_popup_menu", "rc_select", "rc_insert_column", "rc_delete_column", "rc_insert_row", "rc_delete_row")) self.sheet.place(x=20, y=480) self.cargarTodaInformacion() self.raiz.mainloop() def generarPDFListado(self): try: #Crea un objeto para la creación del PDF nombreArchivo = "ListadoPersonas.pdf" rep = reportPDF.Canvas(nombreArchivo) #Agrega el tipo de fuente Arial registerFont(TTFont('Arial', 'ARIAL.ttf')) #Crea el texto en donde se incluye la información textobject = rep.beginText() # Coloca el titulo textobject.setFont('Arial', 16) textobject.setTextOrigin(10, 800) textobject.setFillColor(colors.darkorange) textobject.textLine(text='LISTA DE FACTURA') #Escribe el titulo en el reportes rep.drawText(textobject) #consultar la informacion de la base de datos self.facturaBo = FacturaBO.FacturaBO( ) #se crea un objeto de logica de negocio informacion = self.facturaBo.consultar() #agrega los titulos de la tabla en la información consultada titulos = [ "Factura", "Cedula", "Tiempo uso", "Monto", "ID articulo" ] informacion.insert(0, titulos) #crea el objeto tabla para mostrar la información t = Table(informacion) #Le coloca el color tanto al borde de la tabla como de las celdas t.setStyle( TableStyle([("BOX", (0, 0), (-1, -1), 0.25, colors.black), ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black) ])) #para cambiar el color de las fichas de hace un ciclo según la cantidad de datos #que devuelve la base de datos data_len = len(informacion) for each in range(data_len): if each % 2 == 0: bg_color = colors.whitesmoke else: bg_color = colors.lightgrey if each == 0: #Le aplica un estilo diferente a la tabla t.setStyle( TableStyle([('BACKGROUND', (0, each), (-1, each), colors.orange)])) else: t.setStyle( TableStyle([('BACKGROUND', (0, each), (-1, each), bg_color)])) #acomoda la tabla según el espacio requerido aW = 840 aH = 780 w, h = t.wrap(aW, aH) t.drawOn(rep, 10, aH - h) #Guarda el archivo rep.save() #Abre el archivo desde comandos, puede variar en MacOs es open #subprocess.Popen("open '%s'" % nombreArchivo, shell=True) subprocess.Popen(nombreArchivo, shell=True) #Windows except IOError: msg.showerror("Error", "El archivo ya se encuentra abierto") #Limpiar def limpiarInformacion(self): self.factura.limpiar() msg.showinfo( "Acción del sistema", "La información del formulario ha sido eliminada correctamente") #envia la info def enviarInformacion(self): try: self.facturaBo = FacturaBO.FacturaBO( ) #se crea un objeto de logica de negocio if (self.insertando == True): self.facturaBo.guardar(self.factura) else: self.facturaBo.modificar(self.factura) self.cargarTodaInformacion() self.insertando = True self.factura.limpiar() #se limpia el formulario if (self.insertando == True): msg.showinfo( "Acción: Agregar factura", "La información de la factura ha sido incluida correctamente" ) # Se muestra el mensaje de que todo esta correcto else: msg.showinfo( "Acción: Modificar factura", "La información de la factura ha sido modificada correctamente" ) # Se muestra el mensaje de que todo esta correcto except Exception as e: msg.showerror( "Error", str(e) ) #si se genera algun tipo de error muestra un mensache con dicho error #eliminar la info def eliminarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() factura = (self.sheet.get_cell_data(datoSeleccionado[0], 0)) resultado = msg.askquestion( "Eliminar", "¿Desear eliminar a " + factura + " de la base de datos?") if resultado == "yes": self.factura.PK_N_FACTURA.set(factura) self.facturaBo = FacturaBO.FacturaBO() self.facturaBo.eliminar(self.factura) self.cargarTodaInformacion() self.factura.limpiar() except Exception as e: msg.showerror("Error", str(e)) #cargar toda la info def cargarTodaInformacion(self): try: self.facturaBo = FacturaBO.FacturaBO() resultado = self.facturaBo.consultar() self.sheet.set_sheet_data(resultado) except Exception as e: msg.showerror("Error", str(e)) #selecionado def cargarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() numero = (self.sheet.get_cell_data(datoSeleccionado[0], 0)) self.factura.PK_N_FACTURA.set(numero) self.facturaBo = FacturaBO.FacturaBO() self.facturaBo.consultarFactura(self.factura) self.insertando = False msg.showinfo( "Acción: Consultar factura", "La información de la factura ha sido consultada correctamente" ) except Exception as e: msg.showerror("Error", str(e)) #abrir def abrir_C(self): from mant_Cliente import Directorio_C self.raiz.destroy() Directorio_C() def abrir_A(self): from mant_Articulos import Directorio_A self.raiz.destroy() Directorio_A() def abrir_p(self): from mant_Proveedor import Directorio_P self.raiz.destroy() Directorio_P() def abrir_R(self): from mant_RelacionAP import Conexion_AP self.raiz.destroy() Conexion_AP()
class Aplicacion: def __init__(self): self.raiz = Tk() self.raiz.title ("Mantenimiento de Administración") self.raiz.geometry('900x600') menubar = Menu(self.raiz) self.raiz.config(menu=menubar) filemenu = Menu(menubar, tearoff=0) filemenu.add_command(label="Acerca de..") filemenu.add_separator() filemenu.add_command(label="Salir", command=self.raiz.quit) mantmenu = Menu(menubar, tearoff=0) mantmenu.add_command(label="Clientes", command=self.mostrar_mant_telefonos) mantmenu.add_command(label="Servidor") menubar.add_cascade(label="Archivo", menu=filemenu) menubar.add_cascade(label="Mantenimiento", menu=mantmenu) self.fuente = font.Font(weight="bold") self.persona = Persona.Persona() self.insertando = True self.lb_tituloPantalla = Label(self.raiz, text = "MANTENIMIENTO DE ADMINISTRACIÓN", font = self.fuente) self.lb_tituloPantalla.place(x = 320, y = 20) self.lb_cedula = Label(self.raiz, text = "Cedula:") self.lb_cedula.place(x = 240, y = 60) self.txt_cedula = Entry(self.raiz, textvariable=self.persona.cedula, justify="right") self.txt_cedula.place(x = 370, y = 60) self.lb_nombre = Label(self.raiz, text = "Nombre:") self.lb_nombre.place(x = 240, y = 90) self.txt_nombre = Entry(self.raiz, textvariable=self.persona.nombre, justify="right", width=30) self.txt_nombre.place(x = 370, y = 90) self.lb_apellido1 = Label(self.raiz, text = "Primer apellido:") self.lb_apellido1.place(x = 240, y = 120) self.txt_apellido1 = Entry(self.raiz, textvariable=self.persona.apellido1, justify="right", width=30) self.txt_apellido1.place(x = 370, y = 120) self.lb_apellido2 = Label(self.raiz, text = "Segundo apellido:") self.lb_apellido2.place(x = 240, y = 150) self.txt_apellido2 = Entry(self.raiz, textvariable=self.persona.apellido2, justify="right", width=30) self.txt_apellido2.place(x = 370, y = 150) self.lb_fec_nacimiento = Label(self.raiz, text = "Fecha nacimiento:") self.lb_fec_nacimiento.place(x = 240, y = 180) self.txt_fechaNacimiento = Entry(self.raiz, textvariable=self.persona.fecNacimiento, justify="right", width=30, state="readonly") self.txt_fechaNacimiento.place(x = 370, y = 180) self.bt_mostrarCalendario = Button(self.raiz, text="...", width=3, command = self.mostrarDatePicker) self.bt_mostrarCalendario.place(x = 650, y = 180) self.lb_sexo = Label(self.raiz, text = "Sexo:") self.lb_sexo.place(x = 240, y = 210) self.radio_sexoM = Radiobutton(self.raiz, text="Masculino", variable=self.persona.sexo, value=1) self.radio_sexoF = Radiobutton(self.raiz, text="Femenino", variable=self.persona.sexo, value=2) self.radio_sexoM.place(x = 370, y = 210) self.radio_sexoF.place(x = 490, y = 210) self.persona.sexo.set(1) self.lb_observaciones = Label(self.raiz, text = "Observaciones:") self.lb_observaciones.place(x = 240, y = 250) self.txt_observaciones = Entry(self.raiz, textvariable=self.persona.observaciones, justify="right", width=30) self.txt_observaciones.place(x = 370, y = 250) self.bt_borrar = Button(self.raiz, text="Limpiar", width=15, command = self.limpiarInformacion) self.bt_borrar.place(x = 370, y = 310) self.bt_enviar = Button(self.raiz, text="Enviar", width=15, command = self.enviarInformacion) self.bt_enviar.place(x = 510, y = 310) self.bt_modificar = Button(self.raiz, text="Modificar", width=15, command = self.enviarInformacion) self.bt_modificar.place(x = 650, y = 310) self.lb_tituloPantalla = Label(self.raiz, text = "INFORMACIÓN INCLUIDA", font = self.fuente) self.lb_tituloPantalla.place(x = 350, y = 355) self.lb_bloquear=Button(self.raiz,text="Bloquear",width=15,command=self.bloquear) self.lb_bloquear.place(x=650,y=330) self.desbloquear=Button(self.raiz,text="Desbloquear",width=15,command=self.desbloquear) self.lb_desbloquear.place(x=650,y=340) self.lb_iniciar_tiempo=Button(self.raiz,text="Iniciar tiempo",width=15,command=self.iniciar_tiempo) self.lb_iniciar_tiempo.place(x=650,y=350) self.lb_detener_tiempo=Button(self.raiz,text="Detener tiempo",width=15,command=self.detener_tiempo) self.lb_bloquear.place(x=650,y=360) self.lb_enviar_mensaje=Button(self.raiz,text="Enviar",width=15,command=self.enviarInformacion) self.lb_enviar_mensaje.place(x=650,y=370) self.sheet = Sheet(self.raiz, page_up_down_select_row = True, column_width = 120, startup_select = (0,1,"rows"), headers = ['Cédula', 'Nombre', 'Primer Ape.', 'Segundo Ape.', 'Fec. Nacimiento', 'Sexo'], height = 195, width = 720 ) self.sheet.enable_bindings(("single_select", "column_select", "row_select", "column_width_resize", "double_click_column_resize", #"row_width_resize", #"column_height_resize", "arrowkeys", "row_height_resize", "double_click_row_resize", "right_click_popup_menu", "rc_select", "rc_insert_column", "rc_delete_column", "rc_insert_row", "rc_delete_row")) self.sheet.place(x = 20, y = 390) self.bt_cargar = Button(self.raiz, text="Cargar", width=15, command = self.cargarInformacion) self.bt_cargar.place(x = 750, y = 385) self.bt_eliminar = Button(self.raiz, text="Eliminar", width=15, command = self.eliminarInformacion) self.bt_eliminar.place(x = 750, y = 425) self.cargarTodaInformacion() self.raiz.mainloop() def mostrar_mant_telefonos(self): mant_telefonos.MantTelefonos(self.raiz) def cargarTodaInformacion(self): try: self.personaBo = PersonoBO.PersonaBO() resultado = self.personaBo.consultar() self.sheet.set_sheet_data(resultado) except Exception as e: msg.showerror("Error", str(e)) def cargarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() cedula = (self.sheet.get_cell_data(datoSeleccionado[0],0)) self.persona.cedula.set(cedula) self.personaBo = PersonoBO.PersonaBO() self.personaBo.consultarPersona(self.persona) self.insertando = False msg.showinfo("Acción: Consultar persona", "La información de la persona ha sido consultada correctamente") except Exception as e: msg.showerror("Error", str(e)) def eliminarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() cedula = (self.sheet.get_cell_data(datoSeleccionado[0],0)) nombre = (self.sheet.get_cell_data(datoSeleccionado[0],1)) resultado = msg.askquestion("Eliminar", "¿Desear eliminar a "+nombre+" de la base de datos?") if resultado == "yes": self.persona.cedula.set(cedula) self.personaBo = PersonoBO.PersonaBO() self.personaBo.eliminar(self.persona) self.cargarTodaInformacion() self.persona.limpiar() except Exception as e: msg.showerror("Error", str(e)) def printTxt(self, texto): print(texto) def enviarInformacion(self): try: self.personaBo = PersonoBO.PersonaBO() if(self.insertando == True): self.personaBo.guardar(self.persona) else: self.personaBo.modificar(self.persona) self.cargarTodaInformacion() self.persona.limpiar() if(self.insertando == True): msg.showinfo("Acción: Agregar persona", "La información de la persona ha sido incluida correctamente") else: msg.showinfo("Acción: Agregar modificar", "La información de la persona ha sido modificada correctamente") self.insertando = True except Exception as e: msg.showerror("Error", str(e)) def limpiarInformacion(self): self.persona.limpiar() self.insertando = True msg.showinfo("Acción del sistema", "La información del formulario ha sido eliminada correctamente") def mostrarDatePicker(self): self.top = Toplevel(self.raiz) self.cal = Calendar(self.top, font="Arial 14", selectmode='day', locale='en_US', cursor="hand", year=2019, month=6, day=16) self.cal.pack(fill="both", expand=True) ttk.Button(self.top, text="Seleccionar", command = self.seleccionarFecha).pack() def seleccionarFecha(self): self.persona.fecNacimiento.set(self.cal.selection_get())
class EmailTab(tk.Frame): def __init__(self, master): self.emailHandler = EmailSheetHandler(FILENAME) tk.Frame.__init__(self, master) self.grid_columnconfigure(0, weight = 1) self.grid_rowconfigure(0, weight = 1) self.frame = ttk.Frame(self, height=450, width=400) self.frame.grid_columnconfigure(0, weight = 1) self.frame.grid_rowconfigure(0, weight = 1) self.sheet = Sheet(self.frame, page_up_down_select_row = True, #empty_vertical = 0, column_width = 300, startup_select = (0,1,"rows"), data=self.populate_sheet(), total_columns = 3, #if you want to set empty sheet dimensions at startup height = 450, #height and width arguments are optional width = 600 #For full startup arguments see DOCUMENTATION.md ) self.sheet.enable_bindings(("single_select", #"single_select" or "toggle_select" "drag_select", #enables shift click selection as well "column_drag_and_drop", "row_drag_and_drop", "column_select", "row_select", "column_width_resize", "double_click_column_resize", "arrowkeys", "row_height_resize", "double_click_row_resize", "right_click_popup_menu", "rc_select", "edit_cell")) self.sheet.extra_bindings("end_edit_cell", self.end_edit_cell) self.frame.grid(row = 0, column = 0, sticky = "nsw") self.sheet.grid(row = 0, column = 0, sticky = "nw") self.email_button_frame = ttk.Frame(self.frame, padding=(3,3,12,12), borderwidth=5, width=100, heigh=200) self.email_add_button = tk.Button(self.email_button_frame, text="Add email", command=self.add_email) self.email_merge_button = tk.Button(self.email_button_frame, text="Merge email (with file)", command=self.merge_mails) self.email_update_button = tk.Button(self.email_button_frame, text="Update file with table", command=self.email_file_update ) self.email_button_frame.grid(row=0, column=2, sticky="nswe") self.email_add_button.grid(row=1, column=1) self.email_merge_button.grid(row=2, column=1) self.email_update_button.grid(row=3, column=1) # print(self.sheet.get_sheet_data(get_index=0, get_header=0)) def end_edit_cell(self, event): print(event) print(self.sheet.get_cell_data(event[0], event[1 ])) def add_email(self): package = [] AddDialogue(package, "Add Email", "Add Email") print("Rsult: ", package) self.emailHandler.append_to_file(package) self.update_table() def email_file_update(self): self.emailHandler.update_email_file(self.sheet.get_sheet_data()) def update_table(self): data = self.populate_sheet() self.sheet.set_sheet_data(data) def merge_mails(self): file = filedialog.askopenfile().name print(file) # TODO: handle merge print(self.emailHandler.validate(file)) def populate_sheet(self): self.data = [] try: with open(FILENAME, 'r') as f: L = f.readlines() self.data = [i.strip("\n").split(",") for i in L] # for i in self.data: i.append("50") return self.data except FileNotFoundError: return self.data
class MantTelefono(): def __init__(self, parent): self.parent = parent self.raiz = Toplevel(self.parent) self.raiz.title("Mantenimiento de Telefonos") self.raiz.geometry('900x510') menubar = Menu(self.raiz) self.raiz.config(menu=menubar) filemenu = Menu(menubar, tearoff=0) filemenu.add_command(label="Acerca de..") filemenu.add_separator() filemenu.add_command(label="Salir", command=self.raiz.quit) mantmenu = Menu(menubar, tearoff=0) mantmenu.add_command(label="Personas", command=self.mostrar_mant_personas) mantmenu.add_command(label="Direcciones") menubar.add_cascade(label="Archivo", menu=filemenu) menubar.add_cascade(label="Mantenimiento", menu=mantmenu) self.fuente = font.Font(weight="bold") self.telefono = Telefono.Telefono() self.insertando = True self.nombreCliente = StringVar() self.Cliente = Cliente.Cliente() self.lb_tituloPantalla = Label(self.raiz, text="MANTENIMIENTO DE TELEFONOS", font=self.fuente) self.lb_tituloPantalla.place(x=320, y=20) self.lb_cedula = Label(self.raiz, text="Cedula:") self.lb_cedula.place(x=240, y=60) self.txt_cedula = Entry(self.raiz, textvariable=self.telefono.cedula, justify="right", width=12) self.txt_cedula.place(x=370, y=60) self.bt_consultar = Button(self.raiz, text="Consultar", width=15, command=self.consultarNombre) self.bt_consultar.place(x=512, y=60) self.lb_nombre = Label(self.raiz, text="Nombre:") self.lb_nombre.place(x=240, y=90) self.txt_nombre = Entry(self.raiz, textvariable=self.nombrePersona, justify="right", width=30) self.txt_nombre.place(x=370, y=90) self.lb_telefono = Label(self.raiz, text="Telefono:") self.lb_telefono.place(x=240, y=120) self.txt_telefono = Entry(self.raiz, textvariable=self.telefono.telefono, justify="right", width=30) self.txt_telefono.place(x=370, y=120) self.lb_descripcion = Label(self.raiz, text="Descripción:") self.lb_descripcion.place(x=240, y=150) self.txt_descripcion = Entry(self.raiz, textvariable=self.telefono.descripcion, justify="right", width=30) self.txt_descripcion.place(x=370, y=150) self.bt_borrar = Button(self.raiz, text="Limpiar", width=15, command=self.limpiarInformacion) self.bt_borrar.place(x=370, y=180) self.bt_enviar = Button(self.raiz, text="Enviar", width=15, command=self.enviarInformacion) self.bt_enviar.place(x=510, y=180) self.lb_tituloPantalla = Label(self.raiz, text="INFORMACIÓN INCLUIDA", font=self.fuente) self.lb_tituloPantalla.place(x=350, y=230) self.sheet = Sheet( self.raiz, page_up_down_select_row=True, column_width=120, startup_select=(0, 1, "rows"), headers=['Cédula', 'Nombre', 'Telefono', 'Descripción'], height=195, width=720) self.sheet.enable_bindings( ("single_select", "column_select", "row_select", "column_width_resize", "double_click_column_resize", "arrowkeys", "row_height_resize", "double_click_row_resize", "right_click_popup_menu", "rc_select", "rc_insert_column", "rc_delete_column", "rc_insert_row", "rc_delete_row")) self.sheet.place(x=20, y=260) self.bt_cargar = Button(self.raiz, text="Cargar", width=15, command=self.cargarInformacion) self.bt_cargar.place(x=750, y=255) self.bt_eliminar = Button(self.raiz, text="Eliminar", width=15, command=self.eliminarInformacion) self.bt_eliminar.place(x=750, y=295) self.cargarTodaInformacion() self.parent.withdraw() self.raiz.protocol("WM_DELETE_WINDOW", self.on_closing) def enviarInformacion(self): try: self.telefonoBo = TelefonoBO.TelefonoBO() if (self.insertando == True): self.telefonoBo.guardar(self.telefono) else: self.telefonoBo.modificar(self.telefono) self.cargarTodaInformacion() self.telefono.limpiar() self.nombreCliente.set("") if (self.insertando == True): msg.showinfo( "Acción: Agregar teléfono", "La información del teléfono ha sido incluida correctamente" ) else: msg.showinfo( "Acción: Modificar teléfono", "La información del teléfono ha sido modificada correctamente" ) self.insertando = True except Exception as e: msg.showerror("Error", str(e)) def limpiarInformacion(self): self.telefono.limpiar() self.nombreCliente.set("") self.insertando = True msg.showinfo( "Acción del sistema", "La información del formulario ha sido eliminada correctamente") def consultarNombre(self): try: self.ClienteBo = PersonoBO.ClienteBO() self.Cliente.cedula.set(self.telefono.cedula.get()) self.ClienteBo.consultarCliente(self.Cliente) if self.Cliente.nombre.get() == "": self.nombreCliente = "No existe el Cliente " else: self.nombreCliente.set(self.Cliente.nombre.get() + " " + self.Cliente.apellido1.get() + " " + self.Cliente.apellido2.get()) except Exception as e: msg.showerror("Error", str(e)) def cargarTodaInformacion(self): try: self.telefonoBo = TelefonoBO.TelefonoBO() resultado = self.telefonoBo.consultar() self.sheet.set_sheet_data(resultado) except Exception as e: msg.showerror("Error", str(e)) def cargarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() telefono = (self.sheet.get_cell_data(datoSeleccionado[0], 2)) self.telefono.telefono.set(telefono) self.telefonoBo = TelefonoBO.TelefonoBO() self.telefonoBo.consultarTelefono(self.telefono) self.consultarNombre() self.insertando = False msg.showinfo( "Acción: Consultar teléfono", "La información del teléfono ha sido consultada correctamente") except Exception as e: msg.showerror("Error", str(e)) def eliminarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() telefono = (self.sheet.get_cell_data(datoSeleccionado[0], 2)) nombre = (self.sheet.get_cell_data(datoSeleccionado[0], 1)) resultado = msg.askquestion( "Eliminar", "¿Desear eliminar el telefono " + telefono + " de " + nombre + " de la base de datos?") if resultado == "yes": self.telefono.telefono.set(telefono) self.telefonoBo = TelefonoBO.TelefonoBO() self.telefonoBo.eliminar(self.telefono) self.cargarTodaInformacion() self.telefono.limpiar() self.nombreCliente.set("") except Exception as e: msg.showerror("Error", str(e)) def mostrar_mant_cliente(self): self.parent.deiconify() self.raiz.destroy() def on_closing(self): self.parent.destroy()
class Directorio_C: def __init__(self): #Pantalla self.raiz = Tk() self.raiz.title("Mantenimiento de Clientes") self.raiz.geometry('600x630') #Barra menu menubar = Menu(self.raiz) self.raiz.config(menu=menubar) filemenu = Menu(menubar, tearoff=0) filemenu.add_command(label="Salir", command=self.raiz.quit) mantmenu = Menu(menubar, tearoff=0) mantmenu.add_command(label="Facturas", command=self.abrir_F) mantmenu.add_command(label="Articulos", command=self.abrir_A) mantmenu.add_command(label="Proveedores", command=self.abrir_p) mantmenu.add_command(label="Conexion", command=self.abrir_R) menubar.add_cascade(label="Archivo", menu=filemenu) menubar.add_cascade(label="Mantenimiento", menu=mantmenu) #Objecto cliente self.fuente = font.Font(weight="bold") self.cliente = Cliente.Cliente() self.insertando = True #Titulo self.lb_tituloPantalla = Label(self.raiz, text="MANTENIMIENTO DE CLIENTES", font=self.fuente) self.lb_tituloPantalla.place(x=180, y=20) #Formulario #Cedula self.lb_cedula = Label(self.raiz, text="Cedula:") self.lb_cedula.place(x=100, y=60) self.txt_cedula = Entry(self.raiz, textvariable=self.cliente.PK_CEDULA, justify="right") self.txt_cedula.place(x=230, y=60) #Nombre self.lb_nombre = Label(self.raiz, text="Nombre:") self.lb_nombre.place(x=100, y=90) self.txt_nombre = Entry(self.raiz, textvariable=self.cliente.NOMBRE_C, justify="right", width=30) self.txt_nombre.place(x=230, y=90) #Apellido 1 self.lb_apellido1 = Label(self.raiz, text="Primer apellido:") self.lb_apellido1.place(x=100, y=120) self.txt_apellido1 = Entry(self.raiz, textvariable=self.cliente.APELLIDO_1, justify="right", width=30) self.txt_apellido1.place(x=230, y=120) #Apellido 2 self.lb_apellido2 = Label(self.raiz, text="Segundo apellido:") self.lb_apellido2.place(x=100, y=150) self.txt_apellido2 = Entry(self.raiz, textvariable=self.cliente.APELLIDO_2, justify="right", width=30) self.txt_apellido2.place(x=230, y=150) #Fecha nacimiento self.lb_fec_nacimiento = Label(self.raiz, text="Fecha nacimiento:") self.lb_fec_nacimiento.place(x=100, y=180) self.txt_fechaNacimiento = Entry( self.raiz, textvariable=self.cliente.FECHA_NACIMIENTO, justify="right", width=30, state="readonly") self.txt_fechaNacimiento.place(x=230, y=180) self.bt_mostrarCalendario = Button(self.raiz, text="...", width=3, command=self.mostrarDatePicker) self.bt_mostrarCalendario.place(x=510, y=180) #Direccion self.lb_direccion = Label(self.raiz, text="Direccion:") self.lb_direccion.place(x=100, y=210) self.txt_direccion = Entry(self.raiz, textvariable=self.cliente.DIRECCION, justify="right", width=30) self.txt_direccion.place(x=230, y=210) #Observaciones self.lb_observaciones = Label(self.raiz, text="Observaciones:") self.lb_observaciones.place(x=100, y=240) self.txt_observaciones = Entry(self.raiz, textvariable=self.cliente.OBSERVACIONES, justify="right", width=30) self.txt_observaciones.place(x=230, y=240) #Telefono 1 self.lb_telefono_1 = Label(self.raiz, text="Telefono Principal:") self.lb_telefono_1.place(x=100, y=270) self.txt_telefono_1 = Entry(self.raiz, textvariable=self.cliente.TELEFONO_1, justify="right", width=30) self.txt_telefono_1.place(x=230, y=270) #Telefono 2 self.lb_telefono_2 = Label(self.raiz, text="Telefono segundario:") self.lb_telefono_2.place(x=100, y=300) self.txt_telefono_2 = Entry(self.raiz, textvariable=self.cliente.TELEFONO_2, justify="right", width=30) self.txt_telefono_2.place(x=230, y=300) #Boton Limpiar self.bt_borrar = Button(self.raiz, text="Limpiar", width=15, command=self.limpiarInformacion) self.bt_borrar.place(x=70, y=340) #Boton Enviar self.bt_enviar = Button(self.raiz, text="Enviar", width=15, command=self.enviarInformacion) self.bt_enviar.place(x=190, y=340) #Boton Cargar self.bt_borrar = Button(self.raiz, text="Cargar", width=15, command=self.cargarInformacion) self.bt_borrar.place(x=310, y=340) #Boton Eliminar self.bt_enviar = Button(self.raiz, text="Eliminar", width=15, command=self.eliminarInformacion) self.bt_enviar.place(x=430, y=340) self.bt_reporte = Button(self.raiz, text="Reporte", width=15, command=self.generarPDFListado) self.bt_reporte.place(x=550, y=340) #label del informacion self.lb_tituloPantalla = Label(self.raiz, text="INFORMACIÓN INCLUIDA", font=self.fuente) self.lb_tituloPantalla.place(x=190, y=400) #cuadro excel self.sheet = Sheet(self.raiz, page_up_down_select_row=True, column_width=120, startup_select=(0, 1, "rows"), headers=[ 'Cédula', 'Nombre', 'Primer Ape.', 'Segundo Ape.', 'Fec. Nacimiento', 'Direccion', 'Observaciones', 'Telefono 1', 'Telefono 2' ], height=170, width=560) self.sheet.enable_bindings( ("single_select", "column_select", "row_select", "column_width_resize", "double_click_column_resize", "arrowkeys", "row_height_resize", "double_click_row_resize", "right_click_popup_menu", "rc_select", "rc_insert_column", "rc_delete_column", "rc_insert_row", "rc_delete_row")) self.sheet.place(x=20, y=440) #toda informacion self.cargarTodaInformacion() #cierre de raiz self.raiz.mainloop() def generarPDFListado(self): try: #Crea un objeto para la creación del PDF nombreArchivo = "ListadoPersonas.pdf" rep = reportPDF.Canvas(nombreArchivo) #Agrega el tipo de fuente Arial registerFont(TTFont('Arial', 'ARIAL.ttf')) #Crea el texto en donde se incluye la información textobject = rep.beginText() # Coloca el titulo textobject.setFont('Arial', 16) textobject.setTextOrigin(10, 800) textobject.setFillColor(colors.darkorange) textobject.textLine(text='LISTA DE CLIENTES') #Escribe el titulo en el reportes rep.drawText(textobject) #consultar la informacion de la base de datos self.clienteBo = ClienteBO.ClienteBO( ) #se crea un objeto de logica de negocio informacion = self.clienteBo.consultar() #agrega los titulos de la tabla en la información consultada titulos = [ "Cédula", "Nombre", "Primer Ape.", "Segundo Ape.", "Fec. Nacimiento", "Direccion", "Observaciones", "Telefono 1", "Telefono 2" ] informacion.insert(0, titulos) #crea el objeto tabla para mostrar la información t = Table(informacion) #Le coloca el color tanto al borde de la tabla como de las celdas t.setStyle( TableStyle([("BOX", (0, 0), (-1, -1), 0.25, colors.black), ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black) ])) #para cambiar el color de las fichas de hace un ciclo según la cantidad de datos #que devuelve la base de datos data_len = len(informacion) for each in range(data_len): if each % 2 == 0: bg_color = colors.whitesmoke else: bg_color = colors.lightgrey if each == 0: #Le aplica un estilo diferente a la tabla t.setStyle( TableStyle([('BACKGROUND', (0, each), (-1, each), colors.orange)])) else: t.setStyle( TableStyle([('BACKGROUND', (0, each), (-1, each), bg_color)])) #acomoda la tabla según el espacio requerido aW = 840 aH = 780 w, h = t.wrap(aW, aH) t.drawOn(rep, 10, aH - h) #Guarda el archivo rep.save() #Abre el archivo desde comandos, puede variar en MacOs es open #subprocess.Popen("open '%s'" % nombreArchivo, shell=True) subprocess.Popen(nombreArchivo, shell=True) #Windows except IOError: msg.showerror("Error", "El archivo ya se encuentra abierto") #calendario def mostrarDatePicker(self): #ventana segundaria self.top = Toplevel(self.raiz) self.cal = Calendar(self.top, font="Arial 14", selectmode='day', locale='en_US', cursor="hand1", year=2019, month=6, day=16) self.cal.pack(fill="both", expand=True) ttk.Button(self.top, text="Seleccionar", command=self.seleccionarFecha).pack() #Selecciona la fecha def seleccionarFecha(self): self.cliente.FECHA_NACIMIENTO.set(self.cal.selection_get()) self.top.destroy() #Limpiar def limpiarInformacion(self): self.cliente.limpiar() msg.showinfo( "Acción del sistema", "La información del formulario ha sido eliminada correctamente") #envia la info def enviarInformacion(self): try: self.clienteBo = ClienteBO.ClienteBO() if (self.insertando == True): self.clienteBo.guardar(self.cliente) else: self.clienteBo.modificar(self.cliente) self.cargarTodaInformacion() self.insertando = True self.cliente.limpiar() if (self.insertando == True): msg.showinfo( "Acción: Agregar cliente", "La información del cliente ha sido incluida correctamente" ) else: msg.showinfo( "Acción: modificar cliente", "La información del cliente ha sido modificada correctamente" ) except Exception as e: msg.showerror("Error", str(e)) #eliminar la info def eliminarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() cedula = (self.sheet.get_cell_data(datoSeleccionado[0], 0)) nombre = (self.sheet.get_cell_data(datoSeleccionado[0], 1)) resultado = msg.askquestion( "Eliminar", "¿Desear eliminar a " + nombre + " de la base de datos?") if resultado == "yes": self.cliente.PK_CEDULA.set(cedula) self.clienteBo = ClienteBO.ClienteBO() self.clienteBo.eliminar(self.cliente) self.cliente.limpiar() except Exception as e: msg.showerror("Error", str(e)) self.cargarTodaInformacion( ) #refrescar la pagina especialmente para llaves foraneas relacionales #cargar toda la info def cargarTodaInformacion(self): try: self.clienteBo = ClienteBO.ClienteBO() resultado = self.clienteBo.consultar() self.sheet.set_sheet_data(resultado) except Exception as e: msg.showerror("Error", str(e)) #selecionado def cargarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() cedula = (self.sheet.get_cell_data(datoSeleccionado[0], 0)) self.cliente.PK_CEDULA.set(cedula) self.clienteBo = ClienteBO.ClienteBO() self.clienteBo.consultarCliente(self.cliente) self.insertando = False msg.showinfo( "Acción: Consultar cliente", "La información del cliente ha sido consultada correctamente") except Exception as e: msg.showerror("Error", str(e)) #abrir def abrir_F(self): from mant_Factura import Directorio_F self.raiz.destroy() Directorio_F() def abrir_A(self): from mant_Articulos import Directorio_A self.raiz.destroy() Directorio_A() def abrir_p(self): from mant_Proveedor import Directorio_P self.raiz.destroy() Directorio_P() def abrir_R(self): from mant_RelacionAP import Conexion_AP self.raiz.destroy() Conexion_AP()
class product_demo(tk.Tk): def __init__(self): tk.Tk.__init__(self) self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) self.frame = tk.Frame(self) self.fill_data_from_db() self.frame.grid_columnconfigure(0, weight=1) self.frame.grid_rowconfigure(0, weight=1) self.sheet = Sheet( self.frame, page_up_down_select_row=True, # empty_vertical = 0, headers=headers, column_width=120, startup_select=(0, 1, "rows"), data=data, height=500, # height and width arguments are optional width=500 # For full startup arguments see DOCUMENTATION.md ) self.sheet.enable_bindings(( "single_select", # "single_select" or "toggle_select" "drag_select", # enables shift click selection as well "column_drag_and_drop", "row_drag_and_drop", "column_select", "row_select", "column_width_resize", "double_click_column_resize", # "row_width_resize", # "column_height_resize", "arrowkeys", "row_height_resize", "double_click_row_resize", "right_click_popup_menu", "rc_select", # "rc_insert_column", # "rc_delete_column", # "rc_insert_row", "rc_delete_row", # "hide_columns", "copy", # "cut", # "paste", # "delete", "undo", "edit_cell")) self.frame.grid(row=0, column=0, sticky="nswe") self.sheet.grid(row=0, column=0, sticky="nswe") # __________ DISPLAY SUBSET OF COLUMNS __________ self.sheet.display_subset_of_columns(indexes=[0, 1, 2], enable=True) # __________ BINDING A FUNCTIONS TO USER ACTIONS __________ self.sheet.extra_bindings([("end_edit_cell", self.end_edit_cell), ("begin_rc_delete_row", self.row_delete)]) # __________ GETTING FULL SHEET DATA __________ # self.all_data = self.sheet.get_sheet_data() # __________ GETTING CELL DATA __________ # print (self.sheet.get_cell_data(0, 0)) # __________ GETTING ROW DATA __________ # print (self.sheet.get_row_data(0)) # only accessible by index # __________ GETTING COLUMN DATA __________ # print (self.sheet.get_column_data(0)) # only accessible by index def end_edit_cell(self, event): print("cell edited") print(event) PRODUCT.query.filter_by(**{ "pid": self.sheet.get_cell_data(event[0], 0) }).update( {headers[event[1]]: self.sheet.get_cell_data(event[0], event[1])}) db_session.commit() def row_delete(self, event): print("row deleted") print(event) print({"pid": self.sheet.get_cell_data(event[1][0], 0)}) PRODUCT.query.filter_by(**{ "pid": self.sheet.get_cell_data(event[1][0], 0) }).delete() db_session.commit() def fill_data_from_db(self): data.clear() ps = PRODUCT.query.all() k = [[i.to_dict(rules=('-ORDERITEM', )).get(z) for z in headers] for i in ps] data.extend(k)
class Content: def __init__(self, app: tk.Tk, login: LoginForm, toolbar: Toolbar, menubar: Menubar, impartus: Impartus): self.app = app self.login = login self.toolbar = toolbar self.menubar = menubar self.impartus = impartus conf = Config.load(ConfigType.IMPARTUS) self.content_font = conf.get('content_font').get(platform.system()) self.content_font_size = conf.get('content_font_size') self.header_font = conf.get('header_font').get(platform.system()) self.header_font_size = conf.get('header_font_size') self.frame_content = None self.sheet = None self.videos = None self.video_slide_mapping = None self.expected_real_paths_differ = False self.all_captions_found = True self.offline_video_ttid_mapping = None # sort options self.sort_by = None self.sort_order = None # threads for downloading videos / slides. self.threads = None self.logger = logging.getLogger(self.__class__.__name__) def _init_content(self): if self.frame_content: self.frame_content.destroy() self.frame_content = self.add_content_frame(self.app) self.sheet = Sheet( self.frame_content, header_font=(self.header_font, self.header_font_size, "bold"), font=(self.content_font, self.content_font_size, "normal"), align='w', row_height="1", # str value for row height in number of lines. row_index_align="w", auto_resize_default_row_index=False, row_index_width=40, header_align='center', empty_horizontal=0, empty_vertical=0, ) self.sheet.enable_bindings(( "single_select", "column_select", "column_width_resize", "double_click_column_resize", "edit_cell", "copy", )) self.sheet.grid(row=0, column=0, sticky='nsew') self.set_headers() self.set_display_columns() self.frame_content.columnconfigure(0, weight=1) self.frame_content.rowconfigure(0, weight=1) self.sheet.extra_bindings('column_select', self.sort_table) self.sheet.extra_bindings('cell_select', self.on_click_button_handler) # sort options self.sort_by = None self.sort_order = None # threads for downloading videos / slides. self.threads = dict() def add_content_frame(self, anchor) -> tk.Frame: # noqa frame_content = tk.Frame(anchor, padx=0, pady=0) frame_content.grid(row=2, column=0, sticky='nsew') return frame_content def set_headers(self, sort_by=None, sort_order=None): """ Set the table headers. """ # set column title to reflect sort status headers = list() for name, value in Columns.display_columns.items(): if value.get('sortable'): if name == sort_by: sort_icon = Icons.SORT_DESC if sort_order == 'desc' else Icons.SORT_ASC else: sort_icon = Icons.UNSORTED text = '{} {}'.format(value['display_name'], sort_icon) else: text = value['display_name'] if value.get('editable'): text = '{} {}'.format(Icons.EDITABLE, text) headers.append(text) self.sheet.headers(headers) def set_display_widgets(self): """ Create the table/sheet. Fill in the data for table content, Set the buttons and their states. """ self.fetch_content() self.fill_content() def on_click_button_handler(self, args): """ On click handler for all the buttons, calls the corresponding function as defined by self.button_columns """ (event, row, col) = args real_col = self.get_real_col(col) self.sheet.highlight_rows(rows=[row], redraw=False) self.sheet.highlight_columns(columns=[col], redraw=False) # is subject field col_name = Columns.column_names[real_col] if Columns.all_columns[col_name].get('editable'): old_value = self.sheet.get_cell_data(row, real_col) self.sheet.create_text_editor(row=row, column=real_col, text=old_value, set_data_ref_on_destroy=False, binding=partial( self.end_edit_cell, old_value)) # not a button. if Columns.all_columns[col_name].get('type') != 'button': self.sheet.refresh() return state_button_col_name, state_button_col_num = self.get_state_button( col_name) state = self.sheet.get_cell_data(row, state_button_col_num) if state == 'False': # data read from sheet is all string. self.sheet.refresh() return # disable the button if it is one of the Download buttons, to prevent a re-download. if col_name == 'download_video': self.sheet.set_cell_data(row, real_col, Icons.PAUSE_DOWNLOAD, redraw=False) elif col_name == 'download_slides': cs = Config.load( ConfigType.COLORSCHEMES)[Variables().colorscheme_var().get()] self.disable_button(row, real_col, cs) func_name = Columns.all_columns[col_name]['function'] getattr(self, func_name)(row, real_col) def get_state_button(self, button_name): # noqa if Columns.all_columns[button_name].get('state'): state_col_name = Columns.all_columns[button_name].get('state') state_col_number = Columns.column_names.index(state_col_name) return state_col_name, state_col_number else: return None, None def end_edit_cell(self, old_value, event=None): row, col = (event[0], event[1]) new_value = self.sheet.get_text_editor_value( event, r=row, c=col, set_data_ref_on_destroy=True, move_down=False, redraw=True, recreate=True) # empty value or escape pressed. if not new_value or new_value == '': return # no changes made. if old_value == new_value: return col_name = Columns.column_names[self.get_real_col(col)] columns_item = Columns.data_columns[col_name] orig_values_col_name = columns_item.get('original_values_col') original_value = self.sheet.get_cell_data( row, Columns.column_names.index(orig_values_col_name)) for i, data in enumerate( self.sheet.get_column_data( Columns.column_names.index(orig_values_col_name))): if data == original_value: self.sheet.set_cell_data(i, col, new_value) self.expected_real_paths_differ = True Mappings.update_mappings(orig_values_col_name, original_value, new_value) self.reset_column_sizes() self.sheet.deselect(row=row, column=col, redraw=False) self.sheet.refresh() if self.expected_real_paths_differ or not self.all_captions_found: self.toolbar.auto_organize_button.config(state='normal') self.menubar.actions_menu.entryconfig(Labels.AUTO_ORGANIZE, state='normal') def reset_column_sizes(self): """ Adjust column sizes after data has been filled. """ # resize cells self.sheet.set_all_column_widths() # reset column widths to fill the screen pad = 5 column_widths = self.sheet.get_column_widths() table_width = self.sheet.RI.current_width + sum(column_widths) + len( column_widths) + pad diff_width = self.frame_content.winfo_width() - table_width # adjust extra width only to top N data columns n = 3 column_states = [ v.get() for v in Variables().display_columns_vars().values() ] count = 0 for k, v in enumerate(column_states): if Columns.column_names[k] == 'downloaded': break count += v # range(0..count) is all data columns. data_col_widths = {k: v for k, v in enumerate(column_widths[:count])} top_n_cols = sorted(data_col_widths, key=data_col_widths.get, reverse=True)[:n] for i in top_n_cols: self.sheet.column_width(i, column_widths[i] + diff_width // n) def get_index(self, row): """ Find the values stored in the hidden column named 'Index', given a row record. In case the row value has been updated due to sorting the table, Index field helps identify the new location of the associated record. """ # find where is the Index column index_col = Columns.column_names.index('index') # original row value as per the index column return int(self.sheet.get_cell_data(row, index_col)) def get_row_after_sort(self, index_value): # find the new correct location of the row_index col_index = Columns.column_names.index('index') col_data = self.sheet.get_column_data(col_index) return col_data.index(str(index_value)) def progress_bar_text(self, value, processed=False): """ return progress bar text, calls the unicode/ascii implementation. """ conf = Config.load(ConfigType.IMPARTUS) if conf.get('progress_bar') == 'unicode': text = self.progress_bar_text_unicode(value) else: text = self.progress_bar_text_ascii(value) pad = ' ' * 2 if 0 < value < 100: percent_text = '{:2d}%'.format(value) status = percent_text elif value == 0: status = '{}{}{}'.format(pad, Icons.VIDEO_NOT_DOWNLOADED, pad) else: # 100 % if processed: status = '{}{}{}'.format(pad, Icons.VIDEO_DOWNLOADED, pad) else: status = '{}{}{}'.format(pad, Icons.VIDEO_PROCESSING, pad) return '{} {}{}'.format(text, status, pad) def progress_bar_text_ascii(self, value): # noqa """ progress bar implementation with ascii characters. """ bars = 50 ascii_space = " " if value > 0: progress_text = '{}'.format('❘' * (value * bars // 100)) empty_text = '{}'.format(ascii_space * (bars - len(progress_text))) full_text = '{}{} '.format(progress_text, empty_text) else: full_text = '{}'.format(ascii_space * bars) return full_text def progress_bar_text_unicode(self, value): # noqa """ progress bar implementation with unicode blocks. """ chars = ['▏', '▎', '▍', '▌', '▋', '▊', '▉', '█'] # 1 full unicode block = 8 percent values # => 13 unicode blocks needed to represent counter 100. unicode_space = ' ' if value > 0: # progress_text: n characters, empty_text: 13-n characters progress_text = '{}{}'.format(chars[-1] * (value // 8), chars[value % 8]) empty_text = '{}'.format(unicode_space * (13 - len(progress_text))) full_text = '{}{}'.format(progress_text, empty_text) else: # all 13 unicode whitespace. full_text = '{} '.format(unicode_space * 13) return full_text def progress_bar_callback(self, count, row, col, processed=False): """ Callback function passed to the backend, where it computes the download progress. Every time the function is called, it will update the progress bar value. """ updated_row = self.get_row_after_sort(row) new_text = self.progress_bar_text(count, processed) if new_text != self.sheet.get_cell_data(updated_row, col): self.sheet.set_cell_data(updated_row, col, new_text, redraw=True) def get_real_col(self, col): # noqa """ with configurable column list, the col number returned by tksheet may not be the same as column no from self.all_columns/self.display_columns. Use self.display_column_vars to identify and return the correct column. """ # find n-th visible column, where n=col i = 0 for c, state in enumerate(Variables().display_columns_vars().values()): if state.get() == 1: if i == col: return c i += 1 def fetch_content(self): self.videos = dict() self.video_slide_mapping = dict() self.expected_real_paths_differ = False self.offline_video_ttid_mapping = None root_url = self.login.url_box.get() subject_dicts = self.impartus.get_subjects(root_url) has_flipped_lectures = False for subject_dict in subject_dicts: videos_by_subject = self.impartus.get_lectures( root_url, subject_dict) flipped_videos_by_subject = self.impartus.get_flipped_lectures( root_url, subject_dict) if len(flipped_videos_by_subject): has_flipped_lectures = True all_videos_by_subject = [ *videos_by_subject, *flipped_videos_by_subject ] slides = self.impartus.get_slides(root_url, subject_dict) mapping_dict = self.impartus.map_slides_to_videos( all_videos_by_subject, slides) for key, val in mapping_dict.items(): self.video_slide_mapping[key] = val self.videos[subject_dict.get('subjectId')] = { x['ttid']: x for x in all_videos_by_subject } state = 'normal' if has_flipped_lectures else 'disabled' self.toolbar.flipped_video_quality_dropdown.configure(state=state) self.menubar.main_menu.entryconfig(Labels.VIDEO, state=state) def fill_content(self): # A mapping dict containing previously downloaded, and possibly moved around / renamed videos. # extract their ttid and map those to the correct records, to avoid forcing the user to re-download. self.offline_video_ttid_mapping = self.impartus.get_mkv_ttid_map() row = 0 sheet_rows = list() for subject_id, videos in self.videos.items(): for ttid, video_metadata in videos.items(): video_metadata = Utils.add_new_fields(video_metadata, self.video_slide_mapping) video_path = self.impartus.get_mkv_path(video_metadata) if not os.path.exists(video_path): # or search from the downloaded videos, using video_ttid_map video_path_moved = self.offline_video_ttid_mapping.get( str(ttid)) if video_path_moved: # For now, use the offline path if a video found. Also set the flag to enable move/rename button video_path = video_path_moved self.expected_real_paths_differ = True captions_path = self.impartus.get_captions_path(video_metadata) if not os.path.exists(captions_path): self.all_captions_found = False slides_path = self.impartus.get_slides_path(video_metadata) video_exists_on_disk = video_path and os.path.exists( video_path) slides_exist_on_server = self.video_slide_mapping.get(ttid) slides_exist_on_disk, slides_path = self.impartus.slides_exist_on_disk( slides_path) metadata = { 'video_metadata': video_metadata, 'video_path': video_path, 'video_exists_on_disk': video_exists_on_disk, 'slides_exist_on_server': slides_exist_on_server, 'slides_exist_on_disk': slides_exist_on_disk, 'slides_url': self.video_slide_mapping.get(ttid), 'slides_path': slides_path, 'captions_path': captions_path, } row_items = list() button_states = list() # data items for col, (key, item) in enumerate(Columns.all_columns.items()): text = '' if item['type'] == 'data': text = video_metadata[key] # title case if item.get('title_case'): text = " ".join(text.splitlines()).strip().title() elif item['type'] == 'auto': text = row elif item['type'] == 'progressbar': if video_exists_on_disk: text = self.progress_bar_text(100, processed=True) else: text = self.progress_bar_text(0) elif item['type'] == 'button': button_states.append( self.get_button_state(key, video_exists_on_disk, slides_exist_on_server, slides_exist_on_disk)) text = item.get('text') elif item['type'] == 'button_state': text = button_states.pop(0) elif item['type'] == 'metadata': text = metadata elif item['type'] == 'original_value': text = video_metadata[key] row_items.append(text) row += 1 sheet_rows.append(row_items) self._init_content() self.sheet.insert_rows(sheet_rows, idx='end') self.reset_column_sizes() self.decorate() # update button status self.set_button_status(redraw=True) self.sheet.grid(row=0, column=0, sticky='nsew') def sort_table(self, args): """ Sorts the table content. """ col = args[1] real_col = self.get_real_col(col) self.sheet.deselect("all") col_name = Columns.column_names[real_col] if not Columns.all_columns[col_name].get('sortable'): return sort_by = col_name if sort_by == self.sort_by: sort_order = 'asc' if self.sort_order == 'desc' else 'desc' else: sort_order = 'desc' self.sort_by = sort_by self.sort_order = sort_order reverse = True if sort_order == 'desc' else False table_data = self.sheet.get_sheet_data() table_data.sort(key=lambda x: x[real_col], reverse=reverse) self.set_headers(sort_by, sort_order) self.set_button_status() self.sheet.refresh() def save_captions_if_needed(self, video_metadata, root_url, captions_path): chat_msgs = self.impartus.get_chats(video_metadata, root_url) date_format = "%Y-%m-%d %H:%M:%S" start_epoch = int( datetime.strptime(video_metadata['startTime'], date_format).timestamp()) try: vtt_content = Captions.get_vtt(chat_msgs, start_epoch) Captions.save_vtt(vtt_content, captions_path) except CaptionsNotFound as ex: self.logger.info( "no lecture chat found for {}".format(captions_path)) return return True def _download_video(self, video_metadata, filepath, captions_path, root_url, row, col, pause_ev, resume_ev): # noqa """ Download a video in a thread. Update the UI upon completion. """ # create a new Impartus session reusing existing token. imp = Impartus(self.impartus.token) pb_col = Columns.column_names.index('downloaded') # # voodoo alert: # It is possible for user to sort the table while download is in progress. # In such a case, the row index supplied to the function call won't match the row index # required to update the correct progressbar/open/play buttons, which now exists at a new # location. # The hidden column index keeps the initial row index, and remains unchanged. # Use row_index to identify the new correct location of the progress bar. row_index = self.get_index(row) imp.process_video(video_metadata, filepath, root_url, pause_ev, resume_ev, partial(self.progress_bar_callback, row=row_index, col=pb_col), video_quality=Variables().lecture_quality_var()) # also download lecture chats, and create a webvtt subtitles file. self.save_captions_if_needed(video_metadata, root_url, captions_path) # download complete, enable open / play buttons updated_row = self.get_row_after_sort(row_index) # update progress bar status to complete. self.progress_bar_callback(row=row_index, col=pb_col, count=100, processed=True) self.sheet.set_cell_data(updated_row, Columns.column_names.index('download_video'), Icons.DOWNLOAD_VIDEO) self.disable_button(updated_row, Columns.column_names.index('download_video')) # enable buttons. self.enable_button(updated_row, Columns.column_names.index('open_folder')) self.enable_button(updated_row, Columns.column_names.index('play_video')) def add_slides(self, row, col): # noqa conf = Config.load(ConfigType.IMPARTUS) file_types = [(str(ext).upper(), '*.{}'.format(ext)) for ext in conf.get('allowed_ext')] filepaths = tkinter.filedialog.askopenfilenames(filetypes=file_types) data = self.read_metadata(row) slides_folder_path = os.path.dirname(data.get('video_path')) for filepath in filepaths: shutil.copy(filepath, slides_folder_path) def pause_resume_button_click(self, row, col, pause_event, resume_event): row_index = self.get_index(row) updated_row = self.get_row_after_sort(row_index) if pause_event.is_set(): self.sheet.set_cell_data(updated_row, col, Icons.PAUSE_DOWNLOAD, redraw=True) resume_event.set() pause_event.clear() else: self.sheet.set_cell_data(updated_row, col, Icons.RESUME_DOWNLOAD, redraw=True) pause_event.set() resume_event.clear() def download_video(self, row, col): """ callback function for Download button. Creates a thread to download the request video. """ data = self.read_metadata(row) video_metadata = data.get('video_metadata') filepath = data.get('video_path') captions_path = data.get('captions_path') root_url = self.login.url_box.get() real_row = self.get_index(row) if self.threads.get(real_row): pause_ev = self.threads.get(real_row)['pause_event'] resume_ev = self.threads.get(real_row)['resume_event'] self.pause_resume_button_click(row, col, pause_ev, resume_ev) return from threading import Event pause_event = Event() resume_event = Event() # note: args is a tuple. thread = threading.Thread(target=self._download_video, args=( video_metadata, filepath, captions_path, root_url, row, col, pause_event, resume_event, )) self.threads[real_row] = { 'thread': thread, 'pause_event': pause_event, 'resume_event': resume_event, } thread.start() def _download_slides(self, ttid, file_url, filepath, root_url, row): """ Download a slide doc in a thread. Update the UI upon completion. """ # create a new Impartus session reusing existing token. imp = Impartus(self.impartus.token) if imp.download_slides(ttid, file_url, filepath, root_url): # download complete, enable show slides buttons self.enable_button(row, Columns.column_names.index('show_slides')) else: tkinter.messagebox.showerror( 'Error', 'Error downloading slides, see console logs for details.') self.enable_button(row, Columns.column_names.index('download_slides')) def download_slides(self, row, col): # noqa """ callback function for Download button. Creates a thread to download the request video. """ data = self.read_metadata(row) video_metadata = data.get('video_metadata') ttid = video_metadata['ttid'] file_url = data.get('slides_url') filepath = data.get('slides_path') root_url = self.login.url_box.get() # note: args is a tuple. thread = threading.Thread(target=self._download_slides, args=( ttid, file_url, filepath, root_url, row, )) # self.threads.append(thread) thread.start() def read_metadata(self, row): """ We saved a hidden column 'metadata' containing metadata for each record. Extract it, and eval it as python dict. """ metadata_col = Columns.column_names.index('metadata') data = self.sheet.get_cell_data(row, metadata_col) return ast.literal_eval(data) def open_folder(self, row, col): # noqa """ fetch video_path's folder from metadata column's cell and open system launcher with it. """ data = self.read_metadata(row) video_folder_path = os.path.dirname(data.get('video_path')) Utils.open_file(video_folder_path) def play_video(self, row, col): # noqa """ fetch video_path from metadata column's cell and open system launcher with it. """ data = self.read_metadata(row) Utils.open_file(data.get('video_path')) def show_slides(self, row, col): # noqa """ fetch slides_path from metadata column's cell and open system launcher with it. """ data = self.read_metadata(row) Utils.open_file(data.get('slides_path')) def auto_organize(self): self.toolbar.auto_organize_button.config(state='disabled') self.menubar.actions_menu.entryconfig(Labels.AUTO_ORGANIZE, state='disabled') moved_files = dict() conf = Config.load(ConfigType.IMPARTUS) for subject_id, videos in self.videos.items(): for ttid, video_metadata in videos.items(): video_metadata = Utils.add_new_fields(video_metadata, self.video_slide_mapping) # for videos expected_video_path = self.impartus.get_mkv_path( video_metadata) real_video_path = self.offline_video_ttid_mapping.get( str(ttid)) if real_video_path and \ pathlib.PurePath(expected_video_path) != pathlib.PurePath(real_video_path) \ and os.path.exists(real_video_path): Utils.move_and_rename_file(real_video_path, expected_video_path) self.logger.info('moved {} -> {}'.format( real_video_path, expected_video_path)) moved_files[real_video_path] = expected_video_path # also update the offline_video_ttid_mapping self.offline_video_ttid_mapping[str( ttid)] = expected_video_path # also check any slides. for ext in conf.get('allowed_ext'): slides_path = '{}.{}'.format( real_video_path[:-len(".mkv")], ext) if os.path.exists(slides_path): expected_slides_path = '{}.{}'.format( expected_video_path[:-len(".mkv")], ext) Utils.move_and_rename_file(slides_path, expected_slides_path) self.logger.info('moved {} -> {}'.format( slides_path, expected_slides_path)) moved_files[slides_path] = expected_slides_path # is the folder empty, remove it.? [also any empty parent folders] old_video_dir = os.path.dirname(real_video_path) sys_name = platform.system() if conf.get('ignore_files').get(sys_name): ignore_files = conf.get('ignore_files')[sys_name] else: ignore_files = [] while True: dir_files = [ x for x in os.listdir(old_video_dir) if x not in ignore_files ] if len(dir_files) > 0: break for file in ignore_files: filepath = os.path.join(old_video_dir, file) if os.path.exists(filepath): os.unlink(filepath) os.rmdir(old_video_dir) self.logger.info('removed empty directory: {}'.format( old_video_dir)) # parent path. old_video_dir = Path(old_video_dir).parent.absolute() # captions expected_captions_path = self.impartus.get_captions_path( video_metadata) if not os.path.exists(expected_captions_path): if self.save_captions_if_needed(video_metadata, self.login.url_box.get(), expected_captions_path): self.logger.info('downloaded captions: {}'.format( expected_captions_path)) self.all_captions_found = True if len(moved_files) > 0: self.auto_organize_dialog(moved_files) self.expected_real_paths_differ = False def set_display_columns(self): column_states = [ i for i, v in enumerate(Variables().display_columns_vars().values()) if v.get() == 1 ] self.sheet.display_columns(indexes=column_states, enable=True, redraw=False) self.reset_column_sizes() self.sheet.refresh() def odd_even_color(self, cs: Dict, redraw=False): """ Apply odd/even colors for table for better looking UI. """ num_rows = self.sheet.total_rows() self.sheet.highlight_rows(list(range(0, num_rows, 2)), bg=cs['even_row']['bg'], fg=cs['even_row']['fg'], redraw=redraw) self.sheet.highlight_rows(list(range(1, num_rows, 2)), bg=cs['odd_row']['bg'], fg=cs['odd_row']['fg'], redraw=redraw) def progress_bar_color(self, cs: Dict, redraw=True): """ Set progress bar color. """ col = Columns.column_names.index('downloaded') num_rows = self.sheet.total_rows() for row in range(num_rows): odd_even_bg = cs['odd_row']['bg'] if row % 2 else cs['even_row'][ 'bg'] self.sheet.highlight_cells(row, col, fg=cs['progressbar']['fg'], bg=odd_even_bg, redraw=redraw) def set_button_status(self, redraw=False): """ reads the states of the buttons from the hidden state columns, and sets the button states appropriately. """ col_indexes = [ x for x, v in enumerate(Columns.all_columns.values()) if v['type'] == 'button_state' ] num_buttons = len(col_indexes) for row, row_item in enumerate(self.sheet.get_sheet_data()): for col in col_indexes: # data set via sheet.insert_row retains tuple/list's element data type, # data set via sheet.set_cell_data makes everything a string. # Consider everything coming out of a sheet as string to avoid any issues. state = str(row_item[col]) if state == 'True': self.enable_button(row, col - num_buttons, redraw=redraw) elif state == 'False': self.disable_button(row, col - num_buttons, redraw=redraw) return def get_button_state(self, key, video_exists_on_disk, slides_exist_on_server, slides_exist_on_disk): # noqa """ Checks to identify when certain buttons should be enabled/disabled. """ state = True if key == 'download_video' and video_exists_on_disk: state = False elif key == 'open_folder' and not video_exists_on_disk: state = False elif key == 'play_video' and not video_exists_on_disk: state = False elif key == 'download_slides' and (slides_exist_on_disk or not slides_exist_on_server): state = False elif key == 'show_slides' and not slides_exist_on_disk: state = False return state def disable_button(self, row, col, redraw=False): """ Disable a button given it's row/col position. """ cs = Config.load( ConfigType.COLORSCHEMES)[Variables().colorscheme_var().get()] self.sheet.highlight_cells(row, col, bg=cs['disabled']['bg'], fg=cs['disabled']['fg'], redraw=redraw) # update state field. state_button_col_name, state_button_col_num = self.get_state_button( Columns.column_names[col]) self.sheet.set_cell_data(row, state_button_col_num, False, redraw=redraw) def enable_button(self, row, col, redraw=False): """ Enable a button given it's row/col position. """ cs = Config.load( ConfigType.COLORSCHEMES)[Variables().colorscheme_var().get()] odd_even_bg = cs['odd_row']['bg'] if row % 2 else cs['even_row']['bg'] odd_even_fg = cs['odd_row']['fg'] if row % 2 else cs['even_row']['fg'] self.sheet.highlight_cells(row, col, bg=odd_even_bg, fg=odd_even_fg, redraw=redraw) # update state field. state_button_col_name, state_button_col_num = self.get_state_button( Columns.column_names[col]) self.sheet.set_cell_data(row, state_button_col_num, True, redraw=redraw) def set_readonly_columns(self, redraw=False): readonly_cols = [ i for i, (k, v) in enumerate(Columns.all_columns.items()) if not v.get('editable') ] self.sheet.readonly_columns(columns=readonly_cols, readonly=True, redraw=redraw) def set_colorscheme(self, cs): if self.frame_content: self.frame_content.configure(bg=cs['root']['bg']) if self.sheet: self.sheet.set_options(frame_bg=cs['table']['bg'], table_bg=cs['table']['bg'], table_fg=cs['table']['fg'], header_bg=cs['header']['bg'], header_fg=cs['header']['fg'], header_grid_fg=cs['table']['grid'], index_grid_fg=cs['table']['grid'], header_border_fg=cs['table']['grid'], index_border_fg=cs['table']['grid'], table_grid_fg=cs['table']['grid'], top_left_bg=cs['header']['bg'], top_left_fg=cs['header']['bg']) self.odd_even_color(cs, redraw=False) self.progress_bar_color(cs, redraw=False) self.set_button_status(redraw=False) self.set_readonly_columns(redraw=False) self.sheet.refresh() def decorate(self): """ calls multiple ui related tweaks. """ self.align_columns() cs = Config.load( ConfigType.COLORSCHEMES)[Variables().colorscheme_var().get()] self.set_colorscheme(cs) self.odd_even_color(cs) self.progress_bar_color(cs) def align_columns(self): # data and progressbar west/left aligned, button center aligned. self.sheet.align_columns([ Columns.column_names.index(k) for k in Columns.data_columns.keys() ], align='w') self.sheet.align_columns([ Columns.column_names.index(k) for k in Columns.progressbar_column.keys() ], align='w') self.sheet.align_columns([ Columns.column_names.index(k) for k in Columns.button_columns.keys() ], align='center') def show_video_callback(self, impartus: Impartus, event=None): # noqa if threading.activeCount( ) > 1: # 1. main thread, 2,3... download threads. response = tk.messagebox.askquestion( 'Download(s) in progress!', "Reloading the content will lose the downloads in progress.\n" + "Do you want to continue?", icon='warning') if response != 'yes': return self.toolbar.reload_button.config(state='disabled') self.menubar.actions_menu.entryconfig(Labels.RELOAD, state='disabled') self.toolbar.auto_organize_button.config(state='disabled') self.menubar.actions_menu.entryconfig(Labels.AUTO_ORGANIZE, state='disabled') self.toolbar.frame_toolbar.grid(row=1, column=0, sticky='ew') self.login.authenticate(impartus) self.set_display_widgets() self.toolbar.reload_button.config(state='normal') self.menubar.actions_menu.entryconfig(Labels.RELOAD, state='normal') if self.expected_real_paths_differ or not self.all_captions_found: auto_organize_button_state = 'normal' else: auto_organize_button_state = 'disabled' self.toolbar.auto_organize_button.config( state=auto_organize_button_state) self.menubar.actions_menu.entryconfig(Labels.AUTO_ORGANIZE, state=auto_organize_button_state) def on_auto_organize_dialog_close(self): self.login.authenticate(self.impartus) Dialogs.on_dialog_close() self.show_video_callback(self.impartus) def auto_organize_dialog(self, moved_files): # noqa dialog = Dialogs.create_dialog( on_close_callback=self.on_auto_organize_dialog_close, title='Auto Organize') label = tk.Label( dialog, text='Following files were moved / renamed -', ) label.grid(row=0, column=0, sticky='w', ipadx=10, ipady=10) dialog.columnconfigure(0, weight=1) # show a dialog with the output. sheet = Sheet( Dialogs.dialog, header_font=(self.header_font, self.header_font_size, "bold"), font=(self.content_font, self.content_font_size, "normal"), align='w', row_height="1", # str value for row height in number of lines. row_index_align="w", auto_resize_default_row_index=False, row_index_width=40, header_align='center', empty_horizontal=0, empty_vertical=0, ) sheet.headers(['Source', '', 'Destination']) target_parent = os.path.dirname(self.impartus.download_dir) for row, (source, destination) in enumerate(moved_files.items()): source = source[len(target_parent) + 1:] destination = destination[len(target_parent) + 1:] sheet.insert_row([source, Icons.MOVED_TO, destination]) sheet.set_all_column_widths() sheet.grid(row=1, column=0, sticky='nsew') ok_button = tk.Button(dialog, text='OK', command=self.on_auto_organize_dialog_close) ok_button.grid(row=2, column=0, padx=10, pady=10)
class edit_oder_demo(tk.Tk): def __init__(self, oid): # oid will be set in edit_order() function in crud_main_window.py to be called from fill_data_from_db() self.oid = oid tk.Tk.__init__(self) self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(0, weight=1) self.frame = tk.Frame(self) self.fill_data_from_db() self.frame.grid_columnconfigure(0, weight=1) self.frame.grid_rowconfigure(0, weight=1) self.sheet = Sheet( self.frame, page_up_down_select_row=True, # empty_vertical = 0, column_width=120, startup_select=(0, 1, "rows"), headers=headers, data=data, height=500, # height and width arguments are optional width=550, # For full startup arguments see DOCUMENTATION.md ) self.sheet.enable_bindings(( "single_select", # "single_select" or "toggle_select" "drag_select", # enables shift click selection as well "column_drag_and_drop", "row_drag_and_drop", "column_select", "row_select", "column_width_resize", "double_click_column_resize", # "row_width_resize", # "column_height_resize", "arrowkeys", "row_height_resize", "double_click_row_resize", "right_click_popup_menu", "rc_select", # "rc_insert_column", # "rc_delete_column", "rc_insert_row", "rc_delete_row", # "hide_columns", "copy", # "cut", # "paste", # "delete", "undo", "edit_cell")) self.frame.grid(row=0, column=0, sticky="nswe") self.sheet.grid(row=0, column=0, sticky="nswe") # __________ DISPLAY SUBSET OF COLUMNS __________ # self.sheet.display_subset_of_columns(indexes=[0, 1, 2], enable=True) # __________ BINDING A FUNCTIONS TO USER ACTIONS __________ self.sheet.extra_bindings([ ("end_edit_cell", self.end_edit_cell), ("begin_rc_delete_row", self.row_delete), ("end_insert_row", self.end_insert_row), ]) # __________ GETTING FULL SHEET DATA __________ # self.all_data = self.sheet.get_sheet_data() # __________ GETTING CELL DATA __________ # print (self.sheet.get_cell_data(0, 0)) # __________ GETTING ROW DATA __________ # print (self.sheet.get_row_data(0)) # only accessible by index # __________ GETTING COLUMN DATA __________ # print (self.sheet.get_column_data(0)) # only accessible by index def end_insert_row(self, event): print("cell inserted") try: oi = ORDERITEM(**{'oid': self.oid}) db_session.add(oi) db_session.commit() self.sheet.set_cell_data(event[1], 1, value=self.oid) self.sheet.set_cell_data(event[1], 0, value=oi.iid) self.sheet.dehighlight_rows(rows=[event[0]]) except Exception as e: self.sheet.highlight_rows(rows=[event[0]], fg='red', bg='red') e.with_traceback() def end_edit_cell(self, event): print("cell edited") ORDERITEM.query.filter_by(**{ "iid": self.sheet.get_cell_data(event[0], 0) }).update( {headers[event[1]]: self.sheet.get_cell_data(event[0], event[1])}) db_session.commit() def row_delete(self, event): print("row deleted") print({"iid": self.sheet.get_cell_data(event[1][0], 0)}) ORDERITEM.query.filter_by( **{ "iid": self.sheet.get_cell_data(event[1][0], 0) }).delete() db_session.commit() def fill_data_from_db(self): data.clear() ois = ORDERITEM.query.filter_by(oid=self.oid) k = [[ i.to_dict(rules=('-ORDER1', '-PRODUCT')).get(z) or 0 for z in headers ] for i in ois] data.extend(k)
class Directorio_A: def __init__(self): #Pantalla self.raiz = Tk() self.raiz.title("Mantenimiento de Articulos") self.raiz.geometry('680x520') #Barra menu menubar = Menu(self.raiz) self.raiz.config(menu=menubar) filemenu = Menu(menubar, tearoff=0) filemenu.add_command(label="Salir", command=self.raiz.quit) mantmenu = Menu(menubar, tearoff=0) mantmenu.add_command(label="Proveedor", command=self.abrir_P) mantmenu.add_command(label="Clientes", command=self.abrir_C) mantmenu.add_command(label="Facturas", command=self.abrir_F) mantmenu.add_command(label="Conexion", command=self.abrir_R) menubar.add_cascade(label="Archivo", menu=filemenu) menubar.add_cascade(label="Mantenimiento", menu=mantmenu) #Objecto Articulo self.fuente = font.Font(weight="bold") self.articulo = Articulos.Articulo() self.insertando = True #Titulo self.lb_tituloPantalla = Label(self.raiz, text="MANTENIMIENTO DE ARTICULOS", font=self.fuente) self.lb_tituloPantalla.place(x=180, y=20) #Formulario #ID articulo self.lb_cedula = Label(self.raiz, text="ID articulo:") self.lb_cedula.place(x=100, y=60) self.txt_cedula = Entry(self.raiz, textvariable=self.articulo.PK_ID_ART, justify="right") self.txt_cedula.place(x=230, y=60) #Nombre self.lb_nombre = Label(self.raiz, text="nombre del articulo:") self.lb_nombre.place(x=100, y=90) self.txt_nombre = Entry(self.raiz, textvariable=self.articulo.NOMBRE, justify="right", width=30) self.txt_nombre.place(x=230, y=90) #Cantidad existente self.lb_apellido1 = Label(self.raiz, text="Cantidad existente:") self.lb_apellido1.place(x=100, y=120) self.txt_apellido1 = Entry(self.raiz, textvariable=self.articulo.CANT_EXI, justify="right") self.txt_apellido1.place(x=230, y=120) #descripcion self.lb_apellido2 = Label(self.raiz, text="Descripcion:") self.lb_apellido2.place(x=100, y=150) self.txt_apellido2 = Entry(self.raiz, textvariable=self.articulo.DESCRIPCION, justify="right", width=30) self.txt_apellido2.place(x=230, y=150) #Precio unitario self.lb_apellido1 = Label(self.raiz, text="Precio unitario:") self.lb_apellido1.place(x=100, y=180) self.txt_apellido1 = Entry(self.raiz, textvariable=self.articulo.PRECIO_UN, justify="right") self.txt_apellido1.place(x=230, y=180) #Boton Limpiar self.bt_borrar = Button(self.raiz, text="Limpiar", width=15) self.bt_borrar.place(x=70, y=220) #Boton Enviar self.bt_enviar = Button(self.raiz, text="Enviar", width=15, command=self.enviarInformacion) self.bt_enviar.place(x=190, y=220) #Boton Cargar self.bt_borrar = Button(self.raiz, text="Cargar", width=15, command=self.cargarInformacion) self.bt_borrar.place(x=310, y=220) #Boton Eliminar self.bt_enviar = Button(self.raiz, text="Eliminar", width=15, command=self.eliminarInformacion) self.bt_enviar.place(x=430, y=220) self.bt_reporte = Button(self.raiz, text="Reporte", width=15, command=self.generarPDFListado) self.bt_reporte.place(x=550, y=340) #Se coloca un label del informacion self.lb_tituloPantalla = Label(self.raiz, text="INFORMACIÓN INCLUIDA", font=self.fuente) self.lb_tituloPantalla.place(x=190, y=275) self.sheet = Sheet(self.raiz, page_up_down_select_row=True, column_width=120, startup_select=(0, 1, "rows"), headers=[ 'ID articulo', 'Nombre', 'Cantidad', 'Descripcion', 'Preio Unitario' ], height=170, width=560) #hoja excel self.sheet.enable_bindings( ("single_select", "column_select", "row_select", "column_width_resize", "double_click_column_resize", "arrowkeys", "row_height_resize", "double_click_row_resize", "right_click_popup_menu", "rc_select", "rc_insert_column", "rc_delete_column", "rc_insert_row", "rc_delete_row")) self.sheet.place(x=20, y=310) #toda informacion self.cargarTodaInformacion() self.raiz.mainloop() def generarPDFListado(self): try: #Crea un objeto para la creación del PDF nombreArchivo = "ListadoArticulos.pdf" rep = reportPDF.Canvas(nombreArchivo) #Agrega el tipo de fuente Arial registerFont(TTFont('Arial', 'ARIAL.ttf')) #Crea el texto en donde se incluye la información textobject = rep.beginText() # Coloca el titulo textobject.setFont('Arial', 16) textobject.setTextOrigin(10, 800) textobject.setFillColor(colors.darkorange) textobject.textLine(text='LISTA DE ARTICULOS') #Escribe el titulo en el reportes rep.drawText(textobject) #consultar la informacion de la base de datos self.articuloBo = ArticuloBO.ArticuloBO( ) #se crea un objeto de logica de negocio informacion = self.articuloBo.consultar() #agrega los titulos de la tabla en la información consultada titulos = [ "ID articulo", "Nombre del articulo", "Descripcion", "Cant.Existente", "Precio Unitario" ] informacion.insert(0, titulos) #crea el objeto tabla para mostrar la información t = Table(informacion) #Le coloca el color tanto al borde de la tabla como de las celdas t.setStyle( TableStyle([("BOX", (0, 0), (-1, -1), 0.25, colors.black), ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black) ])) #para cambiar el color de las fichas de hace un ciclo según la cantidad de datos #que devuelve la base de datos data_len = len(informacion) for each in range(data_len): if each % 2 == 0: bg_color = colors.whitesmoke else: bg_color = colors.lightgrey if each == 0: #Le aplica un estilo diferente a la tabla t.setStyle( TableStyle([('BACKGROUND', (0, each), (-1, each), colors.orange)])) else: t.setStyle( TableStyle([('BACKGROUND', (0, each), (-1, each), bg_color)])) #acomoda la tabla según el espacio requerido aW = 840 aH = 780 w, h = t.wrap(aW, aH) t.drawOn(rep, 10, aH - h) #Guarda el archivo rep.save() #Abre el archivo desde comandos, puede variar en MacOs es open #subprocess.Popen("open '%s'" % nombreArchivo, shell=True) subprocess.Popen(nombreArchivo, shell=True) #Windows except IOError: msg.showerror("Error", "El archivo ya se encuentra abierto") #Limpiar def limpiarInformacion(self): self.articulo.limpiar() msg.showinfo( "Acción del sistema", "La información del formulario ha sido eliminada correctamente") #envia la info def enviarInformacion(self): try: self.articuloBo = ArticuloBO.ArticuloBO() if (self.insertando == True): self.articuloBo.guardar(self.articulo) else: self.articuloBo.modificar(self.articulo) self.cargarTodaInformacion() self.insertando = True self.articulo.limpiar() if (self.insertando == True): msg.showinfo( "Acción: Agregar articulo", "La información del articulo ha sido incluida correctamente" ) else: msg.showinfo( "Acción: modificar articulo", "La información del articulo ha sido modificada correctamente" ) except Exception as e: msg.showerror("Error", str(e)) #eliminar la info def eliminarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() idarticulo = (self.sheet.get_cell_data(datoSeleccionado[0], 0)) nombre = (self.sheet.get_cell_data(datoSeleccionado[0], 1)) resultado = msg.askquestion( "Eliminar", "¿Desear eliminar a " + nombre + " de la base de datos?") if resultado == "yes": self.articulo.PK_ID_ART.set(idarticulo) self.articuloBo = ArticuloBO.ArticuloBO() self.articuloBo.eliminar(self.articulo) self.cargarTodaInformacion() self.articulo.limpiar() except Exception as e: msg.showerror("Error", str(e)) #cargar toda la info def cargarTodaInformacion(self): try: self.articuloBo = ArticuloBO.ArticuloBO() resultado = self.articuloBo.consultar() self.sheet.set_sheet_data(resultado) except Exception as e: msg.showerror("Error", str(e)) #selecionado def cargarInformacion(self): try: datoSeleccionado = self.sheet.get_currently_selected() idarticulo = (self.sheet.get_cell_data(datoSeleccionado[0], 0)) self.articulo.PK_ID_ART.set(idarticulo) self.articuloBo = ArticuloBO.ArticuloBO() self.articuloBo.consultarArticulo(self.articulo) self.insertando = False msg.showinfo( "Acción: Consultar proveedor", "La información del proveedor ha sido consultada correctamente" ) except Exception as e: msg.showerror("Error", str(e)) #abrir def abrir_P(self): from mant_Proveedor import Directorio_P self.raiz.destroy() Directorio_P() def abrir_C(self): from mant_Clientes import Directorio_C self.raiz.destroy() Directorio_C() def abrir_F(self): from mant_Factura import Directorio_F self.raiz.destroy() Directorio_F() def abrir_R(self): from mant_RelacionAP import Conexion_AP self.raiz.destroy() Conexion_AP() self.raiz.mainloop()