如何从多个ipywidgets创建?

时间:2016-11-14 17:20:45

标签: python jupyter-notebook ipywidgets

假设我想要一个由IntText小部件和DropDown小部件组成的小部件,该小部件是这些小部件值的串联字符串。我该怎么办?

这是一次尝试:

import re
import ipywidgets as ipw

from IPython.display import display


class IntMultipliedDropdown:
    _VALUE_PATTERN = re.compile('(?P<num>\d+) (?P<option>\w+-?\w*)')

    def __init__(self, options, option_value, int_value=1):
        self.number = ipw.IntText(int_value)
        self.options = ipw.Dropdown(options=options, value=option_value)
        self.box = ipw.HBox([self.number, self.options])

        self.number.observe(self._on_changes, names='value')
        self.options.observe(self._on_changes, names='value')

        self._handelers = []

    def _on_changes(self, change):
        for handeler in self._handelers:
            handeler(self.value)

    @property
    def value(self):
        return "{} {}".format(self.number.value, self.options.value)

    @value.setter
    def value(self, value):
        match = re.search(self._VALUE_PATTERN, value)
        groupdict = match.groupdict()
        self.number.value = groupdict['num']
        self.options.value = groupdict['option']

    def _ipython_display_(self, **kwargs):
        return self.box._ipython_display_(**kwargs)

    def observe(self, handler):
        if handler not in self._handelers:
            self._handelers.append(handler)


mywidget = IntMultipliedDropdown(['apple', 'bed', 'cell'], 'cell')
mywidget.observe(print)

display(mywidget)
print('default value:', mywidget.value)

mywidget.value = '2 bed'

它有效,但有缺点。首先,当我设置mywidget.value时,被调用的函数被调用两次:数值变化和选项值变化。

第二个也是最糟糕的是我不能在Box小部件中使用这个小部件,如:

ipw.HBox([ipw.Label('Mylabel'), mywidget])

提出了什么:

ValueError: Can't clean for JSON: <__main__.IntMultipliedDropdown object at 0x7f7d604fff28>

有更好的解决方案吗?

2 个答案:

答案 0 :(得分:1)

  1. 您创建的课程不是小工具,但您确实模仿了某些行为(observedisplay)。这可能就是为什么你无法在HBox中显示它。如果要创建新窗口小部件,请从ipyw.Widget或任何其他窗口小部件继承。
  2. 您正在侦听两个基础窗口小部件,因此在更改其值时调用两个函数是正常的。如果您只想调用一个函数,请直接收听新小部件的value
  3. 通过继承HBox

    ,您就可以做到这一点
    import re
    import ipywidgets as ipw
    from traitlets import Unicode
    from IPython.display import display
    
    
    class IntMultipliedDropdown(ipw.HBox):
        _VALUE_PATTERN = re.compile('(?P<num>\d+) (?P<option>\w+-?\w*)')
        value = Unicode()
    
        def __init__(self, options, option_value, int_value=1, **kwargs):
            self.number = ipw.IntText(int_value)
            self.options = ipw.Dropdown(options=options, value=option_value)
    
            self._update_value()
    
            self.number.observe(self._update_value, names='value')
            self.options.observe(self._update_value, names='value')
            self.observe(self._update_children, names='value')
    
            super().__init__(children=[self.number, self.options], **kwargs)
    
    
        def _update_children(self, *args):
            match = re.search(self._VALUE_PATTERN, self.value)
            groupdict = match.groupdict()
            self.number.value = groupdict['num']
            self.options.value = groupdict['option']
    
        def _update_value(self, *args):
            self.value = "{} {}".format(self.number.value, self.options.value)
    
    mywidget = IntMultipliedDropdown(['apple', 'bed', 'cell'], 'cell')
    display(mywidget)
    

答案 1 :(得分:0)

可能有一个原因让您在创建新窗口小部件时遇到了所有麻烦,但为什么不使用the interactive function

类似的东西:

import ipywidgets as ipw
from ipywidgets import *

w_number = ipw.IntText(value = 1)
w_options = ipw.Dropdown(options = ['apple', 'bed', 'cell'], value ='cell')

mywidget_value = ''

def display_value(number, options):
    mywidget_value = str(number)+' '+options
    #print(mywidget_value)
    return mywidget_value

w_box = interactive(display_value, number=w_number, options=w_options)

display(w_box)

然后你有一个Box,你可以调整它的布局。您还可以使用w_box.kwargsw_box.result函数的返回值访问关键字参数,这是您要查找的2个小部件的连接字符串...