##// END OF EJS Templates
Merge pull request #6890 from bollwyvl/widget-select-multiple...
Jonathan Frederic -
r20301:c8aa3bbf merge
parent child Browse files
Show More
@@ -5,8 +5,9 b' define(['
5 5 "widgets/js/widget",
6 6 "base/js/utils",
7 7 "jquery",
8 "underscore",
8 9 "bootstrap",
9 ], function(widget, utils, $){
10 ], function(widget, utils, $, _){
10 11
11 12 var DropdownView = widget.DOMWidgetView.extend({
12 13 render : function(){
@@ -52,19 +53,19 b' define(['
52 53 /**
53 54 * Update the contents of this view
54 55 *
55 * Called when the model is changed. The model may have been
56 * Called when the model is changed. The model may have been
56 57 * changed by another view or by a state update from the back-end.
57 58 */
58 59
59 60 if (options === undefined || options.updated_view != this) {
60 var selected_item_text = this.model.get('value_name');
61 var selected_item_text = this.model.get('selected_label');
61 62 if (selected_item_text.trim().length === 0) {
62 63 this.$droplabel.html(" ");
63 64 } else {
64 65 this.$droplabel.text(selected_item_text);
65 66 }
66 67
67 var items = this.model.get('_value_names');
68 var items = this.model.get('_options_labels');
68 69 var $replace_droplist = $('<ul />')
69 70 .addClass('dropdown-menu');
70 71 // Copy the style
@@ -150,7 +151,7 b' define(['
150 151 * Calling model.set will trigger all of the other views of the
151 152 * model to update.
152 153 */
153 this.model.set('value_name', $(e.target).text(), {updated_view: this});
154 this.model.set('selected_label', $(e.target).text(), {updated_view: this});
154 155 this.touch();
155 156
156 157 // Manually hide the droplist.
@@ -188,7 +189,7 b' define(['
188 189 */
189 190 if (options === undefined || options.updated_view != this) {
190 191 // Add missing items to the DOM.
191 var items = this.model.get('_value_names');
192 var items = this.model.get('_options_labels');
192 193 var disabled = this.model.get('disabled');
193 194 var that = this;
194 195 _.each(items, function(item, index) {
@@ -209,7 +210,7 b' define(['
209 210 }
210 211
211 212 var $item_element = that.$container.find(item_query);
212 if (that.model.get('value_name') == item) {
213 if (that.model.get('selected_label') == item) {
213 214 $item_element.prop('checked', true);
214 215 } else {
215 216 $item_element.prop('checked', false);
@@ -263,7 +264,7 b' define(['
263 264 * Calling model.set will trigger all of the other views of the
264 265 * model to update.
265 266 */
266 this.model.set('value_name', $(e.target).val(), {updated_view: this});
267 this.model.set('selected_label', $(e.target).val(), {updated_view: this});
267 268 this.touch();
268 269 },
269 270 });
@@ -305,7 +306,7 b' define(['
305 306 */
306 307 if (options === undefined || options.updated_view != this) {
307 308 // Add missing items to the DOM.
308 var items = this.model.get('_value_names');
309 var items = this.model.get('_options_labels');
309 310 var disabled = this.model.get('disabled');
310 311 var that = this;
311 312 var item_html;
@@ -328,7 +329,7 b' define(['
328 329 .on('click', $.proxy(that.handle_click, that));
329 330 that.update_style_traits($item_element);
330 331 }
331 if (that.model.get('value_name') == item) {
332 if (that.model.get('selected_label') == item) {
332 333 $item_element.addClass('active');
333 334 } else {
334 335 $item_element.removeClass('active');
@@ -410,7 +411,7 b' define(['
410 411 * Calling model.set will trigger all of the other views of the
411 412 * model to update.
412 413 */
413 this.model.set('value_name', $(e.target).attr('value'), {updated_view: this});
414 this.model.set('selected_label', $(e.target).attr('value'), {updated_view: this});
414 415 this.touch();
415 416 },
416 417 });
@@ -430,7 +431,8 b' define(['
430 431 this.$listbox = $('<select />')
431 432 .addClass('widget-listbox form-control')
432 433 .attr('size', 6)
433 .appendTo(this.$el);
434 .appendTo(this.$el)
435 .on('change', $.proxy(this.handle_change, this));
434 436 this.update();
435 437 },
436 438
@@ -443,7 +445,7 b' define(['
443 445 */
444 446 if (options === undefined || options.updated_view != this) {
445 447 // Add missing items to the DOM.
446 var items = this.model.get('_value_names');
448 var items = this.model.get('_options_labels');
447 449 var that = this;
448 450 _.each(items, function(item, index) {
449 451 var item_query = 'option[data-value="' + encodeURIComponent(item) + '"]';
@@ -451,14 +453,14 b' define(['
451 453 $('<option />')
452 454 .text(item)
453 455 .attr('data-value', encodeURIComponent(item))
454 .attr('value_name', item)
455 .appendTo(that.$listbox)
456 .on('click', $.proxy(that.handle_click, that));
456 .attr('selected_label', item)
457 .on("click", $.proxy(that.handle_click, that))
458 .appendTo(that.$listbox);
457 459 }
458 460 });
459 461
460 462 // Select the correct element
461 this.$listbox.val(this.model.get('value_name'));
463 this.$listbox.val(this.model.get('selected_label'));
462 464
463 465 // Disable listbox if needed
464 466 var disabled = this.model.get('disabled');
@@ -504,20 +506,68 b' define(['
504 506
505 507 handle_click: function (e) {
506 508 /**
507 * Handle when a value is clicked.
509 * Handle when a new value is clicked.
510 */
511 this.$listbox.val($(e.target).val()).change();
512 },
513
514 handle_change: function (e) {
515 /**
516 * Handle when a new value is selected.
508 517 *
509 518 * Calling model.set will trigger all of the other views of the
510 519 * model to update.
511 520 */
512 this.model.set('value_name', $(e.target).text(), {updated_view: this});
521 this.model.set('selected_label', this.$listbox.val(), {updated_view: this});
513 522 this.touch();
514 },
523 },
524 });
525
526
527 var SelectMultipleView = SelectView.extend({
528 render: function(){
529 /**
530 * Called when view is rendered.
531 */
532 SelectMultipleView.__super__.render.apply(this);
533 this.$el.removeClass('widget-select')
534 .addClass('widget-select-multiple');
535 this.$listbox.attr('multiple', true)
536 .on('change', $.proxy(this.handle_change, this));
537 return this;
538 },
539
540 update: function(){
541 /**
542 * Update the contents of this view
543 *
544 * Called when the model is changed. The model may have been
545 * changed by another view or by a state update from the back-end.
546 */
547 SelectMultipleView.__super__.update.apply(this, arguments);
548 this.$listbox.val(this.model.get('selected_labels'));
549 },
550
551 handle_change: function (e) {
552 /**
553 * Handle when a new value is selected.
554 *
555 * Calling model.set will trigger all of the other views of the
556 * model to update.
557 */
558 this.model.set('selected_labels',
559 (this.$listbox.val() || []).slice(),
560 {updated_view: this});
561 this.touch();
562 },
515 563 });
516 564
565
517 566 return {
518 567 'DropdownView': DropdownView,
519 568 'RadioButtonsView': RadioButtonsView,
520 569 'ToggleButtonsView': ToggleButtonsView,
521 570 'SelectView': SelectView,
571 'SelectMultipleView': SelectMultipleView,
522 572 };
523 573 });
@@ -43,11 +43,11 b' casper.notebook_test(function () {'
43 43
44 44 //values=["' + selection_values + '"[i] for i in range(4)]
45 45 selection_index = this.append_cell(
46 'values=["' + selection_values + '"[i] for i in range(4)]\n' +
47 'selection = [widgets.Dropdown(values=values),\n' +
48 ' widgets.ToggleButtons(values=values),\n' +
49 ' widgets.RadioButtons(values=values),\n' +
50 ' widgets.Select(values=values)]\n' +
46 'options=["' + selection_values + '"[i] for i in range(4)]\n' +
47 'selection = [widgets.Dropdown(options=options),\n' +
48 ' widgets.ToggleButtons(options=options),\n' +
49 ' widgets.RadioButtons(options=options),\n' +
50 ' widgets.Select(options=options)]\n' +
51 51 '[display(selection[i]) for i in range(4)]\n' +
52 52 'for widget in selection:\n' +
53 53 ' def handle_change(name,old,new):\n' +
@@ -136,9 +136,9 b' casper.notebook_test(function () {'
136 136 index = this.append_cell(
137 137 'from copy import copy\n' +
138 138 'for widget in selection:\n' +
139 ' d = copy(widget.values)\n' +
139 ' d = copy(widget.options)\n' +
140 140 ' d.append("z")\n' +
141 ' widget.values = d\n' +
141 ' widget.options = d\n' +
142 142 'selection[0].value = "z"');
143 143 this.execute_cell_then(index, function(index){
144 144
@@ -7,7 +7,7 b' from .widget_float import FloatText, BoundedFloatText, FloatSlider, FloatProgres'
7 7 from .widget_image import Image
8 8 from .widget_int import IntText, BoundedIntText, IntSlider, IntProgress, IntRangeSlider
9 9 from .widget_output import Output
10 from .widget_selection import RadioButtons, ToggleButtons, Dropdown, Select
10 from .widget_selection import RadioButtons, ToggleButtons, Dropdown, Select, SelectMultiple
11 11 from .widget_selectioncontainer import Tab, Accordion
12 12 from .widget_string import HTML, Latex, Text, Textarea
13 13 from .interaction import interact, interactive, fixed, interact_manual
@@ -59,7 +59,7 b' def _widget_abbrev_single_value(o):'
59 59 if isinstance(o, string_types):
60 60 return Text(value=unicode_type(o))
61 61 elif isinstance(o, dict):
62 return Dropdown(values=o)
62 return Dropdown(options=o)
63 63 elif isinstance(o, bool):
64 64 return Checkbox(value=o)
65 65 elif isinstance(o, float):
@@ -76,7 +76,7 b' def _widget_abbrev(o):'
76 76 float_or_int = (float, int)
77 77 if isinstance(o, (list, tuple)):
78 78 if o and all(isinstance(x, string_types) for x in o):
79 return Dropdown(values=[unicode_type(k) for k in o])
79 return Dropdown(options=[unicode_type(k) for k in o])
80 80 elif _matches(o, (float_or_int, float_or_int)):
81 81 min, max, value = _get_min_max_value(o[0], o[1])
82 82 if all(isinstance(_, int) for _ in o):
@@ -118,7 +118,7 b' def test_single_value_dict():'
118 118 check_widget(w,
119 119 cls=widgets.Dropdown,
120 120 description='d',
121 values=d,
121 options=d,
122 122 value=next(iter(d.values())),
123 123 )
124 124
@@ -229,7 +229,7 b' def test_list_tuple_str():'
229 229 d = dict(
230 230 cls=widgets.Dropdown,
231 231 value=first,
232 values=values
232 options=values
233 233 )
234 234 check_widgets(c, tup=d, lis=d)
235 235
@@ -287,12 +287,12 b' def test_default_values():'
287 287 ),
288 288 h=dict(
289 289 cls=widgets.Dropdown,
290 values={'a': 1, 'b': 2},
290 options={'a': 1, 'b': 2},
291 291 value=2
292 292 ),
293 293 j=dict(
294 294 cls=widgets.Dropdown,
295 values=['hi', 'there'],
295 options=['hi', 'there'],
296 296 value='there'
297 297 ),
298 298 )
@@ -310,12 +310,12 b' def test_default_out_of_bounds():'
310 310 ),
311 311 h=dict(
312 312 cls=widgets.Dropdown,
313 values={'a': 1},
313 options={'a': 1},
314 314 value=1,
315 315 ),
316 316 j=dict(
317 317 cls=widgets.Dropdown,
318 values=['hi', 'there'],
318 options=['hi', 'there'],
319 319 value='hi',
320 320 ),
321 321 )
@@ -634,3 +634,59 b' def test_float_range_logic():'
634 634 frsw(lower=5)
635 635 with nt.assert_raises(ValueError):
636 636 frsw(upper=5)
637
638
639 def test_multiple_selection():
640 smw = widgets.SelectMultiple
641
642 # degenerate multiple select
643 w = smw()
644 check_widget(w, value=tuple(), options=None, selected_labels=tuple())
645
646 # don't accept random other value when no options
647 with nt.assert_raises(KeyError):
648 w.value = (2,)
649 check_widget(w, value=tuple(), selected_labels=tuple())
650
651 # basic multiple select
652 w = smw(options=[(1, 1)], value=[1])
653 check_widget(w, cls=smw, value=(1,), options=[(1, 1)])
654
655 # don't accept random other value
656 with nt.assert_raises(KeyError):
657 w.value = w.value + (2,)
658 check_widget(w, value=(1,), selected_labels=(1,))
659
660 # change options
661 w.options = w.options + [(2, 2)]
662 check_widget(w, options=[(1, 1), (2,2)])
663
664 # change value
665 w.value = w.value + (2,)
666 check_widget(w, value=(1, 2), selected_labels=(1, 2))
667
668 # change value name
669 w.selected_labels = (1,)
670 check_widget(w, value=(1,))
671
672 # don't accept random other names when no options
673 with nt.assert_raises(KeyError):
674 w.selected_labels = (3,)
675 check_widget(w, value=(1,))
676
677 # don't accept selected_label (from superclass)
678 with nt.assert_raises(AttributeError):
679 w.selected_label = 3
680
681 # don't return selected_label (from superclass)
682 with nt.assert_raises(AttributeError):
683 print(w.selected_label)
684
685 # dict style
686 w.options = {1: 1}
687 check_widget(w, options={1: 1})
688
689 # updating
690 with nt.assert_raises(KeyError):
691 w.value = (2,)
692 check_widget(w, options={1: 1})
@@ -30,38 +30,38 b' from IPython.utils.warn import DeprecatedClass'
30 30 class _Selection(DOMWidget):
31 31 """Base class for Selection widgets
32 32
33 ``values`` can be specified as a list or dict. If given as a list,
33 ``options`` can be specified as a list or dict. If given as a list,
34 34 it will be transformed to a dict of the form ``{str(value):value}``.
35 35 """
36 36
37 37 value = Any(help="Selected value")
38 value_name = Unicode(help="The name of the selected value", sync=True)
39 values = Any(help="""List of (key, value) tuples or dict of values that the
38 selected_label = Unicode(help="The label of the selected value", sync=True)
39 options = Any(help="""List of (key, value) tuples or dict of values that the
40 40 user can select.
41 41
42 42 The keys of this list are the strings that will be displayed in the UI,
43 43 representing the actual Python choices.
44 44
45 The keys of this list are also available as _value_names.
45 The keys of this list are also available as _options_labels.
46 46 """)
47 47
48 _values_dict = Dict()
49 _value_names = Tuple(sync=True)
50 _value_values = Tuple()
48 _options_dict = Dict()
49 _options_labels = Tuple(sync=True)
50 _options_values = Tuple()
51 51
52 52 disabled = Bool(False, help="Enable or disable user changes", sync=True)
53 53 description = Unicode(help="Description of the value this widget represents", sync=True)
54 54
55 55 def __init__(self, *args, **kwargs):
56 56 self.value_lock = Lock()
57 self.values_lock = Lock()
58 self.on_trait_change(self._values_readonly_changed, ['_values_dict', '_value_names', '_value_values', '_values'])
59 if 'values' in kwargs:
60 self.values = kwargs.pop('values')
57 self.options_lock = Lock()
58 self.on_trait_change(self._options_readonly_changed, ['_options_dict', '_options_labels', '_options_values', '_options'])
59 if 'options' in kwargs:
60 self.options = kwargs.pop('options')
61 61 DOMWidget.__init__(self, *args, **kwargs)
62 self._value_in_values()
62 self._value_in_options()
63 63
64 def _make_values(self, x):
64 def _make_options(self, x):
65 65 # If x is a dict, convert it to list format.
66 66 if isinstance(x, (OrderedDict, dict)):
67 67 return [(k, v) for k, v in x.items()]
@@ -70,7 +70,7 b' class _Selection(DOMWidget):'
70 70 if not isinstance(x, (list, tuple)):
71 71 raise ValueError('x')
72 72
73 # If x is an ordinary list, use the values as names.
73 # If x is an ordinary list, use the option values as names.
74 74 for y in x:
75 75 if not isinstance(y, (list, tuple)) or len(y) < 2:
76 76 return [(i, i) for i in x]
@@ -78,42 +78,42 b' class _Selection(DOMWidget):'
78 78 # Value is already in the correct format.
79 79 return x
80 80
81 def _values_changed(self, name, old, new):
82 """Handles when the values tuple has been changed.
81 def _options_changed(self, name, old, new):
82 """Handles when the options tuple has been changed.
83 83
84 Setting values implies setting value names from the keys of the dict.
85 """
86 if self.values_lock.acquire(False):
84 Setting options implies setting option labels from the keys of the dict.
85 """
86 if self.options_lock.acquire(False):
87 87 try:
88 self.values = new
88 self.options = new
89 89
90 values = self._make_values(new)
91 self._values_dict = {i[0]: i[1] for i in values}
92 self._value_names = [i[0] for i in values]
93 self._value_values = [i[1] for i in values]
94 self._value_in_values()
90 options = self._make_options(new)
91 self._options_dict = {i[0]: i[1] for i in options}
92 self._options_labels = [i[0] for i in options]
93 self._options_values = [i[1] for i in options]
94 self._value_in_options()
95 95 finally:
96 self.values_lock.release()
96 self.options_lock.release()
97 97
98 def _value_in_values(self):
98 def _value_in_options(self):
99 99 # ensure that the chosen value is one of the choices
100 if self._value_values:
101 if self.value not in self._value_values:
102 self.value = next(iter(self._value_values))
103 100
104 def _values_readonly_changed(self, name, old, new):
105 if not self.values_lock.locked():
106 raise TraitError("`.%s` is a read-only trait. Use the `.values` tuple instead." % name)
101 if self._options_values:
102 if self.value not in self._options_values:
103 self.value = next(iter(self._options_values))
107 104
105 def _options_readonly_changed(self, name, old, new):
106 if not self.options_lock.locked():
107 raise TraitError("`.%s` is a read-only trait. Use the `.options` tuple instead." % name)
108 108 def _value_changed(self, name, old, new):
109 109 """Called when value has been changed"""
110 110 if self.value_lock.acquire(False):
111 111 try:
112 112 # Reverse dictionary lookup for the value name
113 for k,v in self._values_dict.items():
113 for k, v in self._options_dict.items():
114 114 if new == v:
115 115 # set the selected value name
116 self.value_name = k
116 self.selected_label = k
117 117 return
118 118 # undo the change, and raise KeyError
119 119 self.value = old
@@ -121,11 +121,68 b' class _Selection(DOMWidget):'
121 121 finally:
122 122 self.value_lock.release()
123 123
124 def _value_name_changed(self, name, old, new):
124 def _selected_label_changed(self, name, old, new):
125 125 """Called when the value name has been changed (typically by the frontend)."""
126 126 if self.value_lock.acquire(False):
127 127 try:
128 self.value = self._values_dict[new]
128 self.value = self._options_dict[new]
129 finally:
130 self.value_lock.release()
131
132
133 class _MultipleSelection(_Selection):
134 """Base class for MultipleSelection widgets.
135
136 As with ``_Selection``, ``options`` can be specified as a list or dict. If
137 given as a list, it will be transformed to a dict of the form
138 ``{str(value): value}``.
139
140 Despite their names, ``value`` (and ``selected_label``) will be tuples, even
141 if only a single option is selected.
142 """
143
144 value = Tuple(help="Selected values")
145 selected_labels = Tuple(help="The labels of the selected options",
146 sync=True)
147
148 @property
149 def selected_label(self):
150 raise AttributeError(
151 "Does not support selected_label, use selected_labels")
152
153 def _value_in_options(self):
154 # ensure that the chosen value is one of the choices
155 if self.options:
156 old_value = self.value or []
157 new_value = []
158 for value in old_value:
159 if value in self._options_dict.values():
160 new_value.append(value)
161 if new_value:
162 self.value = new_value
163 else:
164 self.value = [next(iter(self._options_dict.values()))]
165
166 def _value_changed(self, name, old, new):
167 """Called when value has been changed"""
168 if self.value_lock.acquire(False):
169 try:
170 self.selected_labels = [
171 self._options_labels[self._options_values.index(v)]
172 for v in new
173 ]
174 except:
175 self.value = old
176 raise KeyError(new)
177 finally:
178 self.value_lock.release()
179
180 def _selected_labels_changed(self, name, old, new):
181 """Called when the selected label has been changed (typically by the
182 frontend)."""
183 if self.value_lock.acquire(False):
184 try:
185 self.value = [self._options_dict[name] for name in new]
129 186 finally:
130 187 self.value_lock.release()
131 188
@@ -165,6 +222,15 b' class Select(_Selection):'
165 222 _view_name = Unicode('SelectView', sync=True)
166 223
167 224
225 @register('IPython.SelectMultiple')
226 class SelectMultiple(_MultipleSelection):
227 """Listbox that allows many items to be selected at any given time.
228 Despite their names, inherited from ``_Selection``, the currently chosen
229 option values, ``value``, or their labels, ``selected_labels`` must both be
230 updated with a list-like object."""
231 _view_name = Unicode('SelectMultipleView', sync=True)
232
233
168 234 # Remove in IPython 4.0
169 235 ToggleButtonsWidget = DeprecatedClass(ToggleButtons, 'ToggleButtonsWidget')
170 236 DropdownWidget = DeprecatedClass(Dropdown, 'DropdownWidget')
@@ -86,7 +86,7 b''
86 86 },
87 87 "outputs": [],
88 88 "source": [
89 "exporter_names = widgets.Dropdown(values=get_export_names(), value='html')\n",
89 "exporter_names = widgets.Dropdown(options=get_export_names(), value='html')\n",
90 90 "export_button = widgets.Button(description=\"Export\")\n",
91 91 "download_link = widgets.HTML(visible=False)"
92 92 ]
@@ -274,7 +274,7 b''
274 274 "cell_type": "markdown",
275 275 "metadata": {},
276 276 "source": [
277 "There are four widgets that can be used to display single selection lists. All four inherit from the same base class. You can specify the **enumeration of selectables by passing a list**. You can **also specify the enumeration as a dictionary**, in which case the **keys will be used as the item displayed** in the list and the corresponding **value will be returned** when an item is selected."
277 "There are four widgets that can be used to display single selection lists, and one that can be used to display multiple selection lists. All inherit from the same base class. You can specify the **enumeration of selectable options by passing a list**. You can **also specify the enumeration as a dictionary**, in which case the **keys will be used as the item displayed** in the list and the corresponding **value will be returned** when an item is selected."
278 278 ]
279 279 },
280 280 {
@@ -298,7 +298,7 b''
298 298 "source": [
299 299 "from IPython.display import display\n",
300 300 "w = widgets.Dropdown(\n",
301 " values=['1', '2', '3'],\n",
301 " options=['1', '2', '3'],\n",
302 302 " value='2',\n",
303 303 " description='Number:',\n",
304 304 ")\n",
@@ -332,7 +332,7 b''
332 332 "outputs": [],
333 333 "source": [
334 334 "w = widgets.Dropdown(\n",
335 " values={'One': 1, 'Two': 2, 'Three': 3},\n",
335 " options={'One': 1, 'Two': 2, 'Three': 3},\n",
336 336 " value=2,\n",
337 337 " description='Number:',\n",
338 338 ")\n",
@@ -371,7 +371,7 b''
371 371 "source": [
372 372 "widgets.RadioButtons(\n",
373 373 " description='Pizza topping:',\n",
374 " values=['pepperoni', 'pineapple', 'anchovies'],\n",
374 " options=['pepperoni', 'pineapple', 'anchovies'],\n",
375 375 ")"
376 376 ]
377 377 },
@@ -396,7 +396,7 b''
396 396 "source": [
397 397 "widgets.Select(\n",
398 398 " description='OS:',\n",
399 " values=['Linux', 'Windows', 'OSX'],\n",
399 " options=['Linux', 'Windows', 'OSX'],\n",
400 400 ")"
401 401 ]
402 402 },
@@ -421,12 +421,46 b''
421 421 "source": [
422 422 "widgets.ToggleButtons(\n",
423 423 " description='Speed:',\n",
424 " values=['Slow', 'Regular', 'Fast'],\n",
424 " options=['Slow', 'Regular', 'Fast'],\n",
425 425 ")"
426 426 ]
427 427 },
428 428 {
429 429 "cell_type": "markdown",
430 "metadata": {},
431 "source": [
432 "### SelectMultiple\n",
433 "Multiple values can be selected with <kbd>shift</kbd> and <kbd>ctrl</kbd> pressed and mouse clicks or arrow keys."
434 ]
435 },
436 {
437 "cell_type": "code",
438 "execution_count": null,
439 "metadata": {
440 "collapsed": true
441 },
442 "outputs": [],
443 "source": [
444 "w = widgets.SelectMultiple(\n",
445 " description=\"Fruits\",\n",
446 " options=['Apples', 'Oranges', 'Pears']\n",
447 ")\n",
448 "display(w)"
449 ]
450 },
451 {
452 "cell_type": "code",
453 "execution_count": null,
454 "metadata": {
455 "collapsed": false
456 },
457 "outputs": [],
458 "source": [
459 "w.value"
460 ]
461 },
462 {
463 "cell_type": "markdown",
430 464 "metadata": {
431 465 "slideshow": {
432 466 "slide_type": "slide"
@@ -236,11 +236,11 b''
236 236 "outputs": [],
237 237 "source": [
238 238 "name = widgets.Text(description='Name:')\n",
239 "color = widgets.Dropdown(description='Color:', values=['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'])\n",
239 "color = widgets.Dropdown(description='Color:', options=['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'])\n",
240 240 "page1 = widgets.Box(children=[name, color])\n",
241 241 "\n",
242 242 "age = widgets.IntSlider(description='Age:', min=0, max=120, value=50)\n",
243 "gender = widgets.RadioButtons(description='Gender:', values=['male', 'female'])\n",
243 "gender = widgets.RadioButtons(description='Gender:', options=['male', 'female'])\n",
244 244 "page2 = widgets.Box(children=[age, gender])\n",
245 245 "\n",
246 246 "tabs = widgets.Tab(children=[page1, page2])\n",
General Comments 0
You need to be logged in to leave comments. Login now