Skip to content

Commit

Permalink
Add docs for Tree.
Browse files Browse the repository at this point in the history
  • Loading branch information
freakboy3742 committed Jun 29, 2023
1 parent 95f6cc2 commit b526209
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 12 deletions.
8 changes: 5 additions & 3 deletions docs/reference/api/widgets/table.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ ListSource at runtime.
The simplest instantiation of a Table is to use a list of lists (or list of tuples),
containing the items to display in the table. When creating the table, you must also
specify the headings to use on the table; those headings will be converted into
accessors on the Row data objects created for the table data. In this example,
we will display a table of 2 columns, with 3 initial rows of data:
accessors on the Row data objects created for the table data. The values in the tuples
provided will then be mapped sequentially to the accessors.

In this example, we will display a table of 2 columns, with 3 initial rows of data:

.. code-block:: python
Expand Down Expand Up @@ -59,7 +61,7 @@ to control the display order of columns independent of the storage of that data.
data=[
{"name": "Arthur Dent", "age": 42, "planet": "Earth"},
{"name", "Ford Prefect", "age": 37, "planet": "Betelgeuse Five"},
{"name": "Tricia McMillan", "age": 38, "plaent": "Earth"},
{"name": "Tricia McMillan", "age": 38, "planet": "Earth"},
]
)
Expand Down
127 changes: 118 additions & 9 deletions docs/reference/api/widgets/tree.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,136 @@ A widget for displaying a hierarchical tree of tabular data.
Usage
-----

A Table uses a :class:`~toga.sources.TreeSource` to manage the data being displayed.
A Tree uses a :class:`~toga.sources.TreeSource` to manage the data being displayed.
options. If ``data`` is not specified as a TreeSource, it will be converted into a
TreeSource at runtime.

The simplest instantiation of a Tree is to use a dictionary, where the keys are the data
for each node, and the values describe the children for that node. When creating the
Tree, you must also specify the headings to use on the tree; those headings will be
converted into accessors on the Node data objects created for the tree data. The values
in the tuples provided as keys in the data will then be mapped sequentially to the
accessors; or, if an atomic value has been provided as a key, only the first accessor
will be populated.

In this example, we will display a tree with 2 columns. The tree will have 2 root
nodes; the first root node will have 1 child node; the second root node will have 2
children. The root nodes will only populate the "name" column; the other column will be
blank:

.. code-block:: python
import toga
tree = toga.Tree(
headings=["Name", "Age"],
data={
"Earth": {
("Arthur Dent", 42): None,
},
"Betelgeuse Five": {
("Ford Prefect", 37): None,
("Zaphod Beeblebrox", 47): None,
},
}
)
# Get the details of the first child of the second root node:
print(f"{tree.data[1][0].name} is age {tree.data[1][0].age}")
# Append new data to the first root node in the tree
tree.data[0].append(("Tricia McMillan", 38))
You can also specify data for a Tree using a list of 2-tuples, with dictionaries
providing serving as data values. This allows to to store data in the data source that
won't be displayed in the tree. It also allows you to control the display order of
columns independent of the storage of that data.

.. code-block:: python
import toga
tree = toga.Tree(
headings=["Name", "Age"],
data=[
({"name": "Earth"}), [
({"name": "Arthur Dent", "age": 42, "status": "Anxious"}, None)
],
({"name": "Betelgeuse Five"}), [
({"name": "Ford Prefect", "age": 37, "status": "Hoopy"}, None)
({"name": "Zaphod Beeblebrox", "age": 47, "status": "Oblivious"}, None)
],
]
)
# Get the details of the first child of the second root node:
print(f"{tree.data[1][0].name} is age {tree.data[1][0].age}")
# Append new data to the first root node in the tree
tree.data[0].append({"name": "Tricia McMillan", "age": 38, "status": "Overqualified"})
The attribute names used on each row of data (called "accessors") are created automatically from
the name of the headings that you provide. This is done by:

1. Converting the heading to lower case;
2. Removing any character that can't be used in a Python identifier;
3. Replacing all whitespace with "_";
4. Prepending ``_`` if the first character is a digit.

If you want to use different accessors to the ones that are automatically generated, you
can override them by providing an ``accessors`` argument. This can be either:

* A list of the same size as the list of headings, specifying the accessors for each
heading. A value of :any:`None` will fall back to the default generated accessor; or
* A dictionary mapping heading names to accessor names.

In this example, the tree will use "Name" as the visible header, but internally, the
attribute "character" will be used:

.. code-block:: python
import toga
tree = toga.Tree(['Navigate'])
tree = toga.Tree(
headings=["Name", "Age"],
accessors={"Name", 'character'},
data=[
({"character": "Earth"}), [
({"character": "Arthur Dent", "age": 42, "status": "Anxious"}, None)
],
({"character": "Betelgeuse Five"}), [
({"character": "Ford Prefect", "age": 37, "status": "Hoopy"}, None)
({"character": "Zaphod Beeblebrox", "age": 47, "status": "Oblivious"}, None)
],
]
)
# Get the details of the first child of the second root node:
print(f"{tree.data[1][0].character} is age {tree.data[1][0].age}")
# Get the details of the first item in the data:
print(f"{tree.data[0].character}, who is age {tree.data[0].age}, is from {tree.data[0].planet}")
You can also create a tree *without* a heading row. However, if you do this, you *must*
specify accessors.

tree.insert(None, None, 'root1')
If the value provided by an accessor is :any:`None`, or the accessor isn't defined for a
given row, the value of ``missing_value`` provided when constructing the Tree will
be used to populate the cell in the Tree.

root2 = tree.insert(None, None, 'root2')
If the value provided by an accessor is any type other than a tuple :any:`tuple` or
:any:`toga.Widget`, the value will be converted into a string. If the value has an
``icon`` attribute, the cell will use that icon in the Tree cell, displayed to the left
of the text label. If the value of the ``icon`` attribute is :any:`None`, no icon will
be displayed.

tree.insert(root2, None, 'root2.1')
root2_2 = tree.insert(root2, None, 'root2.2')
If the value provided by an accessor is a :any:`tuple`, the first element in the tuple
must be an :class:`toga.Icon`, and the second value in the tuple will be used to provide
the text label (again, by converting the value to a string, or using ``missing_value``
if the value is :any:`None`, as appropriate).

tree.insert(root2_2, None, 'root2.2.1')
tree.insert(root2_2, None, 'root2.2.2')
tree.insert(root2_2, None, 'root2.2.3')
If the value provided by an accessor is a :class:`toga.Widget`, that widget will be displayed
in the tree. Note that this is currently a beta API, and may change in future.

Reference
---------
Expand Down

0 comments on commit b526209

Please sign in to comment.