Flet Python Project - Change popupbutton's color

233 Views Asked by At

I want the button popupbutton's color change when I click on the popupmenuitem. My button didn't change the color when I click, but after I debug, the dStatus properties already change the color. Here is my code.

self.dStatus = Icon(name=icons.CIRCLE_ROUNDED, color="White")

def onButtonClick(e):
    if e.control.data == "Online":
        self.dStatus = Icon(name=icons.CIRCLE_ROUNDED, color="Green" )
    elif e.control.data == "Busy":
        self.dStatus = Icon(name=icons.CIRCLE_ROUNDED, color="Red")
        
    
    avatar_container.content = self.dStatus

avatar_container = Container(
        width=40,
        height=40,
        margin=margin.only(top=35, left=300),

        content = PopupMenuButton(
            content= self.dStatus,

            items=[
            PopupMenuItem(text="Status"),
            PopupMenuItem(content=ElevatedButton(text="Online",icon=icons.CIRCLE_ROUNDED, icon_color="Green",data="Online", on_click= onButtonClick),  ),
            PopupMenuItem(content=ElevatedButton(text="Busy",icon=icons.CIRCLE_ROUNDED, icon_color="Red",data="BUsy", on_click= onButtonClick ),  )
            ]
    )
    )

1

There are 1 best solutions below

0
On

The main thing you're missing is a self.update() at the end of your callback (or avatar_container.update() if you don't want to update the whole UserControl, or even `avatar_container.content.content.update() to update only the icon). Without it, the data is update but the component is not refreshed so you don't see the change.

There were three other problems in your code:

  • First one, you were changing avatar_container.content to self.dStatus, but avatar_container.content is the whole container, not just the icon. Therefore, once you've used the menu once, it is replaced by an icon and the menu has disapeared. You need to update only the icon for the menu to stay here. The icon is in the content of the PopupMenuButton, which is in the content of the avatar_container. Therefore, the update looks like that: avatar_container.container.container = self.dStatus.
  • Second one, there was a typo in the last PopupMenuItem, the data was "BUsy" instead of "Busy".
  • Finally, the use of ElevatedButton in the PopupMenuItem is not recommended, as clicking outside of the button (but still on the menu item) would close the menu without executing the onButtonClick callback, and clicking on the button will execute the callback but not close the menu. Therefore I changed buttons to simple rows containing the icon and the text.

Here is the updated code:

import flet as ft

class Avatar(ft.UserControl):
    def build(self):
        self.dStatus = ft.Icon(name=ft.icons.CIRCLE_ROUNDED, color="White")

        def onButtonClick(e):
            if e.control.data == "Online":
                self.dStatus = ft.Icon(name=ft.icons.CIRCLE_ROUNDED, color="Green")
            elif e.control.data == "Busy":
                self.dStatus = ft.Icon(name=ft.icons.CIRCLE_ROUNDED, color="Red")
            avatar_container.content.content = self.dStatus  # Modify the icon instead of the whole container
            self.update()  # Update the UserControl (could be more precise with avatar_container.update(), or even deeper)

        avatar_container = ft.Container(
            width=40,
            height=40,
            margin=ft.margin.only(top=35, left=300),

            content=ft.PopupMenuButton(
                content=self.dStatus,

                items=[
                    ft.PopupMenuItem(text="Status"),
                    ft.PopupMenuItem(
                        content=ft.Row(
                            [
                                ft.Icon(ft.icons.CIRCLE_ROUNDED, color="Green"),
                                ft.Text("Online"),
                            ],
                        ),
                        data="Online",
                        on_click=onButtonClick,
                    ),
                    ft.PopupMenuItem(
                        content=ft.Row(
                            [
                                ft.Icon(ft.icons.CIRCLE_ROUNDED, color="Red"),
                                ft.Text("Busy"),
                            ],
                        ),
                        data="Busy",  # Typo here: BUsy
                        on_click=onButtonClick,
                    ),
                ]
            )
        )

        return avatar_container


if __name__ == "__main__":
    def main(page: ft.Page):
        page.bgcolor = ft.colors.GREY_500
        page.add(Avatar())
    ft.app(target=main)

Note: When asking a question, create a minimal reproducible example, the current one you posted does not work out of the box as we don't know the class of the structure of the code. It will be easier for people to help if they can start to search a solution straight away instead of having to figure out how to run the example first.