Examples¶
Minimal example¶
Simplest example rendering:
[-] item 1
sub item 1
sub item 2
item 2
1#!/usr/bin/python
2# Copyright (C) 2013 Patrick Totzke <patricktotzke@gmail.com>
3# This file is released under the GNU GPL, version 3 or a later revision.
4
5import urwid
6import urwidtrees
7
8
9tree_widget = urwidtrees.widgets.TreeBox(
10 urwidtrees.decoration.CollapsibleIndentedTree(
11 urwidtrees.tree.SimpleTree([
12 (urwid.SelectableIcon('item 1'), (
13 (urwid.SelectableIcon('sub item 1'), None),
14 (urwid.SelectableIcon('sub item 2'), None),
15 )),
16 (urwid.SelectableIcon('item 2'), None),
17 ])
18 )
19)
20
21urwid.MainLoop(tree_widget).run()
Basic use¶
1#!/usr/bin/python
2# Copyright (C) 2013 Patrick Totzke <patricktotzke@gmail.com>
3# This file is released under the GNU GPL, version 3 or a later revision.
4
5import urwid
6from urwidtrees.tree import SimpleTree
7from urwidtrees.widgets import TreeBox
8
9
10# define some colours
11palette = [
12 ('body', 'black', 'light gray'),
13 ('focus', 'light gray', 'dark blue', 'standout'),
14 ('bars', 'dark blue', 'light gray', ''),
15 ('arrowtip', 'light blue', 'light gray', ''),
16 ('connectors', 'light red', 'light gray', ''),
17]
18
19# We use selectable Text widgets for our example..
20
21
22class FocusableText(urwid.WidgetWrap):
23 """Selectable Text used for nodes in our example"""
24 def __init__(self, txt):
25 t = urwid.Text(txt)
26 w = urwid.AttrMap(t, 'body', 'focus')
27 urwid.WidgetWrap.__init__(self, w)
28
29 def selectable(self):
30 return True
31
32 def keypress(self, size, key):
33 return key
34
35# define a test tree in the format accepted by SimpleTree. Essentially, a
36# tree is given as (nodewidget, [list, of, subtrees]). SimpleTree accepts
37# lists of such trees.
38
39
40def construct_example_simpletree_structure(selectable_nodes=True, children=3):
41
42 Text = FocusableText if selectable_nodes else urwid.Text
43
44 # define root node
45 tree = (Text('ROOT'), [])
46
47 # define some children
48 c = g = gg = 0 # counter
49 for i in range(children):
50 subtree = (Text('Child {0:d}'.format(c)), [])
51 # and grandchildren..
52 for j in range(children):
53 subsubtree = (Text('Grandchild {0:d}'.format(g)), [])
54 for k in range(children):
55 leaf = (Text('Grand Grandchild {0:d}'.format(gg)), None)
56 subsubtree[1].append(leaf)
57 gg += 1 # inc grand-grandchild counter
58 subtree[1].append(subsubtree)
59 g += 1 # inc grandchild counter
60 tree[1].append(subtree)
61 c += 1
62 return tree
63
64
65def construct_example_tree(selectable_nodes=True, children=2):
66 # define a list of tree structures to be passed on to SimpleTree
67 forrest = [construct_example_simpletree_structure(selectable_nodes,
68 children)]
69
70 # stick out test tree into a SimpleTree and return
71 return SimpleTree(forrest)
72
73def unhandled_input(k):
74 #exit on q
75 if k in ['q', 'Q']: raise urwid.ExitMainLoop()
76
77if __name__ == "__main__":
78 # get example tree
79 stree = construct_example_tree()
80
81 # put the tree into a treebox
82 treebox = TreeBox(stree)
83
84 # add some decoration
85 rootwidget = urwid.AttrMap(treebox, 'body')
86 #add a text footer
87 footer = urwid.AttrMap(urwid.Text('Q to quit'), 'focus')
88 #enclose all in a frame
89 urwid.MainLoop(urwid.Frame(rootwidget, footer=footer), palette, unhandled_input = unhandled_input).run() # go
Decoration¶
1#!/usr/bin/python
2# Copyright (C) 2013 Patrick Totzke <patricktotzke@gmail.com>
3# This file is released under the GNU GPL, version 3 or a later revision.
4
5from example1 import construct_example_tree, palette, unhandled_input # example data
6from urwidtrees.decoration import ArrowTree # for Decoration
7from urwidtrees.widgets import TreeBox
8import urwid
9
10if __name__ == "__main__":
11 # get example tree
12 stree = construct_example_tree()
13 # Here, we add some decoration by wrapping the tree using ArrowTree.
14 atree = ArrowTree(stree,
15 # customize at will..
16 # arrow_hbar_char=u'\u2550',
17 # arrow_vbar_char=u'\u2551',
18 # arrow_tip_char=u'\u25B7',
19 # arrow_connector_tchar=u'\u2560',
20 # arrow_connector_lchar=u'\u255A',
21 )
22
23 # put the into a treebox
24 treebox = TreeBox(atree)
25 rootwidget = urwid.AttrMap(treebox, 'body')
26 #add a text footer
27 footer = urwid.AttrMap(urwid.Text('Q to quit'), 'focus')
28 #enclose in a frame
29 urwid.MainLoop(urwid.Frame(rootwidget, footer=footer), palette, unhandled_input = unhandled_input).run() # go
Collapsible subtrees¶
1#!/usr/bin/python
2# Copyright (C) 2013 Patrick Totzke <patricktotzke@gmail.com>
3# This file is released under the GNU GPL, version 3 or a later revision.
4
5from example1 import construct_example_tree, palette, unhandled_input # example data
6from urwidtrees.decoration import CollapsibleIndentedTree # for Decoration
7from urwidtrees.widgets import TreeBox
8import urwid
9
10if __name__ == "__main__":
11 # get some SimpleTree
12 stree = construct_example_tree()
13
14 # Use (subclasses of) the wrapper decoration.CollapsibleTree to construct a
15 # tree where collapsible subtrees. Apart from the original tree, these take
16 # a callable `is_collapsed` that defines initial collapsed-status if a
17 # given position.
18
19 # We want all grandchildren collapsed initially
20 if_grandchild = lambda pos: stree.depth(pos) > 1
21
22 # We use CollapsibleIndentedTree around the original example tree.
23 # This uses Indentation to indicate the tree structure and squeezes in
24 # text-icons to indicate the collapsed status.
25 # Also try CollapsibleTree or CollapsibleArrowTree..
26 tree = CollapsibleIndentedTree(stree,
27 is_collapsed=if_grandchild,
28 icon_focussed_att='focus',
29 # indent=6,
30 # childbar_offset=1,
31 # icon_frame_left_char=None,
32 # icon_frame_right_char=None,
33 # icon_expanded_char='-',
34 # icon_collapsed_char='+',
35 )
36
37 # put the tree into a treebox
38 treebox = TreeBox(tree)
39 rootwidget = urwid.AttrMap(treebox, 'body')
40 #add a text footer
41 footer = urwid.AttrMap(urwid.Text('Q to quit'), 'focus')
42 #enclose all in a frame
43 urwid.MainLoop(urwid.Frame(rootwidget, footer=footer), palette, unhandled_input = unhandled_input).run() # go
44
Custom Trees: Walking the filesystem¶
1#!/usr/bin/python
2# Copyright (C) 2013 Patrick Totzke <patricktotzke@gmail.com>
3# This file is released under the GNU GPL, version 3 or a later revision.
4
5import urwid
6import os
7from example1 import palette, unhandled_input # example data
8from urwidtrees.widgets import TreeBox
9from urwidtrees.tree import Tree
10from urwidtrees.decoration import CollapsibleArrowTree
11
12
13# define selectable urwid.Text widgets to display paths
14class FocusableText(urwid.WidgetWrap):
15 """Widget to display paths lines"""
16 def __init__(self, txt):
17 t = urwid.Text(txt)
18 w = urwid.AttrMap(t, 'body', 'focus')
19 urwid.WidgetWrap.__init__(self, w)
20
21 def selectable(self):
22 return True
23
24 def keypress(self, size, key):
25 return key
26
27# define Tree that can walk your filesystem
28
29
30class DirectoryTree(Tree):
31 """
32 A custom Tree representing our filesystem structure.
33 This implementation is rather inefficient: basically every position-lookup
34 will call `os.listdir`.. This makes navigation in the tree quite slow.
35 In real life you'd want to do some caching.
36
37 As positions we use absolute path strings.
38 """
39 # determine dir separator and form of root node
40 pathsep = os.path.sep
41 drive, _ = os.path.splitdrive(pathsep)
42
43 # define root node This is part of the Tree API!
44 root = drive + pathsep
45
46 def __getitem__(self, pos):
47 return FocusableText(pos)
48
49 # generic helper
50 def _list_dir(self, path):
51 """returns absolute paths for all entries in a directory"""
52 try:
53 elements = [
54 os.path.join(path, x) for x in os.listdir(path)
55 ] if os.path.isdir(path) else []
56 elements.sort()
57 except OSError:
58 elements = None
59 return elements
60
61 def _get_siblings(self, pos):
62 """lists the parent directory of pos """
63 parent = self.parent_position(pos)
64 siblings = [pos]
65 if parent is not None:
66 siblings = self._list_dir(parent)
67 return siblings
68
69 # Tree API
70 def parent_position(self, pos):
71 parent = None
72 if pos != '/':
73 parent = os.path.split(pos)[0]
74 return parent
75
76 def first_child_position(self, pos):
77 candidate = None
78 if os.path.isdir(pos):
79 children = self._list_dir(pos)
80 if children:
81 candidate = children[0]
82 return candidate
83
84 def last_child_position(self, pos):
85 candidate = None
86 if os.path.isdir(pos):
87 children = self._list_dir(pos)
88 if children:
89 candidate = children[-1]
90 return candidate
91
92 def next_sibling_position(self, pos):
93 candidate = None
94 siblings = self._get_siblings(pos)
95 myindex = siblings.index(pos)
96 if myindex + 1 < len(siblings): # pos is not the last entry
97 candidate = siblings[myindex + 1]
98 return candidate
99
100 def prev_sibling_position(self, pos):
101 candidate = None
102 siblings = self._get_siblings(pos)
103 myindex = siblings.index(pos)
104 if myindex > 0: # pos is not the first entry
105 candidate = siblings[myindex - 1]
106 return candidate
107
108
109if __name__ == "__main__":
110 cwd = os.getcwd() # get current working directory
111 dtree = DirectoryTree() # get a directory walker
112
113 # Use CollapsibleArrowTree for decoration.
114 # define initial collapse:
115 as_deep_as_cwd = lambda pos: dtree.depth(pos) >= dtree.depth(cwd)
116
117 # We hide the usual arrow tip and use a customized collapse-icon.
118 decorated_tree = CollapsibleArrowTree(dtree,
119 is_collapsed=as_deep_as_cwd,
120 arrow_tip_char=None,
121 icon_frame_left_char=None,
122 icon_frame_right_char=None,
123 icon_collapsed_char=u'\u25B6',
124 icon_expanded_char=u'\u25B7',)
125
126 # stick it into a TreeBox and use 'body' color attribute for gaps
127 tb = TreeBox(decorated_tree, focus=cwd)
128 root_widget = urwid.AttrMap(tb, 'body')
129 #add a text footer
130 footer = urwid.AttrMap(urwid.Text('Q to quit'), 'focus')
131 #enclose all in a frame
132 urwid.MainLoop(urwid.Frame(root_widget, footer=footer), palette, unhandled_input = unhandled_input).run() # go
Nesting Trees¶
1#!/usr/bin/python
2# Copyright (C) 2013 Patrick Totzke <patricktotzke@gmail.com>
3# This file is released under the GNU GPL, version 3 or a later revision.
4
5from example1 import palette, construct_example_tree # example data
6from example1 import FocusableText, unhandled_input # Selectable Text used for nodes
7from urwidtrees.widgets import TreeBox
8from urwidtrees.tree import SimpleTree
9from urwidtrees.nested import NestedTree
10from urwidtrees.decoration import ArrowTree, CollapsibleArrowTree # decoration
11import urwid
12import logging
13
14if __name__ == "__main__":
15 #logging.basicConfig(filename='example.log',level=logging.DEBUG)
16 # Take some Arrow decorated Tree that we later stick inside another tree.
17 innertree = ArrowTree(construct_example_tree())
18 # Some collapsible, arrow decorated tree with extra indent
19 anotherinnertree = CollapsibleArrowTree(construct_example_tree(),
20 indent=10)
21
22 # A SimpleTree, that contains the two above
23 middletree = SimpleTree(
24 [
25 (FocusableText('Middle ROOT'),
26 [
27 (FocusableText('Mid Child One'), None),
28 (FocusableText('Mid Child Two'), None),
29 (innertree, None),
30 (FocusableText('Mid Child Three'),
31 [
32 (FocusableText('Mid Grandchild One'), None),
33 (FocusableText('Mid Grandchild Two'), None),
34 ]
35 ),
36 (anotherinnertree,
37 # middletree defines a childnode here. This is usually
38 # covered by the tree 'anotherinnertree', unless the
39 # interepreting NestedTree's constructor gets parameter
40 # interpret_covered=True..
41 [
42 (FocusableText('XXX I\'m invisible!'), None),
43
44 ]),
45 ]
46 )
47 ]
48 ) # end SimpleTree constructor for middletree
49 # use customized arrow decoration for middle tree
50 middletree = ArrowTree(middletree,
51 arrow_hbar_char=u'\u2550',
52 arrow_vbar_char=u'\u2551',
53 arrow_tip_char=u'\u25B7',
54 arrow_connector_tchar=u'\u2560',
55 arrow_connector_lchar=u'\u255A')
56
57 # define outmost tree
58 outertree = SimpleTree(
59 [
60 (FocusableText('Outer ROOT'),
61 [
62 (FocusableText('Child One'), None),
63 (middletree, None),
64 (FocusableText('last outer child'), None),
65 ]
66 )
67 ]
68 ) # end SimpleTree constructor
69
70 # add some Arrow decoration
71 outertree = ArrowTree(outertree)
72 # wrap the whole thing into a Nested Tree
73 outertree = NestedTree(outertree,
74 # show covered nodes like XXX
75 interpret_covered=False
76 )
77
78 # put it into a treebox and run
79 treebox = TreeBox(outertree)
80 rootwidget = urwid.AttrMap(treebox, 'body')
81 #add a text footer
82 footer = urwid.AttrMap(urwid.Text('Q to quit'), 'focus')
83 #enclose all in a frame
84 urwid.MainLoop(urwid.Frame(rootwidget, footer=footer), palette, unhandled_input = unhandled_input).run() # go
Dynamic List¶
Update the tree after it's initially build.
Shows something like:
root
├─➤PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
│ 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.039 ms
│
├─➤64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.053 ms
│
└─➤64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.064 ms
1import subprocess
2import urwid
3import urwidtrees
4
5root_node = [urwid.Text('root'), None]
6tree_widget = urwidtrees.widgets.TreeBox(
7 urwidtrees.decoration.ArrowTree(
8 urwidtrees.tree.SimpleTree([root_node])
9 )
10)
11
12def exit_on_q(key):
13 if key in ['q', 'Q']:
14 raise urwid.ExitMainLoop()
15
16loop = urwid.MainLoop(tree_widget,
17 unhandled_input=exit_on_q)
18
19
20def on_stdout(data):
21 if not root_node[1]:
22 root_node[1] = []
23 root_node[1].append((urwid.Text(data), None))
24 tree_widget.refresh()
25
26
27proc = subprocess.Popen(
28 ['ping', '127.0.0.1'],
29 stdout=loop.watch_pipe(on_stdout),
30 close_fds=True)
31
32loop.run()
33proc.kill()