File: widgets.md

package info (click to toggle)
magicgui 0.9.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 21,796 kB
  • sloc: python: 11,202; makefile: 11; sh: 9
file content (337 lines) | stat: -rw-r--r-- 13,346 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# Widgets

!!! tip
    If you're looking for an index of all available widgets, see the
    [Widget Index](api/widgets/index.md).

All individual graphical elements in **magicgui** are "widgets", and all widgets
are instances of [`magicgui.widgets.Widget`][magicgui.widgets.Widget].  Widgets may be created
directly:

```python
from magicgui.widgets import LineEdit

line_edit = LineEdit(value='hello!')
line_edit.show()
```

Some widgets (such as [`magicgui.widgets.Container`][magicgui.widgets.Container]) are composite
widgets that comprise other widgets:

```python
from magicgui.widgets import LineEdit, SpinBox, Container

line_edit = LineEdit(value='hello!')
spin_box = SpinBox(value=400)
container = Container(widgets=[line_edit, spin_box])
container.show()
```

**magicgui** provides a way to automatically select a widget given a python value
or type annotation using [`magicgui.widgets.create_widget`][magicgui.widgets.create_widget]. Here is an
example that yields the same result as the one above:

```python
from magicgui.widgets import create_widget

x = 'hello!'
y = 400
container = Container(widgets=[create_widget(i) for i in (x, y)])
container.show()
```

!!! tip

    Because there are often multiple valid widget types for a given python object,
    you may sometimes wish to create widgets directly, or use the `widget_type` argument
    in [`create_widget()`][magicgui.widgets.create_widget]

## The widget hierarchy

``` mermaid
graph TB
    A([Widget])-->B([ValueWidget])
    A-->C([ContainerWidget])
    B-->D([RangedWidget])
    B-->E([ButtonWidget])
    B-->F([CategoricalWidget])
    C-->H([MainWindowWidget])
    C-->G([FunctionGui])
    D-->I([SliderWidget])
    click A "#widget"
    click B "#valuewidget"
    click C "#containerwidget"
    click D "#rangedwidget"
    click E "#buttonwidget"
    click F "#categoricalwidget"
    click H "#mainwindowwidget"
    click G "#functiongui"
    click I "#sliderwidget"
```

Many widgets present similar types of information in different ways.  **magicgui** tries
to maintain a consistent API among all types of widgets that are designed to represent
similar objects.  The general class of widget you are working with will determine the
properties and attributes it has.

