Search code examples
pythonuser-interfaceflet

Flet python page.update doesn't update my form gui


In my code, I'm trying to update the textfield value after retrieving image data with tesseract. The problem is that the value updates, but it doesn't do so in the GUI itself.

from flet import *
from vvisiteur import Visiteur
import pytesseract
from PIL import Image as img

class AppForm(UserControl):
    def __init__(self, page : Page):
        super().__init__()
        self.page = page
        self.name = self.app_form_input_field('Name', True)
        self.id_number = self.app_form_input_field('id Number', 3)
        self.phone = self.app_form_input_field('phone', 1)
        self.autre = self.app_form_input_field('Field Tree *', 1)

    def app_form_input_field(self, name:str, expand:int):
        return Container(
            expand=expand,
            height=45,
            bgcolor='#ebebeb',
            border_radius=6,
            padding=8,
            content = TextField(
                        label=name,
                        border_color="transparent",
                        height=20,
                        text_size=13,
                        content_padding=0,
                        cursor_color="black",
                        cursor_width=1,
                        cursor_height=18,
                        color="black",
                    ),
        )
    
    def pickFile(self, e:FilePickerResultEvent):
        image_loc = e.files[0].path
        img_pro=img.open(image_loc)
        text = pytesseract.image_to_string(img_pro, lang='fra')
        sections= {}
        lines = text.split("\n")
        sections['name'] = lines[18] + ' ' + lines[4]
        sections['id number'] = lines[24].split(" ")[0]
        temp =  lines[13].split()
        sections['phone'] = ' '.join(temp[1:])
        print(sections)
        self.id_number.content.value = sections["id number"]
        self.name.content.value = sections["name"]
        self.phone.content.value = sections["phone"]
        self.page.snack_bar = SnackBar(
            Text("sucess get from image", size=30),
            bgcolor="green"
        )
        self.page.snack_bar.open=True
        self.page.update()
    

    def return_vit(self):
        visiteur = Visiteur(self.name.content.value ,self.phone.content.value, self.id_number.content.value)
        return visiteur.to_dict()
        
    def build(self):
        file_picker = FilePicker(on_result=self.pickFile)
        self.page.overlay.append(file_picker)
        return Container(
            expand=True,
            height=220,
            bgcolor="white10",
            border=border.all(1, "#ebebeb"),
            border_radius=8,
            padding= 15,
            content=Column(
                expand=True,
                controls = [
                    Row(controls= [self.name]),
                    Row(controls= [
                        self.id_number,
                        self.phone,
                        self.autre,
                        ]
                    ),
                    ElevatedButton("Process",
                           bgcolor="blue",
                           color='white',
                           on_click=lambda _ :file_picker.pick_files()),
                ]
            )
        )

I'm trying to automatically fill a form with Texfields by retrieving information from an image and changing textfield.value directly in the code. it doesn't work when i use a class for my form but It works when I code directly in the main like this

import pytesseract
from PIL import Image as img
from flet import *
import flet
import os

def main(page: Page):
    image_loc= TextField(label="yout image name")
    id_number= TextField(label="id number")
    name_txt= TextField(label="your name")
    phone= TextField(label="phone number")
    healthy_service = TextField(label="healthy service")
    image_preview = Image(src=False, width= 150, height=120)

    def pickFile(e:FilePickerResultEvent):
        image_loc.value = e.files[0].path
        print(image_loc.value)
        img_pro=img.open(image_loc.value)
        text = pytesseract.image_to_string(img_pro, lang='fra')
        sections= {}
        lines = text.split("\n")
        sections['name'] = lines[18] + ' ' + lines[4]
        sections['id number'] = lines[24].split(" ")[0]
        temp =  lines[13].split()
        sections['phone'] = ' '.join(temp[1:])
        print(sections)
        id_number.value = sections["id number"]
        name_txt.value = sections["name"]
        phone.value = sections["phone"]
        page.snack_bar = SnackBar(
            Text("sucess get from image", size=30),
            bgcolor="green"
        )
        page.snack_bar.open=True
        page.update()

    file_picker = FilePicker(on_result=pickFile)

    page.overlay.append(file_picker)
    page.add(
        Column([
            image_loc,
            ElevatedButton("Process",
                           bgcolor="blue",
                           color='white',
                           on_click=lambda _ :file_picker.pick_files()),
            Text('you result in image', weight="bold"),
            image_preview,
            id_number,
            name_txt,
            phone,
            healthy_service,
        ])
    )

