0

假设我想要一个由 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>

有更好的解决方案吗?

4

2 回答 2

2
  1. 您创建的类不是小部件,尽管您确实模仿了一些行为(observe, display)。这可能就是为什么你不能让它显示在HBox. 如果你想创建一个新的小部件,继承自ipyw.Widget或任何其他小部件。
  2. 您有两个正在侦听的底层小部件,因此当您更改它们的值时调用两个函数是正常的。如果您只想调用一个函数,请直接收听value您的新小部件。

这就是你可以通过继承来做到这一点的方法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)
于 2017-02-14T23:35:16.247 回答
1

您费尽心思创建新小部件可能是有原因的,但为什么不使用interactive功能呢?

就像是:

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.kwargs或函数的返回值w_box.result,这是您要查找的 2 个小部件的串联字符串...

于 2016-11-15T17:02:48.113 回答