python ipyvuetify how to combine multiple widgets into a class

478 Views Asked by At

With ipyvuetify, I have to repeatedly use a pair of Textfield and Textarea in an ExpansionPanel. Their interactions are linked as they are represent two fields from a DB line.

Is it possible to create a custom widget, which contains the different nested ipyvuetify widgets and allows to interact with the whole group as a single object and also is rendered like a widgte when called?

Something like this:

import ipyvuetify as vue

Class customWidget():
    def __init__(self, titleText, bodyText):

        title = vue.TextField(class_='mb-n2', label='Label')
        title.value = titleText
        title.on_event('click.stop', None)
        openIn= vue.Btn(text=True, max_width='10px', children=[vue.Icon(children=['open_in_new'])])
        openIn.on_event('click.stop', None)


        note = vue.Textarea(class_='ma-0 pa-0 text-xs-caption', name='markerA', solo=True, elevation=0, outlined=True)
        note.value = bodyText

        panel = vue.ExpansionPanel(class_='ma-0 pa-0 text-xs-caption', children=[
            vue.ExpansionPanelHeader(class_='ma-0 pa-0 pl-5 pr-5', children=[title, openIn]),
            vue.ExpansionPanelContent(class_='ma-0 pa-0 text-xs-caption', children=[note]),
        ])

        self.expansionPanel = vue.ExpansionPanels(v_model=[0], multiple=True, focusable=False, children=[panel])
2

There are 2 best solutions below

1
On BEST ANSWER

The easiest solution I found so far is to make the customWidget class inherit from the ipyvuetify widget I want to display and prepopulate it with the nested other widgets in the constructor.

This works pretty well and can be set up to still have access to each element even in deeply nested structures.

Care should be taken not to overwrite attributes names which ipyvuetify already uses.

In the case above my solution looks like this:


import ipyvuetify as vue

class customWidget(vue.ExpansionPanels):

    def __init__(self, titleText, bodyText, **kwargs):

        children = []

        title = vue.TextField(
            class_ = 'mb-n2',
            label = 'Label'
        )
        title.value = titleText
        title.on_event('click.stop', None)


        openIn = vue.Btn(
            text = True,
            max_width = '10px',
            children = [
                vue.Icon(
                    children = ['open_in_new']
                )
            ]
        )
        openIn.on_event('click.stop', None)


        note = vue.Textarea(
            class_ = 'ma-0 pa-0 text-xs-caption',
            name = 'markerA',
            solo = True,
            elevation = 0,
            outlined = True
        )
        note.value = bodyText

        panel = vue.ExpansionPanel(
            class_ = 'ma-0 pa-0 text-xs-caption',
            children = [
                vue.ExpansionPanelHeader(
                    class_ = 'ma-0 pa-0 pl-5 pr-5',
                    children = [
                        title,
                        openIn
                    ]
                ),
                vue.ExpansionPanelContent(
                    class_ = 'ma-0 pa-0 text-xs-caption',
                    children = [
                        note
                    ]
                ),
            ]
        )

        # add elements to kwargs, this allows to still pass others via the instance call
        kwargs['v_model'] = [0]
        kwargs['children'] = [panel]
        kwargs['multiple'] = True
        kwargs['focusable'] = False
        
        super().__init__(**kwargs)

        
1
On

Wouldn't you want to include something like:

def display(self):
     display(self.expansionPanel)

then you can go:

c1=customWidget('whatever tieltle','whatever bodytext')

c1.display()