flet.app(target=main)

A Minimum code with class it not work

import pytesseract
from PIL import Image as img
from flet import *
import flet
import os


class form(UserControl):
    def __init__(self, page : Page):
        super().__init__()
        self.page = page
        self.image_loc= TextField(label="yout image name")
        self.id_number= TextField(label="id number")
        self.name_txt= TextField(label="your name")
        self.phone= TextField(label="phone number")
        self.healthy_service = TextField(label="healthy service")
        self.image_preview = Image(src=False, width= 150, height=120)

    def pickFile(self, e:FilePickerResultEvent):
        image_loc = e.files[0].path
        img_pro=img.open(image_loc)
        text = pytesseract.image_to_string(img_pro, lang='fra')
        sections= {}
        lines = text.split("\n")
        sections['name'] = lines[18] + ' ' + lines[4]
        sections['id number'] = lines[24].split(" ")[0]
        temp =  lines[13].split()
        sections['phone'] = ' '.join(temp[1:])
        print(sections)
        self.id_number.value = sections["id number"]
        self.name_txt.value = sections["name"]
        self.phone.value = sections["phone"]
        self.page.snack_bar = SnackBar(
            Text("sucess get from image", size=30),
            bgcolor="green"
        )
        self.page.snack_bar.open=True
        self.page.update()

    def build(self):
        file_picker = FilePicker(on_result=self.pickFile)
        self.page.overlay.append(file_picker)
        return(
            Container(
                content = Column([
                ElevatedButton("Process",
                           bgcolor="blue",
                           color='white',
                           on_click=lambda _ :file_picker.pick_files()),
                Text('you result in image', weight="bold"),
                self.image_preview,
                self.id_number,
                self.name_txt,
                self.phone,
                self.healthy_service,
            ])
        )
    )

def main(page: Page):
    myform = form(page)
    page.add(myform)
    page.update()

flet.app(target=main)

Solution

  • You have to use self.update() to update elements in UserControl

    You can see it even in examples for UserControl


    You still need self.page.update() to update self.page.snack_bar.


    Minimal working code:

    I keep only one TextField and display path instead of text from pytesseract.
    This way everyone can test it.

    import flet as ft   # PEP8: `import *` is not preferred
    
    class Form(ft.UserControl):  # PEP8: `UpperCasenames` for classes
    
        def __init__(self, page : ft.Page):
            super().__init__()
            self.page = page   # to add `SnackBar`
            self.name_txt = ft.TextField(label="your name")
    
        def pickFile(self, e:ft.FilePickerResultEvent):
            if e.files:
                sections = {}
                sections['name'] = e.files[0].path
                print(sections)
                
                self.name_txt.value = sections["name"]
                self.update()       # to update elements in `UserControl`
    
                self.page.snack_bar = ft.SnackBar(
                    ft.Text("sucess get from image", size=30),
                    bgcolor="green"
                )
                self.page.snack_bar.open = True
                self.page.update()  # to update `self.page.snack_bar`
            else:
                self.page.snack_bar = ft.SnackBar(
                    ft.Text("You didn't select image", size=30),
                    bgcolor="red"
                )
                self.page.snack_bar.open = True
                self.page.update()  # to update `self.page.snack_bar`
     
        def build(self):
            file_picker = ft.FilePicker(on_result=self.pickFile)
            self.page.overlay.append(file_picker)
            
            return(
                ft.Container(
                    content = ft.Column([
                    ft.ElevatedButton("Process",
                               bgcolor="blue",
                               color='white',
                               on_click=file_picker.pick_files),  # no need `lambda`
                    ft.Text('you result in image', weight="bold"),
                    self.name_txt,
                ])
            )
        )
    
    def main(page: ft.Page):
        myform = Form(page)
        page.add(myform)
        #page.update()   # doesn't need it
    
    ft.app(target=main)
    

    PEP 8 -- Style Guide for Python Code