我怎样才能摆脱错误=“必须首先将控件添加到页面。”在舰队 python 上

问题描述 投票:0回答:1

这是我的完整代码,除了将表控件添加到页面时之外似乎没有任何其他问题,因为它返回数据来填充所述表,只是当调用填充表的函数时我收到所述错误.

#CONEXION A DB
import flet as ft
from flet import Tab, Tabs
from flet_route import Params, Basket
from Clases.controls import *
#INSTANCIA PARA UTILIZAR LOS CONTROLES
control = Controls()
# Nombre de la tabla
nombre_tabla = "clientes"
# Obtener los nombres de las columnas
nombres_columnas = control.obtenerNombresColumnas(nombre_tabla)
#Style attributes for header class
header_style= {
      "height": 60,
      "bgcolor": "#081d33",
      "border_radius": ft.border_radius.only(top_left=15, top_right=15),
      "padding": ft.padding.only(left=15, right=15),
}
#Method that creates and return textfield
def search_field(function: callable):
      return ft.TextField(
            border_color="transparent",
            width=350,
            height=20,
            text_size=15,
            content_padding=0,
            cursor_color="white",
            cursor_width=1,
            color="white",
            hint_text="Search",
            on_change=function
      )
#Method that adds a container to the search field
def search_bar(control: ft.TextField):
      return ft.Container(
            bgcolor="white10",
            border_radius=6,
            opacity=0,
            animate_opacity=300,
            padding=8,
            content = ft.Row(
                  spacing=10,
                  vertical_alignment="center",
                  controls=[
                        ft.Icon(
                              name=ft.icons.SEARCH_ROUNDED,
                              size=20,
                              opacity=0.85
                        ),
                        control
                  ]
            )

      )
#Define header class
class Header(ft.Container):
    def __init__(self, page):
        super().__init__(**header_style,
                         on_hover=self.toggle_search 
                         )
        #Define attributes
        #self.dt = dt
        self.page = page  # Store the 'page' parameter for later use
        #Create a textfield for search
        self.search_value = search_field(self.filter_data)
        #Create a search box
        self.search = search_bar(self.search_value)
        #Define other class attributes
        self.name = ft.Text("DentistaBromista", color="white", size=18, weight=700)
        self.logout = ft.IconButton(icon=ft.icons.LOGOUT, icon_color="white", tooltip="Cerrar sesion", on_click=self.logOut, width=40)
        #Compile the attributes
        self.content = ft.Row(
            expand=True,
            alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
            controls=[
                self.name,
                self.search, 
                self.logout
            ]
        )
    #Method that log out
    def logOut(self, e: ft.TapEvent):
        #VALIDAR SI SE HACE CLICK
        self.page.go("/")  # Use the stored 'page' for redirecting
    #Method that toggle search bar visibility
    def toggle_search(self, e: ft.HoverEvent):
        #SE MUESTRA SI HACES HOVER Y SI NO SE OCULTA
        self.search.opacity = 1 if e.data == 'true' else 0
        self.search.update()
    #Define a placeholder method for filter data
    def filter_data(self, e):
        print("hola")
#Define form class styling and attributes
form_style = {
    "border_radius": 8,
    "border": ft.border.all(1, "#ebebeb"),
    "bgcolor": "white10",
    "padding": 15,
}
#Method that creates and return textfield
def text_field():
    return ft.TextField(
        border_color="transparent",
        height=30,
        text_size=15,
        content_padding=0,
        cursor_color="black",
        cursor_width=1,
        color="black",
    )
    
#Defin e a container to mantain the textfield
def text_field_container(
    expand: bool | int, name: str, control: ft.TextField
):
    return ft.Container(
        expand=expand,
        height=45,
        bgcolor="#ebebeb",
        border_radius=6,
        padding=8,
        content=ft.Column(
            spacing=1,
            controls=[
                ft.Text(
                    value = name, 
                    size=9,
                    color="black",
                    weight="bold"
                ),
                control
            ]
        )
    )