!!! note

    The categories shown below are sorted by their base class (such as
    [`ValueWidget`](#valuewidget) and [`RangedWidget`](#rangedwidget)). The bases are
    not intended to be instantiated directly.  Instead, you would create the widget
    type you wanted, such as `LineEdit` or `SpinBox`, respectively.

### `Widget`

As mentioned above, all magicgui widgets derive from [`magicgui.widgets.Widget`][magicgui.widgets.Widget] and have the
following attributes (this list is not comprehensive, see
the [`magicgui.widgets.Widget`][magicgui.widgets.Widget] API):

| <div style="width:80px">Attribute</div> | Type | Description |
|-----------|------|-------------|
| `name` | `str` | The name or "ID" of this widget (such as a function parameter name to which this widget corresponds). |
| `annotation` | `Any` | A type annotation for the value represented by the widget. |
| `label` | `str` | A string to use for an associated Label widget (if this widget is being shown in a [`magicgui.widgets.Container`][magicgui.widgets.Container] widget, and `container.labels` is `True`). By default, `name` will be used. Note: `name` refers the name of the parameter, as might be used in a signature, whereas label is just the label for that widget in the GUI. |
| `tooltip` | `str` | A tooltip to display when hovering over the widget. |
| `visible` | `bool` | Whether the widget is visible. |

### `ValueWidget`

In addition to the base [`Widget`](#widget) properties mentioned above, the
following `ValueWidgets` track some `value`:

::: autosummary
    magicgui.widgets.Label
    magicgui.widgets.LineEdit
    magicgui.widgets.LiteralEvalLineEdit
    magicgui.widgets.Password
    magicgui.widgets.TextEdit
    magicgui.widgets.FileEdit
    magicgui.widgets.RangeEdit
    magicgui.widgets.SliceEdit
    magicgui.widgets.DateTimeEdit
    magicgui.widgets.DateEdit
    magicgui.widgets.TimeEdit
    magicgui.widgets.Table
    magicgui.widgets.QuantityEdit

| <div style="width:80px">Attribute</div> | Type | Description |
|-----------|------|-------------|
| `value` | `Any` | The current value of the widget. |
| `changed` | [`psygnal.SignalInstance`][psygnal.SignalInstance] | A [`psygnal.SignalInstance`][psygnal.SignalInstance] that will emit an event when the `value` has changed.  Connect callbacks to the change event using `widget.changed.connect(callback)` |
| `bind` | `Any, optional` | A value or callback to bind this widget.  If bound, whenever `widget.value` is accessed, the value provided here will be returned.  The bound value can be a callable, in which case `bound_value(self)` will be returned (i.e. your callback must accept a single parameter, which is this widget instance.). see [`ValueWidget.bind`][magicgui.widgets.bases.ValueWidget.bind] for details. |

Here is a demonstration of all these:

```python
from magicgui import widgets
import datetime

wdg_list = [
    widgets.Label(value="label value", label="Label:"),
    widgets.LineEdit(value="line edit value", label="LineEdit:"),
    widgets.Password(value="super-secret!", label="Password:"),
    widgets.TextEdit(value="text edit value...", label="TextEdit:"),
    widgets.FileEdit(value="/home", label="FileEdit:"),
    widgets.RangeEdit(value=range(0, 10, 2), label="RangeEdit:"),
    widgets.SliceEdit(value=slice(0, 10, 2), label="SliceEdit:"),
    widgets.DateTimeEdit(
      value=datetime.datetime(1999, 12, 31, 11, 30), label="DateTimeEdit:"
    ),
    widgets.DateEdit(value=datetime.date(81, 2, 18), label="DateEdit:"),
    widgets.TimeEdit(value=datetime.time(12, 20), label="TimeEdit:"),
    widgets.QuantityEdit(value='12 seconds', label="Quantity:")
]
container = widgets.Container(widgets=wdg_list)
container.max_height = 300
container.show()
```

#### `RangedWidget`

`RangedWidgets` are numerical [`ValueWidgets`](#valuewidget) that have a restricted range of valid
values, and a step size.  `RangedWidgets` include:

::: autosummary
    magicgui.widgets.SpinBox
    magicgui.widgets.FloatSpinBox

In addition to all of the `ValueWidget` attributes, `RangedWidget` attributes include:

| <div style="width:80px">Attribute</div> | Type | Description |
|-----------|------|-------------|
| `min` | `float` | The minimum allowable value, by default 0 |
| `max` | `float` | The maximum allowable value, by default 1000 |
| `step` | `float` | The step size for incrementing the value, by default 1 |
| `range` | `tuple of float` | A convenience attribute for getting/setting the (min, max) simultaneously |

```python
w1 = widgets.SpinBox(value=10, max=20, label='SpinBox:')
w2 = widgets.FloatSpinBox(value=380, step=0.5, label='FloatSpinBox:')
container = widgets.Container(widgets=[w1, w2])
container.show()
```

##### `SliderWidget`

`SliderWidgets` are special [`RangedWidgets`](#rangedwidget)
that additionally have an `orientation`, and a `readout`.

::: autosummary
    magicgui.widgets.Slider
    magicgui.widgets.FloatSlider
    magicgui.widgets.LogSlider
    magicgui.widgets.ProgressBar

In addition to all of the `RangedWidget` attributes, `SliderWidget` attributes include:

| <div style="width:80px">Attribute</div> | Type | Description |
|-----------|------|-------------|
| `orientation` | `str` | The orientation for the slider. Must be either `'horizontal'` or `'vertical'`.  by default `'horizontal'` |
| `readout` | `bool` | Whether to show the value of the slider. By default, `True`. |

```python
w1 = widgets.Slider(value=10, max=25, label='Slider:')
w2 = widgets.FloatSlider(value=10.5, max=18.5, label='FloatSlider:')
w3 = widgets.ProgressBar(value=80, max=100, label='ProgressBar:')
container = widgets.Container(widgets=[w1, w2, w3])
container.show()
```

#### `ButtonWidget`

`ButtonWidgets` are boolean [`ValueWidgets`](#valuewidget) that also have some
`text` associated with them.

::: autosummary
    magicgui.widgets.PushButton
    magicgui.widgets.CheckBox

In addition to all of the `ValueWidget` attributes, `ButtonWidget` attributes include:

| <div style="width:80px">Attribute</div> | Type | Description |
|-----------------------------------------|------|-------------|
| `text` | `str` | The text to display on the button. If not provided, will use `name`. |

```python
w1 = widgets.PushButton(value=True, text='PushButton Text')
w2 = widgets.CheckBox(value=False, text='CheckBox Text')
container = widgets.Container(widgets=[w1, w2])
container.show()
```

#### `CategoricalWidget`

`CategoricalWidget` are [`ValueWidgets`](#valuewidget) that provide a set
of valid choices.  They can be created from:

- an [`enum.Enum`][enum.Enum]
- an iterable of objects (or an iterable of 2-tuples `(name, object)`)
- a callable that returns an [`enum.Enum`][enum.Enum] or an iterable
- a [`typing.Literal`][typing.Literal] annotation.

::: autosummary
    magicgui.widgets.ComboBox
    magicgui.widgets.RadioButtons
    magicgui.widgets.Select

In addition to all of the `ValueWidget` attributes, `CategoricalWidget` attributes include:

| <div style="width:80px">Attribute</div> | <div style="width:100px">Type</div>  | Description |
|-----------------------------------------|------|-------------|
| `choices` | [`Enum`][enum.Enum], [`Iterable`][typing.Iterable], or [`Callable`][typing.Callable] | Available choices displayed in the widget. |
| `value` | `Any` | In the case of a `CategoricalWidget` the `value` is the *data* of the currently selected choice (see also: `current_choice` below). |
| `current_choice` | `str` | The name associated with the current choice.  For instance, if `choices` was provided as `choices=[('one', 1), ('two', 2)]`, then an example `value` would be `1`, and an example `current_choice` would be `'one'`. |

```python
choices = ['one', 'two', 'three']
w1 = widgets.ComboBox(choices=choices, value='two', label='ComboBox:')
w2 = widgets.RadioButtons(choices=choices, label='RadioButtons:')
w3 = widgets.Select(choices=choices, label='Select:')
container = widgets.Container(widgets=[w1, w2, w3])
container.max_height = 220
container.show()
```

### `ContainerWidget`

A `ContainerWidget` is a list-like `Widget` that can contain other widgets.
Containers allow you to build more complex widgets from sub-widgets. A notable
example of a `Container` is [`magicgui.widgets.FunctionGui`][magicgui.widgets.FunctionGui])
(the product of the [`@magicgui`][magicgui.magicgui] decorator).

::: autosummary
    magicgui.widgets.Container
    magicgui.widgets.MainWindow
    magicgui.widgets.FunctionGui

| <div style="width:80px">Attribute</div> | Type | Description |
|-----------------------------------------|------|-------------|
| `layout` | `str` | The layout for the container.  Must be either `'horizontal'` or `'vertical'`. |
| `widgets` | `Sequence[Widget]` | The widgets that the container contains. |
| `labels` | `bool` | Whether each widget should be shown with a corresponding `Label` widget to the left.  Note: the text for each widget defaults to `widget.name`, but can be overridden by setting `widget.label`. |

`Container` implements the full [`collections.abc.MutableSequence`][collections.abc.MutableSequence] interface.
You can add and remove widgets from it just as you would add or remove items from a list.

```python
from magicgui.widgets import Container, Slider, FloatSlider, ProgressBar

container = widgets.Container()
container.append(widgets.LineEdit(value='Mookie', label='Your Name:'))
container.append(widgets.FloatSlider(value=10.5, label='FloatSlider:'))
container.show()
```

#### `MainWindowWidget`

A `MainWindowWidget` is a special type of `ContainerWidget` that also includes a menu
bar.

#### `FunctionGui`

A `FunctionGui` is a special type of [`ContainerWidget`](#containerwidget)
that is created from a function.  It is the product of the
[`@magicgui`][magicgui.magicgui] decorator.  It is a container that contains a
widget for each of the parameters in the function.
See [`magicgui.widgets.FunctionGui`][magicgui.widgets.FunctionGui] for details.

#### `@magicgui`

It's worth noting that [`@magicgui`][magicgui.magicgui] and
[`@magic_factory`][magicgui.magic_factory] decorators are just conveniences
that build a special type of [`Container`][magicgui.widgets.Container] widget (a
[`FunctionGui`][magicgui.widgets.FunctionGui]), with a widget representing each of the
parameters in a decorated function.

```python
from magicgui import magicgui

@magicgui
def my_function(x='hello', y=400): ...

my_function.show()
```

In terms of simply building widgets, the following code performs a similar task
to [`@magicgui`][magicgui.magicgui].

```python
from inspect import signature

def my_function(x='hello', y=400):
  ...

params = signature(my_function).parameters.values()
container = Container(
    widgets=[create_widget(p.default, name=p.name) for p in params]
)
container.show()
```

!!! tip

    *Note that the [`FunctionGui`][magicgui.widgets.FunctionGui] widget
    produced by `@magicgui` is actually a **callable** object that behaves very
    much like the original function, except that it will use current values from
    the GUI as default parameters when calling the function.*