{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "< [OPTIONAL Predefined widget styles](06.03-OPTIONAL-widget-specific-styling.ipynb) | [Contents](00.00-index.ipynb) | [More widget libraries](07.00-More_widget_libraries.ipynb) >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# *OPTIONAL* widget layout exercises\n", "\n", "Earlier notebooks listed the container widgets in ipywidgets and how the widgets contained in them are laid out. As a reminder, the contents of the container are its `children`, a tuple of widgets. The distribution and alignment of the children are determined by the flex-box properties of the `layout` described in [Widget Styling](06-Widget-Styling.ipynb#The-Flexbox-layout).\n", "\n", "This set of exercises leads up to a password generator widget that will be completed after discussing widget events. The generator allows the user to set the length of the password, choose a set of special characters to include, and decide whether to include any digits. \n", "\n", "**Eventually** the widget will look like this:\n", "\n", "\"animated\n", "\n", "**At the end of this notebook** we will have laid out the controls shown below. We'll come back to the generator in later notebooks after we have discussed widget events.\n", "\n", "\"part\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "jupyter": { "outputs_hidden": true } }, "outputs": [], "source": [ "import ipywidgets as widgets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Alignment of children\n", "\n", "The cell below defines three children that are different sizes and lays them out in a horizontal box. Adjust the two layout properties in the code cell below so that the displayed hbox matches the image below.\n", "\n", "![final layout of widgets](images/container-exercises1-final-layout.png)\n", "\n", "You may need to look back at the [styling notebook](06-Widget_Styling.ipynb)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "jupyter": { "outputs_hidden": true } }, "outputs": [], "source": [ "button = widgets.Button(description='Click me')\n", "text = widgets.Textarea(description='Words here:', rows=10)\n", "valid = widgets.Valid(description='check', value=True)\n", "\n", "container = widgets.HBox()\n", "container.children = [button, text, valid]\n", "container.layout.width = '100%'\n", "\n", "# The border is set here just to make it easier to see the position of \n", "# the children with respect to the box.\n", "container.layout.border = '2px solid grey'\n", "container.layout.height = '250px'\n", "\n", "# ↓↓↓↓↓↓↓ Adjust these properties ↓↓↓↓↓↓↓↓↓\n", "container.layout.justify_content = 'flex-start'\n", "container.layout.align_items = 'flex-start'\n", "# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑\n", "\n", "container" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Layout from scratch\n", "\n", "Three child widgets are defined in the cell below. Compose them into a vertical box laid out as shown in this image: \n", "\n", "![layout of vertical box](images/container-exercises2-final-layout.png)\n", "\n", "You should be able to accomplish that layout by setting the appropriate `layout` attribute(s) on `vbox` (don't forget to add the children first).\n", "\n", "A box is drawn around the container to make it easier to see where the children are placed" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "jupyter": { "outputs_hidden": true } }, "outputs": [], "source": [ "# %load solutions/password-ex2.py\n", "\n", "numbers = widgets.Checkbox(description='Include numbers in password')\n", "words = widgets.Label('The generated password is:')\n", "toggles = widgets.ToggleButtons(description='Type of special characters to include',\n", " options=[',./;[', '!@#~%', '^&*()'],\n", " style={'description_width': 'initial'})\n", "vbox = widgets.VBox()\n", "\n", "# The border is set here just to make it easier to see the position of \n", "# the children with respect to the box.\n", "vbox.layout.border = '2px solid grey'\n", "vbox.layout.height = '250px'\n", "\n", "# ↓↓↓↓↓↓↓ Insert your layout settings here ↓↓↓↓↓↓↓ \n", "\n", "# Don't forget to add the children...\n", "\n", "vbox" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. Improve the look of the children\n", "\n", "The \"special character\" toggle buttons would really look better if the label was above the buttons, and the checkbox would look better without the whitespace to its left.\n", "\n", "### i. A better special character control\n", "\n", "In the cell below, construct a widget with the text \"Type of special characters to include\" above the `ToggleButtons`, with all of the content left-aligned, and the toggle buttons slightly indented. \n", "\n", "Use the `margin` property of the layout to indent.\n", "\n", "It should look like this when you are done:\n", "\n", "\n", "
\n", "![special characters widget](images/container-exercises-special-chars.png)\n", "
\n", "\n", "This is the second time we've needed a vbox with all the items left-aligned, so let's start out with a `Layout` widget that defines that format" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "jupyter": { "outputs_hidden": true } }, "outputs": [], "source": [ "# %load solutions/password-ex3i.py\n", "\n", "vbox_left_layout = widgets.Layout(align_items='flex-start')\n", "\n", "label = widgets.Label('Choose special characters to include')\n", "toggles = widgets.ToggleButtons(description='',\n", " options=[',./;[', '!@#~%', '^&*()'],\n", " style={'description_width': 'initial'})\n", "\n", "# Set the margins to control the indentation. \n", "# The order is top right bottom left\n", "toggles.layout.margin = '0 0 0 20px'\n", "\n", "better_toggles = widgets.VBox([label, toggles])\n", "better_toggles.layout = vbox_left_layout\n", "better_toggles" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ii. Checkbox whitespace issues\n", "\n", "The checkbox in the example above has unnecessary whitespace to the left of the box. Setting the `description_width` to `initial` removes it, so do that below." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "jupyter": { "outputs_hidden": true } }, "outputs": [], "source": [ "# %load solutions/password-ex3ii.py\n", "\n", "numbers = widgets.Checkbox(description='Include numbers in password',\n", " style={'description_width': 'initial'})\n", "numbers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4 Put the pieces together\n", "\n", "Use your improved toggles and number checkbox to re-do the password generator interface from exercise 2, above.\n", "\n", "When you are done it should look like this:\n", "\n", "![part of password generator](images/05-container-exercises-ex4.png)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "jupyter": { "outputs_hidden": true } }, "outputs": [], "source": [ "# %load solutions/password-ex4.py\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Alignment of children: additional (optional) challenges\n", "\n", "Using only `layout` attributes make the widget above:\n", "\n", "+ Display the children in reverse order (**not** by just reversing the list of children).\n", "+ Display the children vertically instead of horzontally." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "< [OPTIONAL Predefined widget styles](06.03-OPTIONAL-widget-specific-styling.ipynb) | [Contents](00.00-index.ipynb) | [More widget libraries](07.00-More_widget_libraries.ipynb) >" ] } ], "metadata": { "kernelspec": { "display_name": "widgets-tutorial", "language": "python", "name": "widgets-tutorial" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" } }, "nbformat": 4, "nbformat_minor": 4 }