|
| 1 | +--- |
| 2 | +jupyter: |
| 3 | + jupytext: |
| 4 | + text_representation: |
| 5 | + extension: .md |
| 6 | + format_name: markdown |
| 7 | + format_version: '1.3' |
| 8 | + jupytext_version: 1.13.7 |
| 9 | + kernelspec: |
| 10 | + display_name: Python 3 (ipykernel) |
| 11 | + language: python |
| 12 | + name: python3 |
| 13 | +--- |
| 14 | + |
| 15 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 16 | +## Sharing scientific tools: script to desktop application |
| 17 | + |
| 18 | +### TraitsUI |
| 19 | + |
| 20 | +**Jonathan Rocher, Siddhant Wahal, Jason Chambless, Corran Webster, Prabhu Ramachandran** |
| 21 | + |
| 22 | +**SciPy 2022** |
| 23 | + |
| 24 | +<!-- #endregion --> |
| 25 | + |
| 26 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 27 | +## TraitsUI: Easy GUI building |
| 28 | + |
| 29 | +- Meant for traits |
| 30 | +- Declarative UI |
| 31 | +- Interoperates with Qt and wxPython |
| 32 | +- Docs: https://docs.enthought.com/traitsui |
| 33 | +- GH: https://github.com/enthought/traitsui |
| 34 | + |
| 35 | +<!-- #endregion --> |
| 36 | + |
| 37 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 38 | +## Approach |
| 39 | + |
| 40 | +- Just declare what needs to be done |
| 41 | +- Do not need to write a lot of code |
| 42 | +- Embed 2D plots with `chaco` |
| 43 | +- Embed 3D plots with `mayavi` |
| 44 | +- Build rich scientific dialogs |
| 45 | + |
| 46 | +<!-- #endregion --> |
| 47 | + |
| 48 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 49 | +## Model-View-Controller (MVC) design pattern |
| 50 | + |
| 51 | +- Model: manages data, state, and internal logic |
| 52 | +- View: presents the model in a graphically interactive way |
| 53 | +- Controller: manages information between view and model |
| 54 | + |
| 55 | +<br/> |
| 56 | + |
| 57 | +- For simple cases, View and Controller may be the same |
| 58 | + |
| 59 | +<!-- #endregion --> |
| 60 | + |
| 61 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 62 | +## MVC with traitsui |
| 63 | + |
| 64 | +- Model: `HasTraits` object |
| 65 | +- View: `traitsui`, `View` class |
| 66 | +- Controller: `traitsui` `Handler` class |
| 67 | + |
| 68 | +<!-- #endregion --> |
| 69 | + |
| 70 | + |
| 71 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 72 | +## Views |
| 73 | + |
| 74 | +- A declarative specification for a GUI |
| 75 | +- Made up of `Item` and `Group` objects |
| 76 | + |
| 77 | +<!-- #endregion --> |
| 78 | + |
| 79 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 80 | +## Simple example |
| 81 | + |
| 82 | +<!-- #endregion --> |
| 83 | + |
| 84 | +```python |
| 85 | +from traits.api import HasTraits, Int, Str, Enum |
| 86 | + |
| 87 | +class Person(HasTraits): |
| 88 | + name = Str() |
| 89 | + age = Int() |
| 90 | + gender = Enum('female', 'male', 'other') |
| 91 | + |
| 92 | +``` |
| 93 | + |
| 94 | +```python |
| 95 | +%gui qt |
| 96 | +``` |
| 97 | + |
| 98 | +```python |
| 99 | +p = Person(name='Worf') |
| 100 | +p.edit_traits() |
| 101 | +``` |
| 102 | + |
| 103 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 104 | +## Specifying a View |
| 105 | + |
| 106 | + |
| 107 | +<!-- #endregion --> |
| 108 | + |
| 109 | +```python |
| 110 | +from traitsui.api import Item, View |
| 111 | +view1 = View( |
| 112 | + Item(name='name', style='readonly'), |
| 113 | + Item(name='age'), |
| 114 | + Item(name='gender', visible_when='age > 10'), |
| 115 | +) |
| 116 | +``` |
| 117 | + |
| 118 | +```python |
| 119 | +p.edit_traits(view=view1) |
| 120 | +``` |
| 121 | + |
| 122 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 123 | +## Common attributes of `Item` |
| 124 | + |
| 125 | +- `label`: UI label instead of the name |
| 126 | +- `show_label`: Bool |
| 127 | +- `tooltip`/`help`: Str |
| 128 | +- `editor`: `ItemEditor` to use |
| 129 | +- `style`: `{'simple', custom', 'text', 'readonly'}` |
| 130 | +- `enabled_when`, `visible_when`, `defined_when`: Python expression |
| 131 | +- `resizable`: bool |
| 132 | + |
| 133 | +<!-- #endregion --> |
| 134 | + |
| 135 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 136 | +## Groups |
| 137 | + |
| 138 | +- Handy for complex UIs |
| 139 | +- Common attributes: |
| 140 | + - `columns` |
| 141 | + - `label` |
| 142 | + - `layout`: `{'normal', 'flow', 'split', 'tabbed'}` |
| 143 | + - `orientation`: ` {'vertical', 'horizontal'}` |
| 144 | + - `show_border`: bool |
| 145 | + - `enabled_when`, `visible_when`, `defined_when`: Python expression |
| 146 | +- `HGroup`, `VGroup`, `HSplit`, `VSplit`, `Tabbed`: shortcuts |
| 147 | + |
| 148 | +<!-- #endregion --> |
| 149 | + |
| 150 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 151 | +## A simpler way |
| 152 | + |
| 153 | +<!-- #endregion --> |
| 154 | + |
| 155 | +```python |
| 156 | +from traitsui.api import Group |
| 157 | + |
| 158 | +class Person(HasTraits): |
| 159 | + name = Str() |
| 160 | + age = Int() |
| 161 | + gender = Enum('female', 'male', 'other') |
| 162 | + |
| 163 | + traits_view = View( |
| 164 | + Group( |
| 165 | + Item(name='name'), |
| 166 | + Item(name='age'), |
| 167 | + Item(name='gender'), |
| 168 | + label='Personnel profile', |
| 169 | + show_border=True |
| 170 | + ) |
| 171 | + ) |
| 172 | +``` |
| 173 | + |
| 174 | +```python |
| 175 | +p = Person(name='Worf', age=20) |
| 176 | +p.edit_traits() |
| 177 | +``` |
| 178 | + |
| 179 | +```python |
| 180 | + |
| 181 | +``` |
| 182 | + |
| 183 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 184 | +## View attributes |
| 185 | + |
| 186 | +- `dock`: `{'fixed', 'horizontal', 'vertical', 'tabbed'}` |
| 187 | +- `height`/`width` |
| 188 | +- `icon`/`image` |
| 189 | +- `resizable` |
| 190 | +- `scrollable` |
| 191 | +- `title` |
| 192 | +- `buttons` |
| 193 | +- `key_bindings` |
| 194 | +- See docs for more: https://docs.enthought.com/traitsui/traitsui_user_manual/ |
| 195 | + |
| 196 | +<!-- #endregion --> |
| 197 | + |
| 198 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 199 | +## Simple example |
| 200 | +<!-- #endregion --> |
| 201 | + |
| 202 | +```python |
| 203 | +from traitsui.api import CancelButton, OKButton |
| 204 | + |
| 205 | +class Person(HasTraits): |
| 206 | + name = Str() |
| 207 | + age = Int() |
| 208 | + gender = Enum('female', 'male', 'other') |
| 209 | + |
| 210 | + traits_view = View( |
| 211 | + Group( |
| 212 | + Item(name='name'), |
| 213 | + Item(name='age'), |
| 214 | + Item(name='gender'), |
| 215 | + label='Personnel profile', |
| 216 | + show_border=True, |
| 217 | + ), |
| 218 | + buttons=[OKButton, CancelButton] |
| 219 | + ) |
| 220 | +``` |
| 221 | + |
| 222 | + |
| 223 | +```python |
| 224 | +p = Person(name='Worf', age=20) |
| 225 | +p.edit_traits() |
| 226 | +``` |
| 227 | + |
| 228 | + |
| 229 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 230 | +## Toolkit selection |
| 231 | + |
| 232 | +- TraitsUI supports: Qt or wxPython |
| 233 | +- Can set the toolkit in a program |
| 234 | + - 'qt' or 'qt4' |
| 235 | + - 'wx' |
| 236 | + - 'null' |
| 237 | +- Or with the `ETS_TOOLKIT` environment variable |
| 238 | + |
| 239 | +``` |
| 240 | +export ETS_TOOLKIT=qt |
| 241 | +``` |
| 242 | + |
| 243 | +<!-- #endregion --> |
| 244 | + |
| 245 | +```python |
| 246 | +from traits.etsconfig.api import ETSConfig |
| 247 | +ETSConfig.toolkit = 'qt' |
| 248 | +``` |
| 249 | + |
| 250 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 251 | +## Other documentation |
| 252 | + |
| 253 | +- Interesting tutorial: https://docs.enthought.com/traitsui/tutorials |
| 254 | + |
| 255 | +<!-- #endregion --> |
| 256 | + |
| 257 | +<!-- #region slideshow={"slide_type": "slide"} --> |
| 258 | +## Exercise: |
| 259 | + |
| 260 | + |
| 261 | + |
| 262 | +<!-- #endregion --> |
0 commit comments