flexx icon indicating copy to clipboard operation
flexx copied to clipboard

Set a PyWidget in e.g. StackLayout fails because its not using the sub Widget

Open matkuki opened this issue 5 years ago • 4 comments

Hi,

I have an application that looks like this:

  • A main PyWidget object that acts like a hub widget, with some smaller widgets and a StackLayout for displaying Page widgets
  • Many Page widgets that are used to display some widgets, with each having read/update Python functions

Now if I make the page a Widget, it is displayed correctly but I cannot use the Python read/update functions. But if I make it a PyWidget, there is nothing displayed inside the main StackLayout when I show a Page inside it.

Is there a way to make this work without breaking up the Page widget into two?

Thanks, Matic

matkuki avatar Jun 12 '19 07:06 matkuki

My current working solution is to have two objects (one JS on Py) and a creation function like so:

class JsPage(flx.Widget):
    py_page = flx.AnyProp(None, settable=True)

    def init(self, py_page):
        self.py_page = py_page
        # Create all widgets

    @flx.action
    def set_value_of_widget_0(self, value):
        # Set value

    @flx.action
    def set_value_of_widget_1(self, value):
        # Set another value

    ...

class PyPage(flx.PyComponent):
    def set_js_page(self, js_page):
        self.js_page= js_page

    def read(self):
        # Read and store all data

   def update(self):
       self.js_page.set_value_of_widget_0(self.data[0])
       self.js_page.set_value_of_widget_1(self.data[1])
       ...

def create_page():
    py_page = PyPage()
    js_page = Agregat(py_page)
    worker.set_js_page(js_page )
    return js_page

Why does the JsPage have a reference to a PyPage? Because I want to access everything from a single object, the JsPage object:

# Create
page = create_page()
# Read
page.py_page.read()
# Update
page.py_page.update()

Is there a simple way of integrating the JsPage and the PyPage as one?

Thanks

matkuki avatar Jun 12 '19 18:06 matkuki

This should work:

from flexx import flx


class MainPage(flx.PyWidget):

    def init(self):

        with flx.TabLayout():
            Page("page 1")
            Page("page 2")
            Page("page 3")


class Page(flx.PyWidget):

    def init(self, name):
        flx.Button(text=name)


m = flx.launch(MainPage, "chrome-browser")
flx.run()

almarklein avatar Jun 17 '19 09:06 almarklein

Yes, that works. But this does not:

from flexx import flx, event


class MainPage(flx.PyWidget):

    def init(self):
        with flx.HBox():
            with flx.VBox():
                self.buta = flx.Button(text='1')
                self.butb = flx.Button(text='2')
                self.butc = flx.Button(text='3')
                flx.Widget(flex=1)
            with flx.StackLayout(flex=1) as self.sl:
                self.buta.w = Page("page 1")
                self.butb.w = Page("page 2")
                self.butc.w = Page("page 3")

    @event.reaction('buta.pointer_down', 'butb.pointer_down', 'butc.pointer_down')
    def _stacked_current(self, *events):
        button = events[-1].source
        print(button.w)
        self.sl.set_current(button.w)

class Page(flx.PyWidget):

    def init(self, name):
        flx.Button(text=name)


m = flx.launch(MainPage, "firefox-browser")
flx.run()

When a button from 1 to 3 on the left side is pushed, an empty widget is displayed in the StackLayout instead of the corresponding page, even though the page object is printed correctly in the event? print(button.w) in the above code Any Ideas?

matkuki avatar Jun 17 '19 16:06 matkuki

Aah, this is because technically a PyWidget is a PyComponent that wraps a Widget. It works if you change it to self.sl.set_current(button.w._jswidget).

This is a bit of a hack (using the private attribute), so we'd need to do something to make this work correctly. Maybe simply exposing the subwidget with a public attribute. Or convert when serializing a PyWidget. mmm, this needs some thoughts ...

almarklein avatar Jun 19 '19 08:06 almarklein