flet-dev / examples

Flet sample applications
MIT License
433 stars 174 forks source link

help multiprocess #22

Open orcim-wind opened 1 year ago

orcim-wind commented 1 year ago

Hi, can you help me in this example: when i add a row with button [Add] the method 'appLine' adds a line correctly while the external process consumer using the same 'Appline' method fails thanks a lot


# flet
import flet
from flet import (
    Container, Page, Row, Column, animation, transform,
    VerticalDivider, Text, colors,
    ListView, FilledButton, UserControl
)

# multiprocess
from multiprocessing import Process
from multiprocessing import Queue
# from multiprocessing import Value
from queue import Empty

from time import sleep
from random import random

#---------------------------------------------------------
# myClass
#---------------------------------------------------------
class MyApp(UserControl):

    #-------------------------------------------------------
    # override the constructor
    def __init__(self, que):
        # execute the base constructor
        UserControl.__init__(self)

        #-----------------------------------------------------
        # ListView
        self.lVie=ListView(
            expand=1, 
            auto_scroll=True,
        )

        self.lCou = 1
        self.fCol = "#00bb00"
        self.bCol = '#000000'
        self.que  = que
        self.prd  = None

    #-------------------------------------------------------
    def appLine(self, item):

        if item:
            self.lVie.controls.append(
                Text(
                    # f"Line {self.lCou}",
                    f">{item}",
                    color=self.fCol,
                    bgcolor=self.bCol,
                )
            )
            self.lCou += 1
            try:
                self.update()
            except:
                ...

    #-------------------------------------------------------
    def build(self):

        #-----------------------------------------------------
        # Button
        self.btn1 = FilledButton(
            text=" Add ",
            # expand=1,
            on_click=self.clicked_btn,
            data="btn1",
        )
        self.btn2 = FilledButton(
            text=" Rem ",
            # expand=1,
            on_click=self.clicked_btn,
            data="btn2",
        )

        #-----------------------------------------------------
        # Container
        return Container(

            Row(
                [

                    # Left
                    Container(
                        bgcolor=colors.SURFACE_VARIANT,
                        width=150,
                        height=700,
                        border_radius=10,
                    ),

                    VerticalDivider(),

                    # Middle
                    Container(
                        bgcolor=self.bCol,
                        width=150,
                        height=700,
                        # border_radius=10,
                        expand=1, 
                        content=Row(
                            controls=[
                                self.lVie,
                            ],
                        ),
                    ),

                    VerticalDivider(),

                    # Right
                    Container(
                        bgcolor=colors.SURFACE_VARIANT,
                        width=150,
                        height=700,
                        # expand=True,
                        border_radius=10,
                        padding=20,
                        content=Column(
                                controls=[
                                        Column(
                                                controls=[
                                                    self.btn1,
                                                    self.btn2,
                                                ],
                                        ),
                                ],
                        ),
                    ),

                ],
                spacing=0,
                expand=True,
            ),
        )

    #-------------------------------------------------------
    # Button
    def clicked_btn(self, e):
        # print("data:", e.control.data)

        if e.control.data == 'btn1':
            # print("Btn1")
            self.appLine(f"Line {self.lCou}")

            # start generate work
            self.prd = prodStart(self)
            self.prd.start()

        elif e.control.data == 'btn2':
            # print("Btn2")
            if self.lVie.controls.__len__():
                # self.lVie.controls.pop()
                self.lVie.controls.__delitem__(0)
                # self.lCou -= 1
            self.update()

#---------------------------------------------------------
# Application
#---------------------------------------------------------
def main(page: Page):

    page.title = "myApp"
    page.add(app)

#---------------------------------------------------------
# generate work
def producerT(self):
    print('Producer: Running', flush=True)
    # generate work
    for i in range(3):
        # generate a value
        value = random()
        # block
        sleep(value)
        # add to the queue
        self.que.put(value)
    print('Producer: Done', flush=True)

#---------------------------------------------------------
# instance work
def prodStart(self):
    # start the producer
    prod = Process(target=producerT, args=(self,))
    return prod

#-------------------------------------------------------
# consume work 
def consumer(self):
    print('Consumer: Running', flush=True)
    # consume work
    while True:
        # get a unit of work
        try:
            item = self.que.get(timeout=0.5)
        except Empty:
            # print('Consumer: waiting...', flush=True)
            continue
        # check for stop
        if item is None:
            # self.prd.terminate()
            print('Producer: Terminated', flush=True)
            break
        if item:
            # report
            print(f'<< {item}', flush=True)
            self.appLine(f'<< {item}')
    # all done
    print('Consumer: Terminated', flush=True)

#---------------------------------------------------------
# Main
#---------------------------------------------------------
# entry point
if __name__ == '__main__':

    # create the shared queue
    queue = Queue()

    app = MyApp(queue)
    app.horizontal_alignment="center",

    # start the consumer
    consumer_process = Process(target=consumer, args=(app,))
    consumer_process.start()
    # start the producer
    # producer_process = Process(target=producer, args=(queue,0))
    # producer_process.start()

    # Main loop
    flet.app(target=main)
    # flet.app(target=main, view=flet.WEB_BROWSER)

    # force stop consumer
    queue.put(None)

    # wait for all processes to finish
    # producer_process.join()
    consumer_process.join()
FeodorFitsner commented 1 year ago

What error are you getting? What OS is that, Python version, etc.? Could you give more context please?

orcim-wind commented 1 year ago

Linux 5.4.0-124-generic #140-Ubuntu SMP Python 3.8.10 If you run the script above and you set 2 breaks in the lines 57,49 You will be able to see, after pressing the Add button, that the "self.lVie" list is not correctly updated