#Define form class
class formClient(ft.Container):
    def __init__(self, page):
        super().__init__(**form_style)
        #Define attributes
        #self.dt = dt
        self.page = page  # Store the 'page' parameter for later use
        #Define the num of rows for textfields
        self.row1_value = text_field()
        self.row2_value = text_field()
        self.row3_value = text_field()
        
        
        #Define and contain the textfields
        self.row1 = text_field_container(True, "Nombre", self.row1_value)
        self.row2 = text_field_container(True, "Email", self.row2_value)
        self.row3 = text_field_container(True, "Telefono", self.row3_value)
        

        #Button to submit
        self.submit = ft.ElevatedButton(
            text="Añadir",
            style=ft.ButtonStyle(
                shape={"": ft.RoundedRectangleBorder(radius=8)},
            ),
            on_click=self.submit_data
        )
        #Compile the attributes
        self.content = ft.Column(
            expand=True,
            controls=[
                ft.Row(controls=[ft.Text("Llena los campos con los datos del cliente", size=20, color="black")]),
                ft.Row(controls=[ft.Text("1.Informacion personal ", size=15, color="black")]),
                ft.Row(controls=[self.row1, self.row2]),
                ft.Row(controls=[self.row3]),
                ft.Row(controls=[self.submit], alignment="end")
            ]
        )
    #Enviar los datos a la base de datos
    def submit_data(self, e:ft.TapEvent=None):
        self.row_values = (self.row1_value.value, self.row2_value.value, self.row3_value.value)
        print(self.row_values)
        # Validar si los campos no están vacíos
        if all(self.row_values):
            if control.submit_data(e, self.row_values):  # Si submit_data devuelve True
                self.clear_inputs()  # Llamar a clear_inputs
                #Mostrar que se insertó
                self.page.snack_bar = ft.SnackBar(
                    content=ft.Text("¡Se guardo correctamente el cliente!", color="white", weight="bold"),
                    action="Okey!",
                    bgcolor="green",
                    action_color="white",
                    duration=4000)
                self.page.snack_bar.open = True
                self.page.update()
            else:
                #Mostrar que no se insertó
                self.page.snack_bar = ft.SnackBar(
                    content=ft.Text("Hubo un problema al guardar el registro.", color="white", weight="bold"),
                    action="Okey!",
                    bgcolor="red",
                    action_color="white",
                    duration=4000)
                self.page.snack_bar.open = True
                self.page.update()
        else:
            dlg = ft.AlertDialog(title=ft.Text("Por favor llena todos los campos", color="white"))
            self.page.dialog = dlg
            dlg.open = True
            self.page.update()
    #Method for delete user input after submit
    def clear_inputs(self):
        #Borra los valores de los campos
        self.row1_value.value = ""
        self.row2_value.value = ""
        self.row3_value.value = ""
        self.content.update()

#Datatable styles and attributes
data_table_style = {
    "expand": True,
    "border_radius": 8,
    "border": ft.border.all(2, "#ebebeb"),
    "horizontal_lines": ft.border.BorderSide(1, "#ebebeb"),
    "columns": [
        #Traer los datos de la base de datos(los titulos de las columnas)
        ft.DataColumn(ft.Text(index, size=13, color="black", weight="bold"))
        for index in [nombres_columnas[i] for i in [1,2,3] ] #MUESTRA SOLO 4 COLUMNAS NOMBRE, TELEFONO, CORREO Y ACCIONES
    ] + [ft.DataColumn(ft.Text("AGENDAR", size=13, color="black", weight="bold"))] #Columna Acciones
    + [ft.DataColumn(ft.Text("EDITAR", size=13, color="black", weight="bold"))] #Columna Acciones
    + [ft.DataColumn(ft.Text("ELIMINAR", size=13, color="black", weight="bold"))] #Columna Acciones
}
class DataTable(ft.DataTable):
    def __init__(self):
        super().__init__(**data_table_style)
        self.data = control.get_data('clientes')

    def add_data_to_table(self):
        self.rows = []
        for row_dict in self.data:  # Itera sobre cada diccionario en la lista
            data = ft.DataRow()
            data.cells = [
                ft.DataCell(
                    ft.Text(
                        value, size=13, color="black",
                    )
                ) for value in [row_dict['nombre'], row_dict['telefono'], row_dict['email']]
            ]
            data.cells.append(ft.IconButton(ft.icons.EDIT_CALENDAR_ROUNDED))
            data.cells.append(ft.IconButton(ft.icons.EDIT))
            data.cells.append(ft.IconButton(ft.icons.DELETE))

            self.rows.append(data)
        self.update()

class mainForm:
    def __init__(self):
        super().__init__()  
        self.table = DataTable()      
    def main(self, page):
        page.title = "Registro"
        #table = DataTable()     
        header = Header(page)
        form = formClient(page)   

        content = ft.Column(
                expand=True,
                controls=[
                    #Header
                    header,
                    ft.Divider(height=2, color="transparent"),
                    #Form 
                    form,
                    ft.Divider(height=2, color="transparent"),
                    #Table
                    ft.Column(
                        scroll="auto",
                        expand=True,  
                        controls=[ft.Row(controls=[self.table])] #tabla
                    ),
                ],
            )
        
        page.add(content)
        page.update() # Update the page after adding controls
        self.table.add_data_to_table()
        return content  # Return the content, not the page
    #Regresa la vista
    def build(self,  page: ft.Page, params=Params, basket=Basket):
        content = self.main(page)
        return ft.View(
            "/formCliente",
            controls=[content],  # Add the content as a control
            bgcolor="white"
        )

我尝试以不同的方式和在不同的地方添加对函数的调用,以使用从 mysql 带来的数据填充表,但似乎没有任何效果

python oop controls flet
1个回答
0
投票

我不清楚您到底在哪里遇到问题,但可能是从类 init 方法将所有元素添加到页面时出现的问题,您需要在 did_mount() 方法上将其分开,以便在安装控件时添加。

您有一个示例,其中解释了舰队教程的注释: https://flet.dev/docs/tutorials/python-solitaire/

© www.soinside.com 2019 - 2024. All rights reserved.