##// END OF EJS Templates
Updated widget tutorial,...
Jonathan Frederic -
Show More
@@ -1,5 +1,6
1 1 {
2 2 "metadata": {
3 "celltoolbar": "Slideshow",
3 4 "name": "",
4 5 "signature": "sha256:9763f005a69fc65b7a7977011d9604b09b4959e7293cbbb2cf35cc482380e671"
5 6 },
@@ -16,36 +17,90
16 17 ]
17 18 },
18 19 {
19 "cell_type": "heading",
20 "level": 1,
20 "cell_type": "code",
21 "collapsed": false,
22 "input": [
23 "from __future__ import print_function # For py 2.7 compat"
24 ],
25 "language": "python",
21 26 "metadata": {},
22 "source": [
23 "Building a Custom Widget"
24 ]
27 "outputs": [],
28 "prompt_number": 3
25 29 },
26 30 {
27 31 "cell_type": "code",
28 32 "collapsed": false,
29 33 "input": [
30 "from __future__ import print_function # For py 2.7 compat"
34 "%%html\n",
35 "<style>div.text_cell.cell.rendered.slideshow-slide { margin-top: 5em !important; }</style>"
31 36 ],
32 37 "language": "python",
33 38 "metadata": {},
34 "outputs": [],
35 "prompt_number": 1
39 "outputs": [
40 {
41 "html": [
42 "<style>div.text_cell.cell.rendered.slideshow-slide { margin-top: 5em !important; }</style>"
43 ],
44 "metadata": {},
45 "output_type": "display_data",
46 "text": [
47 "<IPython.core.display.HTML object>"
48 ]
49 }
50 ],
51 "prompt_number": 4
52 },
53 {
54 "cell_type": "heading",
55 "level": 1,
56 "metadata": {
57 "slideshow": {
58 "slide_type": "slide"
59 }
60 },
61 "source": [
62 "Building a Custom Widget"
63 ]
36 64 },
37 65 {
38 66 "cell_type": "markdown",
39 67 "metadata": {},
40 68 "source": [
41 "The widget framework is built on top of the Comm framework (short for communication). The Comm framework is a framework that allows you send/receive JSON messages to/from the front-end. To create a custom widget, you need to define the widget both in the back-end and in the front-end. "
69 "The widget framework is built **on top of the Comm framework** (short for communication). The Comm framework is a framework that **allows you send/receive JSON messages** to/from the front-end (as seen below).\n",
70 "\n",
71 "** Insert framework layer image here. **\n",
72 "\n",
73 "To create a custom widget, you need to **define the widget both in the back-end and in the front-end**. "
42 74 ]
43 75 },
44 76 {
45 77 "cell_type": "heading",
46 "level": 2,
78 "level": 1,
79 "metadata": {
80 "slideshow": {
81 "slide_type": "slide"
82 }
83 },
84 "source": [
85 "Building a Custom Widget"
86 ]
87 },
88 {
89 "cell_type": "markdown",
47 90 "metadata": {},
48 91 "source": [
92 "To get started, you'll create a **simple hello world widget**. Later you'll build on this foundation to make more complex widgets."
93 ]
94 },
95 {
96 "cell_type": "heading",
97 "level": 2,
98 "metadata": {
99 "slideshow": {
100 "slide_type": "slide"
101 }
102 },
103 "source": [
49 104 "Back-end (Python)"
50 105 ]
51 106 },
@@ -61,22 +116,26
61 116 "cell_type": "markdown",
62 117 "metadata": {},
63 118 "source": [
64 "To define a widget, you must inherit from the Widget or DOMWidget base class. If you intend for your widget to be displayed in the IPython notebook, you'll need to inherit from the DOMWidget. The DOMWidget class itself inherits from the Widget class. The Widget class is useful for cases in which the Widget is not meant to be displayed directly in the notebook, but instead as a child of another rendering environment. For example, if you wanted to create a D3.js widget (a popular WebGL library), you would implement the rendering window as a DOMWidget and any 3D objects or lights meant to be rendered in that window as Widgets."
119 "To define a widget, you must inherit from the **Widget or DOMWidget** base class. If you intend for your widget to be **displayed in the IPython notebook**, you'll need to **inherit from the DOMWidget**. The DOMWidget class itself inherits from the Widget class. The Widget class is useful for cases in which the **Widget is not meant to be displayed directly in the notebook**, but **instead as a child of another rendering environment**. For example, if you wanted to create a three.js widget (a popular WebGL library), you would implement the rendering window as a DOMWidget and any 3D objects or lights meant to be rendered in that window as Widgets."
65 120 ]
66 121 },
67 122 {
68 123 "cell_type": "heading",
69 124 "level": 3,
70 "metadata": {},
125 "metadata": {
126 "slideshow": {
127 "slide_type": "slide"
128 }
129 },
71 130 "source": [
72 "sync=True traitlets"
131 "_view_name"
73 132 ]
74 133 },
75 134 {
76 135 "cell_type": "markdown",
77 136 "metadata": {},
78 137 "source": [
79 "Inheriting from the DOMWidget does not tell the widget framework what front-end widget to associate with your back-end widget. Instead, you must tell it yourself by defining a specially named Traitlet, `_view_name` (as seen below)."
138 "Inheriting from the DOMWidget does not tell the widget framework what front-end widget to associate with your back-end widget. Instead, you must tell it yourself by defining a **specially named Traitlet, `_view_name`** (as seen below)."
80 139 ]
81 140 },
82 141 {
@@ -95,16 +154,32
95 154 "prompt_number": 2
96 155 },
97 156 {
157 "cell_type": "heading",
158 "level": 3,
159 "metadata": {
160 "slideshow": {
161 "slide_type": "slide"
162 }
163 },
164 "source": [
165 "sync=True traitlets"
166 ]
167 },
168 {
98 169 "cell_type": "markdown",
99 170 "metadata": {},
100 171 "source": [
101 "Traitlets is an IPython library for defining type-safe properties on configurable objects. For this tutorial you do not need to worry about the *configurable* piece of the traitlets machinery. The `sync=True` keyword argument tells the widget framework to handle synchronizing that value to the front-end. Without `sync=True`, the front-end would have no knowledge of `_view_name`."
172 "**Traitlets is** an IPython library for defining **type-safe properties** on configurable objects. For this tutorial you do not need to worry about the *configurable* piece of the traitlets machinery. The **`sync=True` keyword argument** tells the widget framework to **handle synchronizing that value to the front-end**. Without `sync=True`, the front-end would have no knowledge of `_view_name`."
102 173 ]
103 174 },
104 175 {
105 176 "cell_type": "heading",
106 177 "level": 3,
107 "metadata": {},
178 "metadata": {
179 "slideshow": {
180 "slide_type": "slide"
181 }
182 },
108 183 "source": [
109 184 "Other traitlet types"
110 185 ]
@@ -113,7 +188,7
113 188 "cell_type": "markdown",
114 189 "metadata": {},
115 190 "source": [
116 "Unicode is not the only Traitlet type, there are many more: \n",
191 "Unicode, used for _view_name, is not the only Traitlet type, there are many more some of which are listed below: \n",
117 192 "\n",
118 193 "- Any\n",
119 194 "- Bool\n",
@@ -144,13 +219,17
144 219 "- Type\n",
145 220 "- Unicode\n",
146 221 "\n",
147 "Not all of these traitlets can be synchronized across the network, only the JSON-able traits and Widget instances will be synchronized."
222 "**Not all of these traitlets can be synchronized** across the network, **only the JSON-able** traits and **Widget instances** will be synchronized."
148 223 ]
149 224 },
150 225 {
151 226 "cell_type": "heading",
152 227 "level": 2,
153 "metadata": {},
228 "metadata": {
229 "slideshow": {
230 "slide_type": "slide"
231 }
232 },
154 233 "source": [
155 234 "Front-end (JavaScript)"
156 235 ]
@@ -167,22 +246,26
167 246 "cell_type": "markdown",
168 247 "metadata": {},
169 248 "source": [
170 "The IPython widget framework front-end relies heavily on [Backbone.js](http://backbonejs.org/). Backbone.js is an MVC (model view controller) framework. Widgets defined in the back-end are automatically synchronized with generic Backbone.js models in the front-end. The traitlets are added to the front-end instance automatically on first state push. The `_view_name` trait that you defined earlier is used by the widget framework to create the corresponding Backbone.js view and link that view to the generic model."
249 "The IPython widget framework front-end relies heavily on [Backbone.js](http://backbonejs.org/). **Backbone.js is an MVC (model view controller) framework**. Widgets defined in the back-end are automatically **synchronized with generic Backbone.js models** in the front-end. The traitlets are added to the front-end instance **automatically on first state push**. The **`_view_name` trait** that you defined earlier is used by the widget framework to create the corresponding Backbone.js view and **link that view to the model**."
171 250 ]
172 251 },
173 252 {
174 253 "cell_type": "heading",
175 254 "level": 3,
176 "metadata": {},
255 "metadata": {
256 "slideshow": {
257 "slide_type": "slide"
258 }
259 },
177 260 "source": [
178 "Defining a view"
261 "Import the WidgetManager"
179 262 ]
180 263 },
181 264 {
182 265 "cell_type": "markdown",
183 266 "metadata": {},
184 267 "source": [
185 "You first need to import the WidgetManager. You will use it later to register your view by name (the same name you used in the back-end). To import the widget manager, use the `require` method of [require.js](http://requirejs.org/) (as seen below)."
268 "You first need to **import the WidgetManager**. You will use it later to register your view by name (the same name you used in the back-end). To import the widget manager, use the `require` method of [require.js](http://requirejs.org/) (as seen below)."
186 269 ]
187 270 },
188 271 {
@@ -215,10 +298,22
215 298 "prompt_number": 3
216 299 },
217 300 {
301 "cell_type": "heading",
302 "level": 3,
303 "metadata": {
304 "slideshow": {
305 "slide_type": "slide"
306 }
307 },
308 "source": [
309 "Define the view"
310 ]
311 },
312 {
218 313 "cell_type": "markdown",
219 314 "metadata": {},
220 315 "source": [
221 "Next define your widget view class. Inherit from the `DOMWidgetView` by using the `.extend` method. Register the view class with the widget manager by calling `.register_widget_view`. The first parameter is the widget view name (`_view_name` that you defined earlier in Python) and the second is a handle to the class type."
316 "Next define your widget view class. **Inherit from the `DOMWidgetView`** by using the `.extend` method. Register the view class with the widget manager by calling **`.register_widget_view`**. The **first parameter is the widget view name** (`_view_name` that you defined earlier in Python) and the **second is a handle to the class type**."
222 317 ]
223 318 },
224 319 {
@@ -262,13 +357,25
262 357 ]
263 358 }
264 359 ],
265 "prompt_number": 4
360 "prompt_number": 2
361 },
362 {
363 "cell_type": "heading",
364 "level": 3,
365 "metadata": {
366 "slideshow": {
367 "slide_type": "slide"
368 }
369 },
370 "source": [
371 "Render method"
372 ]
266 373 },
267 374 {
268 375 "cell_type": "markdown",
269 376 "metadata": {},
270 377 "source": [
271 "Lastly, override the base `render` method of the view to define custom rendering logic. A handle to the widget's default div element can be acquired via `this.$el`. The `$el` property is a [jQuery](http://jquery.com/) object handle (which can be thought of as a supercharged version of the normal DOM element's handle)."
378 "Lastly, **override the base `render` method** of the view to define custom rendering logic. A handle to the widget's default div element can be acquired via **`this.$el`**. The `$el` property is a **[jQuery](http://jquery.com/) object handle** (which can be thought of as a supercharged version of the normal DOM element's handle)."
272 379 ]
273 380 },
274 381 {
@@ -321,7 +428,11
321 428 {
322 429 "cell_type": "heading",
323 430 "level": 2,
324 "metadata": {},
431 "metadata": {
432 "slideshow": {
433 "slide_type": "slide"
434 }
435 },
325 436 "source": [
326 437 "Test"
327 438 ]
@@ -347,7 +458,11
347 458 {
348 459 "cell_type": "heading",
349 460 "level": 2,
350 "metadata": {},
461 "metadata": {
462 "slideshow": {
463 "slide_type": "slide"
464 }
465 },
351 466 "source": [
352 467 "Making the widget stateful"
353 468 ]
@@ -356,7 +471,7
356 471 "cell_type": "markdown",
357 472 "metadata": {},
358 473 "source": [
359 "There is not much that you can do with the above example that you can't do with the IPython display framework. To change this, you will make the widget stateful. Instead of displaying a static \"hello world\" message, it will display a string set by the back-end. First you need to add the traitlet in the back-end. Use the name of `value` to stay consistent with the rest of the widget framework and to allow your widget to be used with interact."
474 "There is not much that you can do with the above example that you can't do with the IPython display framework. To change this, you will make the widget stateful. Instead of displaying a static \"hello world\" message, it will **display a string set by the back-end**. First you need to **add a traitlet in the back-end**. Use the name of **`value` to stay consistent** with the rest of the widget framework and to **allow your widget to be used with interact**."
360 475 ]
361 476 },
362 477 {
@@ -369,28 +484,47
369 484 ],
370 485 "language": "python",
371 486 "metadata": {},
372 "outputs": [],
373 "prompt_number": 7
487 "outputs": [
488 {
489 "ename": "NameError",
490 "evalue": "name 'widgets' is not defined",
491 "output_type": "pyerr",
492 "traceback": [
493 "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
494 "\u001b[0;32m<ipython-input-5-18ff342e181d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mclass\u001b[0m \u001b[0mHelloWidget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidgets\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mDOMWidget\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0m_view_name\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mUnicode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'HelloView'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msync\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mUnicode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Hello World!'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msync\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
495 "\u001b[0;31mNameError\u001b[0m: name 'widgets' is not defined"
496 ]
497 }
498 ],
499 "prompt_number": 5
374 500 },
375 501 {
376 502 "cell_type": "heading",
377 503 "level": 3,
378 "metadata": {},
504 "metadata": {
505 "slideshow": {
506 "slide_type": "slide"
507 }
508 },
379 509 "source": [
380 "Backbone.js model"
510 "Accessing the model from the view"
381 511 ]
382 512 },
383 513 {
384 514 "cell_type": "markdown",
385 515 "metadata": {},
386 516 "source": [
387 "To access the model associate with a view instance, use the `model` property of the view. `get` and `set` methods are used to interact with the Backbone model. `get` is trivial, however you have to be careful when using `set`. After calling the model `set` you need call the view's `touch` method. This associates the `set` operation with a particular view so output will be routed to the correct IPython cell. The model also has a `on` method which allows you to listen to events triggered by the model (like value changes)."
517 "To access the model associate with a view instance, use the **`model` property** of the view. **`get` and `set`** methods are used to interact with the Backbone model. **`get` is trivial**, however you have to **be careful when using `set`**. **After calling the model `set`** you need call the **view's `touch` method**. This associates the `set` operation with a particular view so **output will be routed to the correct cell**. The model also has a **`on` method** which allows you to listen to events triggered by the model (like value changes)."
388 518 ]
389 519 },
390 520 {
391 521 "cell_type": "heading",
392 522 "level": 3,
393 "metadata": {},
523 "metadata": {
524 "slideshow": {
525 "slide_type": "slide"
526 }
527 },
394 528 "source": [
395 529 "Rendering model contents"
396 530 ]
@@ -399,7 +533,7
399 533 "cell_type": "markdown",
400 534 "metadata": {},
401 535 "source": [
402 "By replacing the string literal with a call to `model.get`, the view will now display the value of the back-end upon display. However, it will not update itself to a new value when the value changes."
536 "By **replacing the string literal with a call to `model.get`**, the view will now display the **value of the back-end upon display**. However, it will not update itself to a new value when the value changes."
403 537 ]
404 538 },
405 539 {
@@ -445,13 +579,25
445 579 ]
446 580 }
447 581 ],
448 "prompt_number": 8
582 "prompt_number": 6
583 },
584 {
585 "cell_type": "heading",
586 "level": 3,
587 "metadata": {
588 "slideshow": {
589 "slide_type": "slide"
590 }
591 },
592 "source": [
593 "Dynamic updates"
594 ]
449 595 },
450 596 {
451 597 "cell_type": "markdown",
452 598 "metadata": {},
453 599 "source": [
454 "To get the view to update itself dynamically, register a function to update the view's value when the model's `value` property changes. This can be done using the `model.on` method. The `on` method takes three parameters, an event name, callback handle, and callback context. The Backbone event named `change` will fire whenever the model changes. By appending `:value` to it, you tell Backbone to only listen to the change event of the `value` property (as seen below)."
600 "To get the view to **update itself dynamically**, register a function to update the view's value when the model's `value` property changes. This can be done using the **`model.on` method**. The `on` method takes three parameters, an event name, callback handle, and callback context. The Backbone **event named `change`** will fire whenever the model changes. By **appending `:value`** to it, you tell Backbone to only listen to the change event of the `value` property (as seen below)."
455 601 ]
456 602 },
457 603 {
@@ -514,7 +660,11
514 660 {
515 661 "cell_type": "heading",
516 662 "level": 2,
517 "metadata": {},
663 "metadata": {
664 "slideshow": {
665 "slide_type": "slide"
666 }
667 },
518 668 "source": [
519 669 "Test"
520 670 ]
@@ -544,6 +694,18
544 694 },
545 695 {
546 696 "cell_type": "heading",
697 "level": 1,
698 "metadata": {
699 "slideshow": {
700 "slide_type": "slide"
701 }
702 },
703 "source": [
704 "Finishing"
705 ]
706 },
707 {
708 "cell_type": "heading",
547 709 "level": 2,
548 710 "metadata": {},
549 711 "source": [
@@ -554,13 +716,17
554 716 "cell_type": "markdown",
555 717 "metadata": {},
556 718 "source": [
557 "The examples above dump the value directly into the DOM. There is no way for you to interact with this dumped data in the front-end. To create an example that accepts input, you will have to do something more than blindly dumping the contents of value into the DOM. For this part of the tutorial, you will use a jQuery spinner to display and accept input in the front-end. IPython currently lacks a spinner implementation so this widget will be unique."
719 "The examples above dump the value directly into the DOM. There is no way for you to interact with this dumped data in the front-end. To create an example that **accepts input**, you will have to do something more than blindly dumping the contents of value into the DOM. In this part of the tutorial, you will **use a jQuery spinner** to display and accept input in the front-end. IPython currently lacks a spinner implementation so this widget will be unique."
558 720 ]
559 721 },
560 722 {
561 723 "cell_type": "heading",
562 724 "level": 3,
563 "metadata": {},
725 "metadata": {
726 "slideshow": {
727 "slide_type": "slide"
728 }
729 },
564 730 "source": [
565 731 "Update the Python code"
566 732 ]
@@ -569,7 +735,7
569 735 "cell_type": "markdown",
570 736 "metadata": {},
571 737 "source": [
572 "You will need to change the type of the value traitlet to `Int`. It also makes sense to change the name of the widget to something more appropriate, like `SpinnerWidget`."
738 "You will need to change the type of the **value traitlet to `Int`**. It also makes sense to **change the name of the widget** to something more appropriate, like `SpinnerWidget`."
573 739 ]
574 740 },
575 741 {
@@ -589,7 +755,11
589 755 {
590 756 "cell_type": "heading",
591 757 "level": 3,
592 "metadata": {},
758 "metadata": {
759 "slideshow": {
760 "slide_type": "slide"
761 }
762 },
593 763 "source": [
594 764 "Updating the Javascript code"
595 765 ]
@@ -598,7 +768,7
598 768 "cell_type": "markdown",
599 769 "metadata": {},
600 770 "source": [
601 "The [jQuery docs for the spinner control](https://jqueryui.com/spinner/) say to use `.spinner` to create a spinner in an element. Calling `.spinner` on `$el` will create a spinner inside `$el`. Make sure to update the widget name here too so it's the same as `_view_name` in the back-end."
771 "The [jQuery docs for the spinner control](https://jqueryui.com/spinner/) say to use **`.spinner` to create a spinner** in an element. Calling **`.spinner` on `$el` will create a spinner inside `$el`**. Make sure to **update the widget name here too** so it's the same as `_view_name` in the back-end."
602 772 ]
603 773 },
604 774 {
@@ -673,10 +843,22
673 843 "prompt_number": 13
674 844 },
675 845 {
846 "cell_type": "heading",
847 "level": 3,
848 "metadata": {
849 "slideshow": {
850 "slide_type": "slide"
851 }
852 },
853 "source": [
854 "Getting and setting the value"
855 ]
856 },
857 {
676 858 "cell_type": "markdown",
677 859 "metadata": {},
678 860 "source": [
679 "To set the value of the spinner on update, you need to use jQuery's spinner API. `spinner.spinner('value', new)` will set the value of the spinner. Add that code to the `value_changed` method to make the spinner update with the value stored in the back-end. Using jQuery's spinner API, you can add a function to handle the spinner `change` event by passing it in when constructing the spinner. Inside the `change` event, call `model.set` to set the value and then `touch` to inform the framework that this view was the view that caused the change to the model. Note: The `var that = this;` is a JavaScript trick to pass the current context into closures."
861 "To **set the value of the spinner on update from the back-end**, you need to use **jQuery's `spinner` API**. `spinner.spinner('value', new)` will set the value of the spinner. Add that code to the **`value_changed` method** to make the spinner **update with the value stored in the back-end((. Using jQuery's spinner API, you can add a function to handle the **spinner `change` event** by passing it in when constructing the spinner. Inside the `change` event, call **`model.set`** to set the value and then **`touch`** to inform the framework that this view was the view that caused the change to the model. **Note: The `var that = this;` is a JavaScript trick to pass the current context into closures.**"
680 862 ]
681 863 },
682 864 {
@@ -773,7 +955,11
773 955 {
774 956 "cell_type": "heading",
775 957 "level": 2,
776 "metadata": {},
958 "metadata": {
959 "slideshow": {
960 "slide_type": "slide"
961 }
962 },
777 963 "source": [
778 964 "Test"
779 965 ]
@@ -825,7 +1011,7
825 1011 "cell_type": "markdown",
826 1012 "metadata": {},
827 1013 "source": [
828 "Trying to use the spinner with another widget."
1014 "Trying to **use the spinner with another widget**."
829 1015 ]
830 1016 },
831 1017 {
@@ -1,7 +1,8
1 1 {
2 2 "metadata": {
3 "celltoolbar": "Slideshow",
3 4 "name": "",
4 "signature": "sha256:30ea15a6e6354e2477229e50d01b6caa3c5033e422acfbff730d7c20ca875e78"
5 "signature": "sha256:7a953d1eb1417e7212ddeb70602b36355521ca1907ac33b089850ccea35bd8ab"
5 6 },
6 7 "nbformat": 3,
7 8 "nbformat_minor": 0,
@@ -16,19 +17,67
16 17 ]
17 18 },
18 19 {
19 "cell_type": "markdown",
20 "cell_type": "code",
21 "collapsed": false,
22 "input": [
23 "%%html\n",
24 "<style>div.text_cell.cell.rendered.slideshow-slide { margin-top: 5em !important; }</style>"
25 ],
26 "language": "python",
20 27 "metadata": {},
28 "outputs": [
29 {
30 "html": [
31 "<style>div.text_cell.cell.rendered.slideshow-slide { margin-top: 5em !important; }</style>"
32 ],
33 "metadata": {},
34 "output_type": "display_data",
35 "text": [
36 "<IPython.core.display.HTML object>"
37 ]
38 }
39 ],
40 "prompt_number": 11
41 },
42 {
43 "cell_type": "markdown",
44 "metadata": {
45 "slideshow": {
46 "slide_type": "slide"
47 }
48 },
21 49 "source": [
22 50 "# Simple Widget Introduction\n",
23 51 "\n",
24 52 "## What are widgets?\n",
25 "<blockquote>Widgets are elements that exists in both the front-end and the back-end.</blockquote>\n",
26 "\n",
27 "You can use widgets to build interactive GUIs for your notebooks. \n",
28 "You can also use widgets to synchronize stateful and stateless information between Python and JavaScript.\n",
53 "Widgets are elements that exists in both the front-end and the back-end.\n",
29 54 "\n",
55 "** Insert Frontend-Backend Picture **"
56 ]
57 },
58 {
59 "cell_type": "markdown",
60 "metadata": {
61 "slideshow": {
62 "slide_type": "slide"
63 }
64 },
65 "source": [
66 "## What can they be used for?\n",
67 "You can use widgets to build **interactive GUIs** for your notebooks. \n",
68 "You can also use widgets to **synchronize stateful and stateless information** between Python and JavaScript."
69 ]
70 },
71 {
72 "cell_type": "markdown",
73 "metadata": {
74 "slideshow": {
75 "slide_type": "slide"
76 }
77 },
78 "source": [
30 79 "## Using widgets \n",
31 "To use the widget framework, you need to import the widgets from `IPython.html.widgets`."
80 "To use the widget framework, you need to **import `IPython.html.widgets`**."
32 81 ]
33 82 },
34 83 {
@@ -43,10 +92,22
43 92 "prompt_number": 1
44 93 },
45 94 {
95 "cell_type": "heading",
96 "level": 3,
97 "metadata": {
98 "slideshow": {
99 "slide_type": "slide"
100 }
101 },
102 "source": [
103 "repr"
104 ]
105 },
106 {
46 107 "cell_type": "markdown",
47 108 "metadata": {},
48 109 "source": [
49 "Widgets have their own display `repr` which allows them to be displayed using IPython's display framework. Constructing and returning an `IntSliderWidget` automatically displays the widget (as seen below). Widgets are displayed inside the `widget area`, which sits between the code cell and output. You can hide all of the widgets in the `widget area` by clicking the grey *x* in the margin."
110 "Widgets have their own display `repr` which allows them to be displayed using IPython's display framework. Constructing and returning an `IntSliderWidget` automatically displays the widget (as seen below). Widgets are **displayed inside the `widget area`**, which sits between the code cell and output. **You can hide all of the widgets** in the `widget area` by clicking the grey *x* in the margin."
50 111 ]
51 112 },
52 113 {
@@ -61,6 +122,18
61 122 "prompt_number": 2
62 123 },
63 124 {
125 "cell_type": "heading",
126 "level": 3,
127 "metadata": {
128 "slideshow": {
129 "slide_type": "slide"
130 }
131 },
132 "source": [
133 "display()"
134 ]
135 },
136 {
64 137 "cell_type": "markdown",
65 138 "metadata": {},
66 139 "source": [
@@ -81,10 +154,22
81 154 "prompt_number": 3
82 155 },
83 156 {
157 "cell_type": "heading",
158 "level": 3,
159 "metadata": {
160 "slideshow": {
161 "slide_type": "slide"
162 }
163 },
164 "source": [
165 "Multiple display() calls"
166 ]
167 },
168 {
84 169 "cell_type": "markdown",
85 170 "metadata": {},
86 171 "source": [
87 "If you display the same widget twice, the displayed instances in the front-end will remain in sync with each other."
172 "If you display the same widget twice, the displayed instances in the front-end **will remain in sync** with each other."
88 173 ]
89 174 },
90 175 {
@@ -100,6 +185,32
100 185 },
101 186 {
102 187 "cell_type": "markdown",
188 "metadata": {
189 "slideshow": {
190 "slide_type": "slide"
191 }
192 },
193 "source": [
194 "## Why does displaying the same widget twice work?\n",
195 "Widgets are **represented in the back-end by a single object**. Each time a widget is displayed, **a new representation** of that same object is created in the front-end. These representations are called **views**.\n",
196 "\n",
197 "** Insert Backend-Frontend Views Figure **"
198 ]
199 },
200 {
201 "cell_type": "heading",
202 "level": 3,
203 "metadata": {
204 "slideshow": {
205 "slide_type": "slide"
206 }
207 },
208 "source": [
209 "Closing widgets"
210 ]
211 },
212 {
213 "cell_type": "markdown",
103 214 "metadata": {},
104 215 "source": [
105 216 "You can close a widget by calling its `close()` method."
@@ -118,13 +229,14
118 229 },
119 230 {
120 231 "cell_type": "markdown",
121 "metadata": {},
232 "metadata": {
233 "slideshow": {
234 "slide_type": "slide"
235 }
236 },
122 237 "source": [
123 "## Why does displaying the same widget twice work?\n",
124 "Widgets are represented in the back-end by a single object. Each time a widget is displayed, a new representation of that same object is created in the front-end.\n",
125 "\n",
126 238 "## Widget properties\n",
127 "All of the IPython widgets share a similar naming scheme. To read the value of a widget, you can query its `value` property."
239 "All of the IPython widgets **share a similar naming scheme**. To read the value of a widget, you can query its `value` property."
128 240 ]
129 241 },
130 242 {
@@ -166,10 +278,22
166 278 "prompt_number": 7
167 279 },
168 280 {
281 "cell_type": "heading",
282 "level": 3,
283 "metadata": {
284 "slideshow": {
285 "slide_type": "slide"
286 }
287 },
288 "source": [
289 "Keys"
290 ]
291 },
292 {
169 293 "cell_type": "markdown",
170 294 "metadata": {},
171 295 "source": [
172 "In addition to `value`, most widgets share `keys`, `description`, `disabled`, and `visible`. To see the entire list of synchronized, stateful properties, of any specific widget, you can query the `keys` property."
296 "In addition to `value`, most widgets share `keys`, `description`, `disabled`, and `visible`. To see the entire list of synchronized, stateful properties, of any specific widget, you can **query the `keys` property**."
173 297 ]
174 298 },
175 299 {
@@ -205,10 +329,14
205 329 },
206 330 {
207 331 "cell_type": "markdown",
208 "metadata": {},
332 "metadata": {
333 "slideshow": {
334 "slide_type": "slide"
335 }
336 },
209 337 "source": [
210 "### Tip: Shorthand for setting the initial values of widget properties\n",
211 "While creating a widget, you can set some or all of the initial values of that widget by defining them as keyword arguments in the widget's constructor (as seen below)."
338 "### Shorthand for setting the initial values of widget properties\n",
339 "While creating a widget, you can set some or all of the initial values of that widget by **defining them as keyword arguments in the widget's constructor** (as seen below)."
212 340 ]
213 341 },
214 342 {
@@ -224,10 +352,14
224 352 },
225 353 {
226 354 "cell_type": "markdown",
227 "metadata": {},
355 "metadata": {
356 "slideshow": {
357 "slide_type": "slide"
358 }
359 },
228 360 "source": [
229 361 "## Linking two similar widgets\n",
230 "If you need to display the same value two different ways, you'll have to use two different widgets. Instead of attempting to manually synchronize the values of the two widgets, you can use the `traitlet` `link` function to link two properties together. Below, the values of three widgets are linked together."
362 "If you need to display the same value two different ways, you'll have to use two different widgets. Instead of **attempting to manually synchronize the values** of the two widgets, you can use the `traitlet` `link` function **to link two properties together**. Below, the values of three widgets are linked together."
231 363 ]
232 364 },
233 365 {
@@ -250,8 +382,13
250 382 },
251 383 {
252 384 "cell_type": "markdown",
253 "metadata": {},
385 "metadata": {
386 "slideshow": {
387 "slide_type": "slide"
388 }
389 },
254 390 "source": [
391 "### Unlinking widgets\n",
255 392 "Unlinking the widgets is simple. All you have to do is call `.unlink` on the link object."
256 393 ]
257 394 },
@@ -6,8 +6,9
6 6 null
7 7 ]
8 8 ],
9 "celltoolbar": "Slideshow",
9 10 "name": "",
10 "signature": "sha256:32c66e8148a9ddc503302503ecda740cc85cf4a8930e2c69f06025f1dfd80780"
11 "signature": "sha256:9f69a28be85dccdcc7e2b5d742047aa140a572d19e4215467aa88745c29ffce7"
11 12 },
12 13 "nbformat": 3,
13 14 "nbformat_minor": 0,
@@ -22,9 +23,36
22 23 ]
23 24 },
24 25 {
26 "cell_type": "code",
27 "collapsed": false,
28 "input": [
29 "%%html\n",
30 "<style>div.text_cell.cell.rendered.slideshow-slide { margin-top: 5em !important; }</style>"
31 ],
32 "language": "python",
33 "metadata": {},
34 "outputs": [
35 {
36 "html": [
37 "<style>div.text_cell.cell.rendered.slideshow-slide { margin-top: 5em !important; }</style>"
38 ],
39 "metadata": {},
40 "output_type": "display_data",
41 "text": [
42 "<IPython.core.display.HTML object>"
43 ]
44 }
45 ],
46 "prompt_number": 1
47 },
48 {
25 49 "cell_type": "heading",
26 50 "level": 1,
27 "metadata": {},
51 "metadata": {
52 "slideshow": {
53 "slide_type": "slide"
54 }
55 },
28 56 "source": [
29 57 "Widget Events"
30 58 ]
@@ -52,7 +80,7
52 80 "cell_type": "markdown",
53 81 "metadata": {},
54 82 "source": [
55 "The `ButtonWidget` is not used to represent a data type. Instead the button widget is used to handle mouse clicks. The `on_click` method of the `ButtonWidget` can be used to register function to be called when the button is clicked. The doc string of the `on_click` can be seen below."
83 "The `ButtonWidget` is not used to represent a data type. Instead the button widget is used to **handle mouse clicks**. The **`on_click` method** of the `ButtonWidget` can be used to register function to be called when the button is clicked. The doc string of the `on_click` can be seen below."
56 84 ]
57 85 },
58 86 {
@@ -84,10 +112,22
84 112 "prompt_number": 2
85 113 },
86 114 {
115 "cell_type": "heading",
116 "level": 3,
117 "metadata": {
118 "slideshow": {
119 "slide_type": "slide"
120 }
121 },
122 "source": [
123 "Example"
124 ]
125 },
126 {
87 127 "cell_type": "markdown",
88 128 "metadata": {},
89 129 "source": [
90 "Button clicks are transmitted from the front-end to the back-end using custom messages. By using the `on_click` method, a button that prints a message when it has been clicked is shown below."
130 "Since button clicks are **stateless**, they are **transmitted from the front-end to the back-end using custom messages**. By using the `on_click` method, a button that prints a message when it has been clicked is shown below."
91 131 ]
92 132 },
93 133 {
@@ -109,10 +149,22
109 149 "prompt_number": 3
110 150 },
111 151 {
152 "cell_type": "heading",
153 "level": 3,
154 "metadata": {
155 "slideshow": {
156 "slide_type": "slide"
157 }
158 },
159 "source": [
160 "on_sumbit"
161 ]
162 },
163 {
112 164 "cell_type": "markdown",
113 165 "metadata": {},
114 166 "source": [
115 "The `TextWidget` also has a special `on_submit` event. The `on_submit` event fires when the user hits return."
167 "The **`TextWidget`** also has a special **`on_submit` event**. The `on_submit` event **fires when the user hits return**."
116 168 ]
117 169 },
118 170 {
@@ -135,7 +187,11
135 187 {
136 188 "cell_type": "heading",
137 189 "level": 2,
138 "metadata": {},
190 "metadata": {
191 "slideshow": {
192 "slide_type": "slide"
193 }
194 },
139 195 "source": [
140 196 "Traitlet events"
141 197 ]
@@ -144,7 +200,7
144 200 "cell_type": "markdown",
145 201 "metadata": {},
146 202 "source": [
147 "Widget properties are IPython traitlets and traitlets are eventful. To handle changes, the `on_trait_change` method of the widget can be used to register a callback. The doc string for `on_trait_change` can be seen below. Both the `name` and `remove` properties are optional."
203 "**Widget properties are IPython traitlets** and **traitlets are eventful**. To handle changes, the **`on_trait_change` method** of the widget can be used to **register a callback**. The doc string for `on_trait_change` can be seen below."
148 204 ]
149 205 },
150 206 {
@@ -190,10 +246,22
190 246 "prompt_number": 5
191 247 },
192 248 {
249 "cell_type": "heading",
250 "level": 3,
251 "metadata": {
252 "slideshow": {
253 "slide_type": "slide"
254 }
255 },
256 "source": [
257 "Signatures"
258 ]
259 },
260 {
193 261 "cell_type": "markdown",
194 262 "metadata": {},
195 263 "source": [
196 "Mentioned in the doc string, the callback registered can have 4 possible signatures:\n",
264 "Mentioned in the doc string, the callback registered can have **4 possible signatures**:\n",
197 265 "\n",
198 266 "- callback()\n",
199 267 "- callback(trait_name)\n",
@@ -1,7 +1,8
1 1 {
2 2 "metadata": {
3 "celltoolbar": "Slideshow",
3 4 "name": "",
4 "signature": "sha256:131de6f76f08282147aa3b67b3ad76b8c0fb76a8582d771c7f864f4e1e7c0e2a"
5 "signature": "sha256:e6f77565893357e0302d40f80fbb389950912ab04a07b64026e28720cf11bfbe"
5 6 },
6 7 "nbformat": 3,
7 8 "nbformat_minor": 0,
@@ -16,8 +17,35
16 17 ]
17 18 },
18 19 {
19 "cell_type": "markdown",
20 "cell_type": "code",
21 "collapsed": false,
22 "input": [
23 "%%html\n",
24 "<style>div.text_cell.cell.rendered.slideshow-slide { margin-top: 5em !important; }</style>"
25 ],
26 "language": "python",
20 27 "metadata": {},
28 "outputs": [
29 {
30 "html": [
31 "<style>div.text_cell.cell.rendered.slideshow-slide { margin-top: 5em !important; }</style>"
32 ],
33 "metadata": {},
34 "output_type": "display_data",
35 "text": [
36 "<IPython.core.display.HTML object>"
37 ]
38 }
39 ],
40 "prompt_number": 1
41 },
42 {
43 "cell_type": "markdown",
44 "metadata": {
45 "slideshow": {
46 "slide_type": "slide"
47 }
48 },
21 49 "source": [
22 50 "# Widget List\n",
23 51 "\n",
@@ -74,7 +102,11
74 102 {
75 103 "cell_type": "heading",
76 104 "level": 2,
77 "metadata": {},
105 "metadata": {
106 "slideshow": {
107 "slide_type": "slide"
108 }
109 },
78 110 "source": [
79 111 "Numeric widgets"
80 112 ]
@@ -89,7 +121,11
89 121 {
90 122 "cell_type": "heading",
91 123 "level": 3,
92 "metadata": {},
124 "metadata": {
125 "slideshow": {
126 "slide_type": "slide"
127 }
128 },
93 129 "source": [
94 130 "FloatSliderWidget"
95 131 ]
@@ -115,7 +151,7
115 151 "cell_type": "markdown",
116 152 "metadata": {},
117 153 "source": [
118 "Sliders can also be displayed vertically."
154 "Sliders can also be **displayed vertically**."
119 155 ]
120 156 },
121 157 {
@@ -139,7 +175,11
139 175 {
140 176 "cell_type": "heading",
141 177 "level": 3,
142 "metadata": {},
178 "metadata": {
179 "slideshow": {
180 "slide_type": "slide"
181 }
182 },
143 183 "source": [
144 184 "FloatProgressWidget"
145 185 ]
@@ -164,7 +204,11
164 204 {
165 205 "cell_type": "heading",
166 206 "level": 3,
167 "metadata": {},
207 "metadata": {
208 "slideshow": {
209 "slide_type": "slide"
210 }
211 },
168 212 "source": [
169 213 "BoundedFloatTextWidget"
170 214 ]
@@ -188,7 +232,11
188 232 {
189 233 "cell_type": "heading",
190 234 "level": 3,
191 "metadata": {},
235 "metadata": {
236 "slideshow": {
237 "slide_type": "slide"
238 }
239 },
192 240 "source": [
193 241 "FloatTextWidget"
194 242 ]
@@ -210,7 +258,11
210 258 {
211 259 "cell_type": "heading",
212 260 "level": 2,
213 "metadata": {},
261 "metadata": {
262 "slideshow": {
263 "slide_type": "slide"
264 }
265 },
214 266 "source": [
215 267 "Boolean widgets"
216 268 ]
@@ -247,7 +299,11
247 299 {
248 300 "cell_type": "heading",
249 301 "level": 3,
250 "metadata": {},
302 "metadata": {
303 "slideshow": {
304 "slide_type": "slide"
305 }
306 },
251 307 "source": [
252 308 "CheckboxWidget"
253 309 ]
@@ -269,7 +325,11
269 325 {
270 326 "cell_type": "heading",
271 327 "level": 2,
272 "metadata": {},
328 "metadata": {
329 "slideshow": {
330 "slide_type": "slide"
331 }
332 },
273 333 "source": [
274 334 "Selection widgets"
275 335 ]
@@ -278,13 +338,17
278 338 "cell_type": "markdown",
279 339 "metadata": {},
280 340 "source": [
281 "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."
341 "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."
282 342 ]
283 343 },
284 344 {
285 345 "cell_type": "heading",
286 346 "level": 3,
287 "metadata": {},
347 "metadata": {
348 "slideshow": {
349 "slide_type": "slide"
350 }
351 },
288 352 "source": [
289 353 "DropdownWidget"
290 354 ]
@@ -372,7 +436,11
372 436 {
373 437 "cell_type": "heading",
374 438 "level": 3,
375 "metadata": {},
439 "metadata": {
440 "slideshow": {
441 "slide_type": "slide"
442 }
443 },
376 444 "source": [
377 445 "RadioButtonsWidget"
378 446 ]
@@ -394,7 +462,11
394 462 {
395 463 "cell_type": "heading",
396 464 "level": 3,
397 "metadata": {},
465 "metadata": {
466 "slideshow": {
467 "slide_type": "slide"
468 }
469 },
398 470 "source": [
399 471 "SelectWidget"
400 472 ]
@@ -416,7 +488,11
416 488 {
417 489 "cell_type": "heading",
418 490 "level": 3,
419 "metadata": {},
491 "metadata": {
492 "slideshow": {
493 "slide_type": "slide"
494 }
495 },
420 496 "source": [
421 497 "ToggleButtonsWidget"
422 498 ]
@@ -438,7 +514,11
438 514 {
439 515 "cell_type": "heading",
440 516 "level": 2,
441 "metadata": {},
517 "metadata": {
518 "slideshow": {
519 "slide_type": "slide"
520 }
521 },
442 522 "source": [
443 523 "String widgets"
444 524 ]
@@ -447,13 +527,17
447 527 "cell_type": "markdown",
448 528 "metadata": {},
449 529 "source": [
450 "There are 4 widgets that can be used to display a string value. Of those, the `TextWidget` and `TextareaWidget` accept input. The `LatexWidget` and `HTMLWidget` display the string as either Latex or HTML respectively, but do not accept input."
530 "There are 4 widgets that can be used to display a string value. Of those, the **`TextWidget` and `TextareaWidget` accept input**. The **`LatexWidget` and `HTMLWidget` display the string** as either Latex or HTML respectively, but **do not accept input**."
451 531 ]
452 532 },
453 533 {
454 534 "cell_type": "heading",
455 535 "level": 3,
456 "metadata": {},
536 "metadata": {
537 "slideshow": {
538 "slide_type": "slide"
539 }
540 },
457 541 "source": [
458 542 "TextWidget"
459 543 ]
@@ -497,7 +581,11
497 581 {
498 582 "cell_type": "heading",
499 583 "level": 3,
500 "metadata": {},
584 "metadata": {
585 "slideshow": {
586 "slide_type": "slide"
587 }
588 },
501 589 "source": [
502 590 "LatexWidget"
503 591 ]
@@ -539,7 +627,11
539 627 {
540 628 "cell_type": "heading",
541 629 "level": 2,
542 "metadata": {},
630 "metadata": {
631 "slideshow": {
632 "slide_type": "slide"
633 }
634 },
543 635 "source": [
544 636 "ButtonWidget"
545 637 ]
@@ -6,6 +6,7
6 6 null
7 7 ]
8 8 ],
9 "celltoolbar": "Slideshow",
9 10 "name": "",
10 11 "signature": "sha256:98ca4ae261d3dc9c0b43b3fa822772a47fff9956e443c640b2caead8d02efece"
11 12 },
@@ -22,19 +23,12
22 23 ]
23 24 },
24 25 {
25 "cell_type": "heading",
26 "level": 1,
27 "metadata": {},
28 "source": [
29 "Widget Styling"
30 ]
31 },
32 {
33 26 "cell_type": "code",
34 27 "collapsed": false,
35 28 "input": [
36 29 "%%html\n",
37 30 "<style>\n",
31 "div.text_cell.cell.rendered.slideshow-slide { margin-top: 5em !important; } // Slideshow styling.\n",
38 32 ".example-container { background: #999999; padding: 2px; min-height: 100px; }\n",
39 33 ".example-container.sm { min-height: 50px; }\n",
40 34 ".example-box { background: #9999FF; width: 50px; height: 50px; text-align: center; vertical-align: middle; color: white; font-weight: bold; margin: 2px;}\n",
@@ -48,6 +42,7
48 42 {
49 43 "html": [
50 44 "<style>\n",
45 "div.text_cell.cell.rendered.slideshow-slide { margin-top: 5em !important; } // Slideshow styling.\n",
51 46 ".example-container { background: #999999; padding: 2px; min-height: 100px; }\n",
52 47 ".example-container.sm { min-height: 50px; }\n",
53 48 ".example-box { background: #9999FF; width: 50px; height: 50px; text-align: center; vertical-align: middle; color: white; font-weight: bold; margin: 2px;}\n",
@@ -66,6 +61,18
66 61 },
67 62 {
68 63 "cell_type": "heading",
64 "level": 1,
65 "metadata": {
66 "slideshow": {
67 "slide_type": "slide"
68 }
69 },
70 "source": [
71 "Widget Styling"
72 ]
73 },
74 {
75 "cell_type": "heading",
69 76 "level": 2,
70 77 "metadata": {},
71 78 "source": [
@@ -76,7 +83,7
76 83 "cell_type": "markdown",
77 84 "metadata": {},
78 85 "source": [
79 "Since the representation of the widget you see is a browser element, Cascading Style Sheets (CSS) are used for styling. Widgets have a `set_css` method that allows you to add and remove CSS properties from your elements. The following example shows had `set_css` can be used to set the background color of a `TextWidget`."
86 "Since the representation of the widget you see is a **browser element**, **Cascading Style Sheets (CSS)** are used for styling. Widgets have a **`set_css` method** that allows you to **add and remove CSS properties** from your elements. The following example shows had `set_css` **can be used to set the background color** of a `TextWidget`."
80 87 ]
81 88 },
82 89 {
@@ -94,10 +101,22
94 101 "prompt_number": 2
95 102 },
96 103 {
104 "cell_type": "heading",
105 "level": 3,
106 "metadata": {
107 "slideshow": {
108 "slide_type": "slide"
109 }
110 },
111 "source": [
112 "Color codes"
113 ]
114 },
115 {
97 116 "cell_type": "markdown",
98 117 "metadata": {},
99 118 "source": [
100 "In the example above, the color `lime` is specified by name. CSS also supports specifying colors by a 3 byte hexadecimal string. The first byte is red, second green, and third blue. The following example sets the `TextWidget`'s background to blue."
119 "In the example above, **the color `lime` is specified by name**. CSS also supports specifying colors by a **3 byte hexadecimal string**. The first byte is red, second green, and third blue (**RGB**). The following example sets the `TextWidget`'s background to blue."
101 120 ]
102 121 },
103 122 {
@@ -112,10 +131,22
112 131 "prompt_number": 3
113 132 },
114 133 {
134 "cell_type": "heading",
135 "level": 3,
136 "metadata": {
137 "slideshow": {
138 "slide_type": "slide"
139 }
140 },
141 "source": [
142 "Forecolor"
143 ]
144 },
145 {
115 146 "cell_type": "markdown",
116 147 "metadata": {},
117 148 "source": [
118 "Font color is just `color`."
149 "In CSS the **font color is `color`.**"
119 150 ]
120 151 },
121 152 {
@@ -130,45 +161,69
130 161 "prompt_number": 4
131 162 },
132 163 {
164 "cell_type": "heading",
165 "level": 3,
166 "metadata": {
167 "slideshow": {
168 "slide_type": "slide"
169 }
170 },
171 "source": [
172 "Size"
173 ]
174 },
175 {
133 176 "cell_type": "markdown",
134 177 "metadata": {},
135 178 "source": [
136 "To remove the styling, you can call `set_css` again, but use an empty string instead of a color value."
179 "CSS is also used to set the **height and width** of controls. The `set_css` method also **can accept a single dictionary with multiple CSS properties** (as seen below)."
137 180 ]
138 181 },
139 182 {
140 183 "cell_type": "code",
141 184 "collapsed": false,
142 185 "input": [
143 "text.set_css('background', '')"
186 "btn = widgets.ButtonWidget()\n",
187 "btn.set_css({\n",
188 " 'width': '100px',\n",
189 " 'height': '100px',\n",
190 "})\n",
191 "btn"
144 192 ],
145 193 "language": "python",
146 194 "metadata": {},
147 195 "outputs": [],
148 "prompt_number": 5
196 "prompt_number": 6
197 },
198 {
199 "cell_type": "heading",
200 "level": 3,
201 "metadata": {
202 "slideshow": {
203 "slide_type": "slide"
204 }
205 },
206 "source": [
207 "Removing"
208 ]
149 209 },
150 210 {
151 211 "cell_type": "markdown",
152 212 "metadata": {},
153 213 "source": [
154 "CSS is also used to set the height and width of controls. The `set_css` method also can accept a single dictionary with multiple CSS properties (as seen below)."
214 "To remove the styling, you can call `set_css` again, but use an empty string instead of a color value."
155 215 ]
156 216 },
157 217 {
158 218 "cell_type": "code",
159 219 "collapsed": false,
160 220 "input": [
161 "btn = widgets.ButtonWidget()\n",
162 "btn.set_css({\n",
163 " 'width': '100px',\n",
164 " 'height': '100px',\n",
165 "})\n",
166 "btn"
221 "text.set_css('background', '')"
167 222 ],
168 223 "language": "python",
169 224 "metadata": {},
170 225 "outputs": [],
171 "prompt_number": 6
226 "prompt_number": 5
172 227 },
173 228 {
174 229 "cell_type": "markdown",
@@ -180,7 +235,11
180 235 {
181 236 "cell_type": "heading",
182 237 "level": 2,
183 "metadata": {},
238 "metadata": {
239 "slideshow": {
240 "slide_type": "slide"
241 }
242 },
184 243 "source": [
185 244 "Parent/child relationships"
186 245 ]
@@ -189,9 +248,9
189 248 "cell_type": "markdown",
190 249 "metadata": {},
191 250 "source": [
192 "To display widget A inside widget B, widget A must be a child of widget B. Only one instance of any particular widget can be child of another. In other words, *widget A* cannot have *widget B* listed twice in it's list of children.\n",
251 "To display widget A inside widget B, widget A must be a child of widget B. **Only one instance of any particular widget can be child of another (this limitation will be removed in IPython 3.0).** In other words, *widget A* cannot have *widget B* listed twice in it's list of children.\n",
193 252 "\n",
194 "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."
253 "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."
195 254 ]
196 255 },
197 256 {
@@ -215,9 +274,14
215 274 },
216 275 {
217 276 "cell_type": "markdown",
218 "metadata": {},
277 "metadata": {
278 "slideshow": {
279 "slide_type": "slide"
280 }
281 },
219 282 "source": [
220 "Children can also be added to parents after the parent has been displayed. The parent is responsible for rendering its children."
283 "### After the parent is displayed\n",
284 "Children **can be added to parents** after the parent has been displayed. The **parent is responsible for rendering its children**."
221 285 ]
222 286 },
223 287 {
@@ -239,7 +303,11
239 303 {
240 304 "cell_type": "heading",
241 305 "level": 2,
242 "metadata": {},
306 "metadata": {
307 "slideshow": {
308 "slide_type": "slide"
309 }
310 },
243 311 "source": [
244 312 "Fancy containers"
245 313 ]
@@ -248,7 +316,7
248 316 "cell_type": "markdown",
249 317 "metadata": {},
250 318 "source": [
251 "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 `AccordionWidget` or a `TabWidget` in combination with one `ContainerWidget` 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."
319 "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 **`AccordionWidget` or a `TabWidget` in combination with one `ContainerWidget` 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**."
252 320 ]
253 321 },
254 322 {
@@ -285,7 +353,11
285 353 {
286 354 "cell_type": "heading",
287 355 "level": 3,
288 "metadata": {},
356 "metadata": {
357 "slideshow": {
358 "slide_type": "slide"
359 }
360 },
289 361 "source": [
290 362 "TabWidget"
291 363 ]
@@ -316,7 +388,11
316 388 {
317 389 "cell_type": "heading",
318 390 "level": 3,
319 "metadata": {},
391 "metadata": {
392 "slideshow": {
393 "slide_type": "slide"
394 }
395 },
320 396 "source": [
321 397 "PopupWidget"
322 398 ]
@@ -325,7 +401,7
325 401 "cell_type": "markdown",
326 402 "metadata": {},
327 403 "source": [
328 "Unlike the other two special containers, the `PopupWidget` is only designed to display one set of widgets. The `PopupWidget` can be used to display widgets outside of the widget area. "
404 "Unlike the other two special containers, the `PopupWidget` is only **designed to display one set of widgets**. The `PopupWidget` can be used to **display widgets outside of the widget area**. "
329 405 ]
330 406 },
331 407 {
@@ -503,7 +579,11
503 579 {
504 580 "cell_type": "heading",
505 581 "level": 1,
506 "metadata": {},
582 "metadata": {
583 "slideshow": {
584 "slide_type": "slide"
585 }
586 },
507 587 "source": [
508 588 "Alignment"
509 589 ]
@@ -512,9 +592,9
512 592 "cell_type": "markdown",
513 593 "metadata": {},
514 594 "source": [
515 "Most widgets have a `description` attribute, which allows a label for the widget to be defined.\n",
516 "The label of the widget has a fixed minimum width.\n",
517 "The text of the label is always right aligned and the widget is left aligned:"
595 "Most widgets have a **`description` attribute**, which allows a label for the widget to be defined.\n",
596 "The label of the widget **has a fixed minimum width**.\n",
597 "The text of the label is **always right aligned and the widget is left aligned**:"
518 598 ]
519 599 },
520 600 {
@@ -527,14 +607,29
527 607 ],
528 608 "language": "python",
529 609 "metadata": {},
530 "outputs": [],
531 "prompt_number": 15
610 "outputs": [
611 {
612 "ename": "NameError",
613 "evalue": "name 'display' is not defined",
614 "output_type": "pyerr",
615 "traceback": [
616 "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
617 "\u001b[0;32m<ipython-input-4-66f52ebe0195>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidgets\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTextWidget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdescription\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"a:\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidgets\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTextWidget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdescription\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"aa:\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidgets\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTextWidget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdescription\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"aaa:\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
618 "\u001b[0;31mNameError\u001b[0m: name 'display' is not defined"
619 ]
620 }
621 ],
622 "prompt_number": 4
532 623 },
533 624 {
534 625 "cell_type": "markdown",
535 "metadata": {},
626 "metadata": {
627 "slideshow": {
628 "slide_type": "slide"
629 }
630 },
536 631 "source": [
537 "If a label is longer than the minimum width, the widget is shifted to the right:"
632 "If a **label is longer** than the minimum width, the **widget is shifted to the right**:"
538 633 ]
539 634 },
540 635 {
@@ -548,14 +643,29
548 643 ],
549 644 "language": "python",
550 645 "metadata": {},
551 "outputs": [],
552 "prompt_number": 16
646 "outputs": [
647 {
648 "ename": "NameError",
649 "evalue": "name 'display' is not defined",
650 "output_type": "pyerr",
651 "traceback": [
652 "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
653 "\u001b[0;32m<ipython-input-3-bd60a4ccdeb5>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidgets\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTextWidget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdescription\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"a:\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidgets\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTextWidget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdescription\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"aa:\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidgets\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTextWidget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdescription\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"aaa:\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidgets\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTextWidget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdescription\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"aaaaaaaaaaaaaaaaaa:\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
654 "\u001b[0;31mNameError\u001b[0m: name 'display' is not defined"
655 ]
656 }
657 ],
658 "prompt_number": 3
553 659 },
554 660 {
555 661 "cell_type": "markdown",
556 "metadata": {},
662 "metadata": {
663 "slideshow": {
664 "slide_type": "slide"
665 }
666 },
557 667 "source": [
558 "If a `description` is not set for the widget, the label is not displayed:"
668 "If a `description` is **not set** for the widget, the **label is not displayed**:"
559 669 ]
560 670 },
561 671 {
@@ -575,7 +685,11
575 685 {
576 686 "cell_type": "heading",
577 687 "level": 1,
578 "metadata": {},
688 "metadata": {
689 "slideshow": {
690 "slide_type": "slide"
691 }
692 },
579 693 "source": [
580 694 "DOM Classes"
581 695 ]
@@ -584,13 +698,17
584 698 "cell_type": "markdown",
585 699 "metadata": {},
586 700 "source": [
587 "IPython defines a large number of DOM (document object model) classes that you can apply to your widgets. Applying a DOM class causes all of the CSS associated with that class to be applied to the element. Classes can be applied and removed using the `add_class` and `remove_class` methods after a widget has been displayed. The majority of DOM classes defined by IPython are actually Bootstrap classes. For more information on Bootstrap classes and CSS, please refer to [Bootstrap's website](http://getbootstrap.com/2.3.2/)."
701 "IPython defines a large number of **DOM (document object model) classes** that you can apply to your widgets. Applying a DOM class causes all of the **CSS associated with that class** to be applied to the element. Classes can be applied and removed using the **`add_class` and `remove_class`** methods **after a widget has been displayed**. The majority of DOM classes defined by IPython are actually **Bootstrap classes**. For more information on Bootstrap classes and CSS, please refer to [Bootstrap's website](http://getbootstrap.com/2.3.2/)."
588 702 ]
589 703 },
590 704 {
591 705 "cell_type": "heading",
592 706 "level": 2,
593 "metadata": {},
707 "metadata": {
708 "slideshow": {
709 "slide_type": "slide"
710 }
711 },
594 712 "source": [
595 713 "Path dependent"
596 714 ]
@@ -599,7 +717,7
599 717 "cell_type": "markdown",
600 718 "metadata": {},
601 719 "source": [
602 "Both `add_class` and `remove_class` allow you to use CSS selectors to pick which sub elements of your widget get styled. Because of this, the `add_class` and `remove_class` methods are path dependent (order specific). The following example shows the same three calls made in three different orders and the resulting output. All three differ."
720 "Both `add_class` and `remove_class` allow you to use **CSS selectors** to pick which sub elements of your widget get styled. Because of this, the `add_class` and `remove_class` methods are **path dependent (order specific)**. The following example shows the **same three calls** made in three **different orders** and the resulting output. **All three differ.**"
603 721 ]
604 722 },
605 723 {
@@ -683,7 +801,11
683 801 {
684 802 "cell_type": "heading",
685 803 "level": 2,
686 "metadata": {},
804 "metadata": {
805 "slideshow": {
806 "slide_type": "slide"
807 }
808 },
687 809 "source": [
688 810 "Alignment classes"
689 811 ]
@@ -692,7 +814,7
692 814 "cell_type": "markdown",
693 815 "metadata": {},
694 816 "source": [
695 "Widgets can be aligned using IPython specific alignment classes. These classes should work with most widgets, but were designed to be applied to `ContainerWidget`s. Examples of these classes follow:\n",
817 "Widgets can be aligned using IPython **alignment classes**. These classes should work with most widgets, but were **designed to be applied to `ContainerWidget`s**. Examples of these classes follow:\n",
696 818 "\n",
697 819 "### Orientation classes\n",
698 820 "#### \"vbox\"\n",
@@ -708,10 +830,19
708 830 "<div class=\"example-box\">A</div>\n",
709 831 "<div class=\"example-box med\">B</div>\n",
710 832 "<div class=\"example-box lrg\">C</div>\n",
711 "</div>\n",
712 "\n",
833 "</div>"
834 ]
835 },
836 {
837 "cell_type": "markdown",
838 "metadata": {
839 "slideshow": {
840 "slide_type": "slide"
841 }
842 },
843 "source": [
713 844 "### Packing classes\n",
714 "These examples use the hbox layout to show packing. Packing is the alignment of the widgets along the the axis that they are displayed on.\n",
845 "These examples use the **hbox layout** to show packing. Packing is the alignment of the widgets along the the **axis that they are displayed on**.\n",
715 846 "#### \"start\"\n",
716 847 "<div class=\"example-container hbox start\">\n",
717 848 "<div class=\"example-box\">A</div>\n",
@@ -731,10 +862,19
731 862 "<div class=\"example-box\">A</div>\n",
732 863 "<div class=\"example-box med\">B</div>\n",
733 864 "<div class=\"example-box lrg\">C</div>\n",
734 "</div>\n",
735 "\n",
865 "</div>"
866 ]
867 },
868 {
869 "cell_type": "markdown",
870 "metadata": {
871 "slideshow": {
872 "slide_type": "slide"
873 }
874 },
875 "source": [
736 876 "### Aligning classes\n",
737 "These examples use the hbox layout to show alignment. Packing is the alignment of the widgets along the the axis perpendicular to the one that they are displayed on.\n",
877 "These examples use the **hbox layout** to show alignment. Packing is the alignment of the widgets along the the **axis perpendicular to the one that they are displayed on**.\n",
738 878 "#### \"align-start\"\n",
739 879 "<div class=\"example-container hbox align-start\">\n",
740 880 "<div class=\"example-box\">A</div>\n",
@@ -754,10 +894,19
754 894 "<div class=\"example-box\">A</div>\n",
755 895 "<div class=\"example-box med\">B</div>\n",
756 896 "<div class=\"example-box lrg\">C</div>\n",
757 "</div>\n",
758 "\n",
897 "</div>"
898 ]
899 },
900 {
901 "cell_type": "markdown",
902 "metadata": {
903 "slideshow": {
904 "slide_type": "slide"
905 }
906 },
907 "source": [
759 908 "### Flex classes\n",
760 "To specify how \"greedy\" a container is when filling in the remaining space of its parent, the `box-flexN` properties are used (where N is 0, 1, or 2). The higher the value of N, the more greedy the child is. `box-flex0` is the default behavior, which is to not fill the parent.\n",
909 "To specify **how \"greedy\" a container is** when filling in the remaining space of its parent, the **`box-flexN`** classes are used (where N is 0, 1, or 2). The **higher the value of N, the more greedy** the child is. **`box-flex0` is the default behavior**, which is to not fill the parent.\n",
761 910 "\n",
762 911 "#### Example 1\n",
763 912 "<div class=\"example-container sm hbox center\">\n",
@@ -799,13 +948,17
799 948 "<div class=\"example-box box-flex0\">box-flex0</div>\n",
800 949 "<div class=\"example-box box-flex1\">box-flex1</div>\n",
801 950 "<div class=\"example-box box-flex2\">box-flex2</div>\n",
802 "</div>\n"
951 "</div>"
803 952 ]
804 953 },
805 954 {
806 955 "cell_type": "heading",
807 956 "level": 3,
808 "metadata": {},
957 "metadata": {
958 "slideshow": {
959 "slide_type": "slide"
960 }
961 },
809 962 "source": [
810 963 "Application to widgets"
811 964 ]
@@ -814,7 +967,7
814 967 "cell_type": "markdown",
815 968 "metadata": {},
816 969 "source": [
817 "Widget containers default as vertical boxes."
970 "Widget containers **default to vbox** alignment."
818 971 ]
819 972 },
820 973 {
@@ -832,10 +985,22
832 985 "prompt_number": 22
833 986 },
834 987 {
988 "cell_type": "heading",
989 "level": 3,
990 "metadata": {
991 "slideshow": {
992 "slide_type": "slide"
993 }
994 },
995 "source": [
996 "Using hbox"
997 ]
998 },
999 {
835 1000 "cell_type": "markdown",
836 1001 "metadata": {},
837 1002 "source": [
838 "To make a widget container display its widgets horizontally, you need to remove the `vbox` class from the container and add the `hbox` class in its place."
1003 "To make a widget container display its widgets horizontally, you need to **remove the `vbox` class** from the container and **add the `hbox` class** in its place."
839 1004 ]
840 1005 },
841 1006 {
@@ -874,7 +1039,11
874 1039 {
875 1040 "cell_type": "heading",
876 1041 "level": 2,
877 "metadata": {},
1042 "metadata": {
1043 "slideshow": {
1044 "slide_type": "slide"
1045 }
1046 },
878 1047 "source": [
879 1048 "Style classes"
880 1049 ]
@@ -927,7 +1096,11
927 1096 {
928 1097 "cell_type": "heading",
929 1098 "level": 3,
930 "metadata": {},
1099 "metadata": {
1100 "slideshow": {
1101 "slide_type": "slide"
1102 }
1103 },
931 1104 "source": [
932 1105 "ContainerWidgets"
933 1106 ]
@@ -957,9 +1130,13
957 1130 {
958 1131 "cell_type": "heading",
959 1132 "level": 3,
960 "metadata": {},
1133 "metadata": {
1134 "slideshow": {
1135 "slide_type": "slide"
1136 }
1137 },
961 1138 "source": [
962 "*ProgressWidgets"
1139 "ProgressWidgets"
963 1140 ]
964 1141 },
965 1142 {
@@ -992,7 +1169,11
992 1169 {
993 1170 "cell_type": "heading",
994 1171 "level": 2,
995 "metadata": {},
1172 "metadata": {
1173 "slideshow": {
1174 "slide_type": "slide"
1175 }
1176 },
996 1177 "source": [
997 1178 "Visibility"
998 1179 ]
@@ -1001,8 +1182,8
1001 1182 "cell_type": "markdown",
1002 1183 "metadata": {},
1003 1184 "source": [
1004 "Sometimes it is necessary to hide or show widgets in place, without having to re-display the widget.\n",
1005 "The `visibility` property of widgets can be used to hide or show widgets that have already been displayed (as seen below)."
1185 "Sometimes it is necessary to **hide or show widgets** in place, **without having to re-display** the widget.\n",
1186 "The `visibility` property of widgets can be used to hide or show **widgets that have already been displayed** (as seen below)."
1006 1187 ]
1007 1188 },
1008 1189 {
@@ -1040,6 +1221,18
1040 1221 "prompt_number": 30
1041 1222 },
1042 1223 {
1224 "cell_type": "heading",
1225 "level": 3,
1226 "metadata": {
1227 "slideshow": {
1228 "slide_type": "slide"
1229 }
1230 },
1231 "source": [
1232 "Another example"
1233 ]
1234 },
1235 {
1043 1236 "cell_type": "markdown",
1044 1237 "metadata": {},
1045 1238 "source": [
General Comments 0
You need to be logged in to leave comments. Login now