##// END OF EJS Templates
Merge pull request #7359 from jdfreder/tab-fix...
Min RK -
r19797:468962b1 merge
parent child Browse files
Show More
@@ -1,301 +1,325 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 "widgets/js/widget",
6 6 "base/js/utils",
7 7 "jquery",
8 8 "bootstrap",
9 9 ], function(widget, utils, $){
10 10
11 11 var AccordionView = widget.DOMWidgetView.extend({
12 12 initialize: function(){
13 13 AccordionView.__super__.initialize.apply(this, arguments);
14 14
15 15 this.containers = [];
16 16 this.model_containers = {};
17 17 this.children_views = new widget.ViewList(this.add_child_view, this.remove_child_view, this);
18 18 this.listenTo(this.model, 'change:children', function(model, value) {
19 19 this.children_views.update(value);
20 20 }, this);
21 21 },
22 22
23 23 render: function(){
24 24 /**
25 25 * Called when view is rendered.
26 26 */
27 27 var guid = 'panel-group' + utils.uuid();
28 28 this.$el
29 29 .attr('id', guid)
30 30 .addClass('panel-group');
31 31 this.model.on('change:selected_index', function(model, value, options) {
32 this.update_selected_index(model.previous('selected_index'), value, options);
32 this.update_selected_index(options);
33 33 }, this);
34 34 this.model.on('change:_titles', function(model, value, options) {
35 this.update_titles(value);
35 this.update_titles(options);
36 36 }, this);
37 37 this.on('displayed', function() {
38 38 this.update_titles();
39 39 }, this);
40 40 this.children_views.update(this.model.get('children'));
41 41 },
42 42
43 update_titles: function(titles) {
43 /**
44 * Update the contents of this view
45 *
46 * Called when the model is changed. The model may have been
47 * changed by another view or by a state update from the back-end.
48 */
49 update: function(options) {
50 this.update_titles();
51 this.update_selected_index(options);
52 return TabView.__super__.update.apply(this);
53 },
54
55 update_titles: function() {
44 56 /**
45 57 * Set tab titles
46 58 */
47 if (!titles) {
48 titles = this.model.get('_titles');
49 }
50
59 var titles = this.model.get('_titles');
51 60 var that = this;
52 61 _.each(titles, function(title, page_index) {
53 62 var accordian = that.containers[page_index];
54 63 if (accordian !== undefined) {
55 64 accordian
56 65 .find('.panel-heading')
57 66 .find('.accordion-toggle')
58 67 .text(title);
59 68 }
60 69 });
61 70 },
62 71
63 update_selected_index: function(old_index, new_index, options) {
72 update_selected_index: function(options) {
64 73 /**
65 74 * Only update the selection if the selection wasn't triggered
66 75 * by the front-end. It must be triggered by the back-end.
67 76 */
68 77 if (options === undefined || options.updated_view != this) {
78 var old_index = this.model.previous('selected_index');
79 var new_index = this.model.get('selected_index');
69 80 this.containers[old_index].find('.panel-collapse').collapse('hide');
70 81 if (0 <= new_index && new_index < this.containers.length) {
71 82 this.containers[new_index].find('.panel-collapse').collapse('show');
72 83 }
73 84 }
74 85 },
75 86
76 87 remove_child_view: function(view) {
77 88 /**
78 89 * Called when a child is removed from children list.
79 90 * TODO: does this handle two different views of the same model as children?
80 91 */
81 92 var model = view.model;
82 93 var accordion_group = this.model_containers[model.id];
83 94 this.containers.splice(accordion_group.container_index, 1);
84 95 delete this.model_containers[model.id];
85 96 accordion_group.remove();
86 97 },
87 98
88 99 add_child_view: function(model) {
89 100 /**
90 101 * Called when a child is added to children list.
91 102 */
92 103 var index = this.containers.length;
93 104 var uuid = utils.uuid();
94 105 var accordion_group = $('<div />')
95 106 .addClass('panel panel-default')
96 107 .appendTo(this.$el);
97 108 var accordion_heading = $('<div />')
98 109 .addClass('panel-heading')
99 110 .appendTo(accordion_group);
100 111 var that = this;
101 112 var accordion_toggle = $('<a />')
102 113 .addClass('accordion-toggle')
103 114 .attr('data-toggle', 'collapse')
104 115 .attr('data-parent', '#' + this.$el.attr('id'))
105 116 .attr('href', '#' + uuid)
106 117 .click(function(evt){
107 118
108 119 // Calling model.set will trigger all of the other views of the
109 120 // model to update.
110 121 that.model.set("selected_index", index, {updated_view: that});
111 122 that.touch();
112 123 })
113 124 .text('Page ' + index)
114 125 .appendTo(accordion_heading);
115 126 var accordion_body = $('<div />', {id: uuid})
116 127 .addClass('panel-collapse collapse')
117 128 .appendTo(accordion_group);
118 129 var accordion_inner = $('<div />')
119 130 .addClass('panel-body')
120 131 .appendTo(accordion_body);
121 132 var container_index = this.containers.push(accordion_group) - 1;
122 133 accordion_group.container_index = container_index;
123 134 this.model_containers[model.id] = accordion_group;
124 135
125 136 var dummy = $('<div/>');
126 137 accordion_inner.append(dummy);
127 138 return this.create_child_view(model).then(function(view) {
128 139 dummy.replaceWith(view.$el);
129 140 that.update();
130 141 that.update_titles();
131 142
132 143 // Trigger the displayed event of the child view.
133 144 that.after_displayed(function() {
134 145 view.trigger('displayed');
135 146 });
136 147 return view;
137 148 }).catch(utils.reject("Couldn't add child view to box", true));
138 149 },
139 150
140 151 remove: function() {
141 152 /**
142 153 * We remove this widget before removing the children as an optimization
143 154 * we want to remove the entire container from the DOM first before
144 155 * removing each individual child separately.
145 156 */
146 157 AccordionView.__super__.remove.apply(this, arguments);
147 158 this.children_views.remove();
148 159 },
149 160 });
150 161
151 162
152 163 var TabView = widget.DOMWidgetView.extend({
153 164 initialize: function() {
154 165 /**
155 166 * Public constructor.
156 167 */
157 168 TabView.__super__.initialize.apply(this, arguments);
158 169
159 170 this.containers = [];
160 171 this.children_views = new widget.ViewList(this.add_child_view, this.remove_child_view, this);
161 172 this.listenTo(this.model, 'change:children', function(model, value) {
162 173 this.children_views.update(value);
163 174 }, this);
164 175 },
165 176
166 177 render: function(){
167 178 /**
168 179 * Called when view is rendered.
169 180 */
170 181 var uuid = 'tabs'+utils.uuid();
171 182 var that = this;
172 183 this.$tabs = $('<div />', {id: uuid})
173 184 .addClass('nav')
174 185 .addClass('nav-tabs')
175 186 .appendTo(this.$el);
176 187 this.$tab_contents = $('<div />', {id: uuid + 'Content'})
177 188 .addClass('tab-content')
178 189 .appendTo(this.$el);
179 190 this.children_views.update(this.model.get('children'));
180 191 },
181 192
182 193 update_attr: function(name, value) {
183 194 /**
184 195 * Set a css attr of the widget view.
185 196 */
186 197 if (name == 'padding' || name == 'margin') {
187 198 this.$el.css(name, value);
188 199 } else {
189 200 this.$tabs.css(name, value);
190 201 }
191 202 },
192 203
193 204 remove_child_view: function(view) {
194 205 /**
195 206 * Called when a child is removed from children list.
196 207 */
197 208 this.containers.splice(view.parent_tab.tab_text_index, 1);
198 209 view.parent_tab.remove();
199 210 view.parent_container.remove();
200 211 view.remove();
201 212 },
202 213
203 214 add_child_view: function(model) {
204 215 /**
205 216 * Called when a child is added to children list.
206 217 */
207 218 var index = this.containers.length;
208 219 var uuid = utils.uuid();
209 220
210 221 var that = this;
211 222 var tab = $('<li />')
212 223 .css('list-style-type', 'none')
213 224 .appendTo(this.$tabs);
214
215 225
216 226 var tab_text = $('<a />')
217 227 .attr('href', '#' + uuid)
218 228 .attr('data-toggle', 'tab')
219 229 .text('Page ' + index)
220 230 .appendTo(tab)
221 231 .click(function (e) {
222 232
223 233 // Calling model.set will trigger all of the other views of the
224 234 // model to update.
225 235 that.model.set("selected_index", index, {updated_view: that});
226 236 that.touch();
227 237 that.select_page(index);
228 238 });
229 239 tab.tab_text_index = that.containers.push(tab_text) - 1;
230 240
231 241 var dummy = $('<div />');
232 242 var contents_div = $('<div />', {id: uuid})
233 243 .addClass('tab-pane')
234 244 .addClass('fade')
235 245 .append(dummy)
236 246 .appendTo(that.$tab_contents);
237 247
248 this.update();
238 249 return this.create_child_view(model).then(function(view) {
239 250 dummy.replaceWith(view.$el);
240 251 view.parent_tab = tab;
241 252 view.parent_container = contents_div;
242 253
243 254 // Trigger the displayed event of the child view.
244 255 that.after_displayed(function() {
245 256 view.trigger('displayed');
257 that.update();
246 258 });
247 259 return view;
248 260 }).catch(utils.reject("Couldn't add child view to box", true));
249 261 },
250 262
251 263 update: function(options) {
252 264 /**
253 265 * Update the contents of this view
254 266 *
255 267 * Called when the model is changed. The model may have been
256 268 * changed by another view or by a state update from the back-end.
257 269 */
258 if (options === undefined || options.updated_view != this) {
259 // Set tab titles
260 var titles = this.model.get('_titles');
261 var that = this;
262 _.each(titles, function(title, page_index) {
263 var tab_text = that.containers[page_index];
264 if (tab_text !== undefined) {
265 tab_text.text(title);
266 }
267 });
270 this.update_titles();
271 this.update_selected_index(options);
272 return TabView.__super__.update.apply(this);
273 },
268 274
275 /**
276 * Updates the tab page titles.
277 */
278 update_titles: function() {
279 var titles = this.model.get('_titles');
280 var that = this;
281 _.each(titles, function(title, page_index) {
282 var tab_text = that.containers[page_index];
283 if (tab_text !== undefined) {
284 tab_text.text(title);
285 }
286 });
287 },
288
289 /**
290 * Updates the tab page titles.
291 */
292 update_selected_index: function(options) {
293 if (options === undefined || options.updated_view != this) {
269 294 var selected_index = this.model.get('selected_index');
270 295 if (0 <= selected_index && selected_index < this.containers.length) {
271 296 this.select_page(selected_index);
272 297 }
273 298 }
274 return TabView.__super__.update.apply(this);
275 299 },
276 300
277 301 select_page: function(index) {
278 302 /**
279 303 * Select a page.
280 304 */
281 305 this.$tabs.find('li')
282 306 .removeClass('active');
283 307 this.containers[index].tab('show');
284 308 },
285 309
286 310 remove: function() {
287 311 /**
288 312 * We remove this widget before removing the children as an optimization
289 313 * we want to remove the entire container from the DOM first before
290 314 * removing each individual child separately.
291 315 */
292 316 TabView.__super__.remove.apply(this, arguments);
293 317 this.children_views.remove();
294 318 },
295 319 });
296 320
297 321 return {
298 322 'AccordionView': AccordionView,
299 323 'TabView': TabView,
300 324 };
301 325 });
@@ -1,584 +1,584 b''
1 1 {
2 2 "cells": [
3 3 {
4 4 "cell_type": "markdown",
5 5 "metadata": {},
6 6 "source": [
7 7 "[Index](Index.ipynb) - [Back](Widget Events.ipynb) - [Next](Custom Widget - Hello World.ipynb)"
8 8 ]
9 9 },
10 10 {
11 11 "cell_type": "code",
12 12 "execution_count": null,
13 13 "metadata": {
14 14 "collapsed": false
15 15 },
16 16 "outputs": [],
17 17 "source": [
18 18 "%%html\n",
19 19 "<style>\n",
20 20 ".example-container { background: #999999; padding: 2px; min-height: 100px; }\n",
21 21 ".example-container.sm { min-height: 50px; }\n",
22 22 ".example-box { background: #9999FF; width: 50px; height: 50px; text-align: center; vertical-align: middle; color: white; font-weight: bold; margin: 2px;}\n",
23 23 ".example-box.med { width: 65px; height: 65px; } \n",
24 24 ".example-box.lrg { width: 80px; height: 80px; } \n",
25 25 "</style>"
26 26 ]
27 27 },
28 28 {
29 29 "cell_type": "code",
30 30 "execution_count": null,
31 31 "metadata": {
32 32 "collapsed": false
33 33 },
34 34 "outputs": [],
35 35 "source": [
36 36 "from IPython.html import widgets\n",
37 37 "from IPython.display import display"
38 38 ]
39 39 },
40 40 {
41 41 "cell_type": "markdown",
42 42 "metadata": {
43 43 "slideshow": {
44 44 "slide_type": "slide"
45 45 }
46 46 },
47 47 "source": [
48 48 "# Widget Styling"
49 49 ]
50 50 },
51 51 {
52 52 "cell_type": "markdown",
53 53 "metadata": {},
54 54 "source": [
55 55 "## Basic styling"
56 56 ]
57 57 },
58 58 {
59 59 "cell_type": "markdown",
60 60 "metadata": {},
61 61 "source": [
62 62 "The widgets distributed with IPython can be styled by setting the following traits:\n",
63 63 "\n",
64 64 "- width \n",
65 65 "- height \n",
66 66 "- fore_color \n",
67 67 "- back_color \n",
68 68 "- border_color \n",
69 69 "- border_width \n",
70 70 "- border_style \n",
71 71 "- font_style \n",
72 72 "- font_weight \n",
73 73 "- font_size \n",
74 74 "- font_family \n",
75 75 "\n",
76 76 "The example below shows how a `Button` widget can be styled:"
77 77 ]
78 78 },
79 79 {
80 80 "cell_type": "code",
81 81 "execution_count": null,
82 82 "metadata": {
83 83 "collapsed": false
84 84 },
85 85 "outputs": [],
86 86 "source": [
87 87 "button = widgets.Button(\n",
88 88 " description='Hello World!',\n",
89 89 " width=100, # Integers are interpreted as pixel measurements.\n",
90 90 " height='2em', # em is valid HTML unit of measurement.\n",
91 91 " color='lime', # Colors can be set by name,\n",
92 92 " background_color='#0022FF', # and also by color code.\n",
93 93 " border_color='red')\n",
94 94 "display(button)"
95 95 ]
96 96 },
97 97 {
98 98 "cell_type": "markdown",
99 99 "metadata": {
100 100 "slideshow": {
101 101 "slide_type": "slide"
102 102 }
103 103 },
104 104 "source": [
105 105 "## Parent/child relationships"
106 106 ]
107 107 },
108 108 {
109 109 "cell_type": "markdown",
110 110 "metadata": {},
111 111 "source": [
112 112 "To display widget A inside widget B, widget A must be a child of widget B. Widgets that can contain other widgets have a **`children` attribute**. This attribute can be **set via a keyword argument** in the widget's constructor **or after construction**. Calling display on an **object with children automatically displays those children**, too."
113 113 ]
114 114 },
115 115 {
116 116 "cell_type": "code",
117 117 "execution_count": null,
118 118 "metadata": {
119 119 "collapsed": false
120 120 },
121 121 "outputs": [],
122 122 "source": [
123 123 "from IPython.display import display\n",
124 124 "\n",
125 125 "float_range = widgets.FloatSlider()\n",
126 126 "string = widgets.Text(value='hi')\n",
127 127 "container = widgets.Box(children=[float_range, string])\n",
128 128 "\n",
129 129 "container.border_color = 'red'\n",
130 130 "container.border_style = 'dotted'\n",
131 131 "container.border_width = 3\n",
132 132 "display(container) # Displays the `container` and all of it's children."
133 133 ]
134 134 },
135 135 {
136 136 "cell_type": "markdown",
137 137 "metadata": {},
138 138 "source": [
139 139 "### After the parent is displayed"
140 140 ]
141 141 },
142 142 {
143 143 "cell_type": "markdown",
144 144 "metadata": {
145 145 "slideshow": {
146 146 "slide_type": "slide"
147 147 }
148 148 },
149 149 "source": [
150 150 "Children **can be added to parents** after the parent has been displayed. The **parent is responsible for rendering its children**."
151 151 ]
152 152 },
153 153 {
154 154 "cell_type": "code",
155 155 "execution_count": null,
156 156 "metadata": {
157 157 "collapsed": false
158 158 },
159 159 "outputs": [],
160 160 "source": [
161 161 "container = widgets.Box()\n",
162 162 "container.border_color = 'red'\n",
163 163 "container.border_style = 'dotted'\n",
164 164 "container.border_width = 3\n",
165 165 "display(container)\n",
166 166 "\n",
167 167 "int_range = widgets.IntSlider()\n",
168 168 "container.children=[int_range]"
169 169 ]
170 170 },
171 171 {
172 172 "cell_type": "markdown",
173 173 "metadata": {
174 174 "slideshow": {
175 175 "slide_type": "slide"
176 176 }
177 177 },
178 178 "source": [
179 179 "## Fancy boxes"
180 180 ]
181 181 },
182 182 {
183 183 "cell_type": "markdown",
184 184 "metadata": {},
185 185 "source": [
186 "If you need to display a more complicated set of widgets, there are **specialized containers** that you can use. To display **multiple sets of widgets**, you can use an **`Accordion` or a `Tab` in combination with one `Box` per set of widgets** (as seen below). The \"pages\" of these widgets are their children. To set the titles of the pages, one must **call `set_title` after the widget has been displayed**."
186 "If you need to display a more complicated set of widgets, there are **specialized containers** that you can use. To display **multiple sets of widgets**, you can use an **`Accordion` or a `Tab` in combination with one `Box` per set of widgets** (as seen below). The \"pages\" of these widgets are their children. To set the titles of the pages, one can **call `set_title`**."
187 187 ]
188 188 },
189 189 {
190 190 "cell_type": "markdown",
191 191 "metadata": {},
192 192 "source": [
193 193 "### Accordion"
194 194 ]
195 195 },
196 196 {
197 197 "cell_type": "code",
198 198 "execution_count": null,
199 199 "metadata": {
200 200 "collapsed": false
201 201 },
202 202 "outputs": [],
203 203 "source": [
204 204 "name1 = widgets.Text(description='Location:')\n",
205 205 "zip1 = widgets.BoundedIntText(description='Zip:', min=0, max=99999)\n",
206 206 "page1 = widgets.Box(children=[name1, zip1])\n",
207 207 "\n",
208 208 "name2 = widgets.Text(description='Location:')\n",
209 209 "zip2 = widgets.BoundedIntText(description='Zip:', min=0, max=99999)\n",
210 210 "page2 = widgets.Box(children=[name2, zip2])\n",
211 211 "\n",
212 212 "accord = widgets.Accordion(children=[page1, page2])\n",
213 213 "display(accord)\n",
214 214 "\n",
215 215 "accord.set_title(0, 'From')\n",
216 216 "accord.set_title(1, 'To')"
217 217 ]
218 218 },
219 219 {
220 220 "cell_type": "markdown",
221 221 "metadata": {
222 222 "slideshow": {
223 223 "slide_type": "slide"
224 224 }
225 225 },
226 226 "source": [
227 227 "### TabWidget"
228 228 ]
229 229 },
230 230 {
231 231 "cell_type": "code",
232 232 "execution_count": null,
233 233 "metadata": {
234 234 "collapsed": false
235 235 },
236 236 "outputs": [],
237 237 "source": [
238 238 "name = widgets.Text(description='Name:')\n",
239 239 "color = widgets.Dropdown(description='Color:', values=['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 243 "gender = widgets.RadioButtons(description='Gender:', values=['male', 'female'])\n",
244 244 "page2 = widgets.Box(children=[age, gender])\n",
245 245 "\n",
246 246 "tabs = widgets.Tab(children=[page1, page2])\n",
247 247 "display(tabs)\n",
248 248 "\n",
249 249 "tabs.set_title(0, 'Name')\n",
250 250 "tabs.set_title(1, 'Details')"
251 251 ]
252 252 },
253 253 {
254 254 "cell_type": "markdown",
255 255 "metadata": {
256 256 "slideshow": {
257 257 "slide_type": "slide"
258 258 }
259 259 },
260 260 "source": [
261 261 "# Alignment"
262 262 ]
263 263 },
264 264 {
265 265 "cell_type": "markdown",
266 266 "metadata": {},
267 267 "source": [
268 268 "Most widgets have a **`description` attribute**, which allows a label for the widget to be defined.\n",
269 269 "The label of the widget **has a fixed minimum width**.\n",
270 270 "The text of the label is **always right aligned and the widget is left aligned**:"
271 271 ]
272 272 },
273 273 {
274 274 "cell_type": "code",
275 275 "execution_count": null,
276 276 "metadata": {
277 277 "collapsed": false
278 278 },
279 279 "outputs": [],
280 280 "source": [
281 281 "display(widgets.Text(description=\"a:\"))\n",
282 282 "display(widgets.Text(description=\"aa:\"))\n",
283 283 "display(widgets.Text(description=\"aaa:\"))"
284 284 ]
285 285 },
286 286 {
287 287 "cell_type": "markdown",
288 288 "metadata": {
289 289 "slideshow": {
290 290 "slide_type": "slide"
291 291 }
292 292 },
293 293 "source": [
294 294 "If a **label is longer** than the minimum width, the **widget is shifted to the right**:"
295 295 ]
296 296 },
297 297 {
298 298 "cell_type": "code",
299 299 "execution_count": null,
300 300 "metadata": {
301 301 "collapsed": false
302 302 },
303 303 "outputs": [],
304 304 "source": [
305 305 "display(widgets.Text(description=\"a:\"))\n",
306 306 "display(widgets.Text(description=\"aa:\"))\n",
307 307 "display(widgets.Text(description=\"aaa:\"))\n",
308 308 "display(widgets.Text(description=\"aaaaaaaaaaaaaaaaaa:\"))"
309 309 ]
310 310 },
311 311 {
312 312 "cell_type": "markdown",
313 313 "metadata": {
314 314 "slideshow": {
315 315 "slide_type": "slide"
316 316 }
317 317 },
318 318 "source": [
319 319 "If a `description` is **not set** for the widget, the **label is not displayed**:"
320 320 ]
321 321 },
322 322 {
323 323 "cell_type": "code",
324 324 "execution_count": null,
325 325 "metadata": {
326 326 "collapsed": false
327 327 },
328 328 "outputs": [],
329 329 "source": [
330 330 "display(widgets.Text(description=\"a:\"))\n",
331 331 "display(widgets.Text(description=\"aa:\"))\n",
332 332 "display(widgets.Text(description=\"aaa:\"))\n",
333 333 "display(widgets.Text())"
334 334 ]
335 335 },
336 336 {
337 337 "cell_type": "markdown",
338 338 "metadata": {
339 339 "slideshow": {
340 340 "slide_type": "slide"
341 341 }
342 342 },
343 343 "source": [
344 344 "## Flex boxes"
345 345 ]
346 346 },
347 347 {
348 348 "cell_type": "markdown",
349 349 "metadata": {},
350 350 "source": [
351 351 "Widgets can be aligned using the `FlexBox`, `HBox`, and `VBox` widgets."
352 352 ]
353 353 },
354 354 {
355 355 "cell_type": "markdown",
356 356 "metadata": {
357 357 "slideshow": {
358 358 "slide_type": "slide"
359 359 }
360 360 },
361 361 "source": [
362 362 "### Application to widgets"
363 363 ]
364 364 },
365 365 {
366 366 "cell_type": "markdown",
367 367 "metadata": {},
368 368 "source": [
369 369 "Widgets display vertically by default:"
370 370 ]
371 371 },
372 372 {
373 373 "cell_type": "code",
374 374 "execution_count": null,
375 375 "metadata": {
376 376 "collapsed": false
377 377 },
378 378 "outputs": [],
379 379 "source": [
380 380 "buttons = [widgets.Button(description=str(i)) for i in range(3)]\n",
381 381 "display(*buttons)"
382 382 ]
383 383 },
384 384 {
385 385 "cell_type": "markdown",
386 386 "metadata": {
387 387 "slideshow": {
388 388 "slide_type": "slide"
389 389 }
390 390 },
391 391 "source": [
392 392 "### Using hbox"
393 393 ]
394 394 },
395 395 {
396 396 "cell_type": "markdown",
397 397 "metadata": {},
398 398 "source": [
399 399 "To make widgets display horizontally, you need to **child them to a `HBox` widget**."
400 400 ]
401 401 },
402 402 {
403 403 "cell_type": "code",
404 404 "execution_count": null,
405 405 "metadata": {
406 406 "collapsed": false
407 407 },
408 408 "outputs": [],
409 409 "source": [
410 410 "container = widgets.HBox(children=buttons)\n",
411 411 "display(container)"
412 412 ]
413 413 },
414 414 {
415 415 "cell_type": "markdown",
416 416 "metadata": {},
417 417 "source": [
418 418 "By setting the width of the container to 100% and its `pack` to `center`, you can center the buttons."
419 419 ]
420 420 },
421 421 {
422 422 "cell_type": "code",
423 423 "execution_count": null,
424 424 "metadata": {
425 425 "collapsed": false
426 426 },
427 427 "outputs": [],
428 428 "source": [
429 429 "container.width = '100%'\n",
430 430 "container.pack = 'center'"
431 431 ]
432 432 },
433 433 {
434 434 "cell_type": "markdown",
435 435 "metadata": {
436 436 "slideshow": {
437 437 "slide_type": "slide"
438 438 }
439 439 },
440 440 "source": [
441 441 "## Visibility"
442 442 ]
443 443 },
444 444 {
445 445 "cell_type": "markdown",
446 446 "metadata": {},
447 447 "source": [
448 448 "Sometimes it is necessary to **hide or show widgets** in place, **without having to re-display** the widget.\n",
449 449 "The `visible` property of widgets can be used to hide or show **widgets that have already been displayed** (as seen below). The `visible` property can be:\n",
450 450 "* `True` - the widget is displayed\n",
451 451 "* `False` - the widget is hidden, and the empty space where the widget would be is collapsed\n",
452 452 "* `None` - the widget is hidden, and the empty space where the widget would be is shown"
453 453 ]
454 454 },
455 455 {
456 456 "cell_type": "code",
457 457 "execution_count": null,
458 458 "metadata": {
459 459 "collapsed": false
460 460 },
461 461 "outputs": [],
462 462 "source": [
463 463 "w1 = widgets.Latex(value=\"First line\")\n",
464 464 "w2 = widgets.Latex(value=\"Second line\")\n",
465 465 "w3 = widgets.Latex(value=\"Third line\")\n",
466 466 "display(w1, w2, w3)"
467 467 ]
468 468 },
469 469 {
470 470 "cell_type": "code",
471 471 "execution_count": null,
472 472 "metadata": {
473 473 "collapsed": true
474 474 },
475 475 "outputs": [],
476 476 "source": [
477 477 "w2.visible=None"
478 478 ]
479 479 },
480 480 {
481 481 "cell_type": "code",
482 482 "execution_count": null,
483 483 "metadata": {
484 484 "collapsed": false
485 485 },
486 486 "outputs": [],
487 487 "source": [
488 488 "w2.visible=False"
489 489 ]
490 490 },
491 491 {
492 492 "cell_type": "code",
493 493 "execution_count": null,
494 494 "metadata": {
495 495 "collapsed": false
496 496 },
497 497 "outputs": [],
498 498 "source": [
499 499 "w2.visible=True"
500 500 ]
501 501 },
502 502 {
503 503 "cell_type": "markdown",
504 504 "metadata": {
505 505 "slideshow": {
506 506 "slide_type": "slide"
507 507 }
508 508 },
509 509 "source": [
510 510 "### Another example"
511 511 ]
512 512 },
513 513 {
514 514 "cell_type": "markdown",
515 515 "metadata": {},
516 516 "source": [
517 517 "In the example below, a form is rendered, which conditionally displays widgets depending on the state of other widgets. Try toggling the student checkbox."
518 518 ]
519 519 },
520 520 {
521 521 "cell_type": "code",
522 522 "execution_count": null,
523 523 "metadata": {
524 524 "collapsed": false
525 525 },
526 526 "outputs": [],
527 527 "source": [
528 528 "form = widgets.VBox()\n",
529 529 "first = widgets.Text(description=\"First Name:\")\n",
530 530 "last = widgets.Text(description=\"Last Name:\")\n",
531 531 "\n",
532 532 "student = widgets.Checkbox(description=\"Student:\", value=False)\n",
533 533 "school_info = widgets.VBox(visible=False, children=[\n",
534 534 " widgets.Text(description=\"School:\"),\n",
535 535 " widgets.IntText(description=\"Grade:\", min=0, max=12)\n",
536 536 " ])\n",
537 537 "\n",
538 538 "pet = widgets.Text(description=\"Pet's Name:\")\n",
539 539 "form.children = [first, last, student, school_info, pet]\n",
540 540 "display(form)\n",
541 541 "\n",
542 542 "def on_student_toggle(name, value):\n",
543 543 " if value:\n",
544 544 " school_info.visible = True\n",
545 545 " else:\n",
546 546 " school_info.visible = False\n",
547 547 "student.on_trait_change(on_student_toggle, 'value')\n"
548 548 ]
549 549 },
550 550 {
551 551 "cell_type": "markdown",
552 552 "metadata": {},
553 553 "source": [
554 554 "[Index](Index.ipynb) - [Back](Widget Events.ipynb) - [Next](Custom Widget - Hello World.ipynb)"
555 555 ]
556 556 }
557 557 ],
558 558 "metadata": {
559 559 "cell_tags": [
560 560 [
561 561 "<None>",
562 562 null
563 563 ]
564 564 ],
565 565 "kernelspec": {
566 566 "display_name": "IPython (Python 2)",
567 567 "name": "python2"
568 568 },
569 569 "language_info": {
570 570 "codemirror_mode": {
571 571 "name": "ipython",
572 572 "version": 2
573 573 },
574 574 "file_extension": ".py",
575 575 "mimetype": "text/x-python",
576 576 "name": "python",
577 577 "nbconvert_exporter": "python",
578 578 "pygments_lexer": "ipython2",
579 579 "version": "2.7.6"
580 580 }
581 581 },
582 582 "nbformat": 4,
583 583 "nbformat_minor": 0
584 584 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now