1 import wx
, wx
.lib
.customtreectrl
, wx
.gizmos
5 from wx
.lib
.mixins
import treemixin
7 overview
= treemixin
.__doc
__
9 class TreeModel(object):
10 ''' TreeModel holds the domain objects that are shown in the different
11 tree controls. Each domain object is simply a two-tuple consisting of
12 a label and a list of child tuples, i.e. (label, [list of child tuples]).
14 def __init__(self
, *args
, **kwargs
):
17 super(TreeModel
, self
).__init
__(*args
, **kwargs
)
19 def GetItem(self
, indices
):
20 text
, children
= 'Hidden root', self
.items
22 text
, children
= children
[index
]
25 def GetText(self
, indices
):
26 return self
.GetItem(indices
)[0]
28 def GetChildren(self
, indices
):
29 return self
.GetItem(indices
)[1]
31 def GetChildrenCount(self
, indices
):
32 return len(self
.GetChildren(indices
))
34 def SetChildrenCount(self
, indices
, count
):
35 children
= self
.GetChildren(indices
)
36 while len(children
) > count
:
38 while len(children
) < count
:
39 children
.append(('item %d'%self
.itemCounter
, []))
42 def MoveItem(self
, itemToMoveIndex
, newParentIndex
):
43 itemToMove
= self
.GetItem(itemToMoveIndex
)
44 newParentChildren
= self
.GetChildren(newParentIndex
)
45 newParentChildren
.append(itemToMove
)
46 oldParentChildren
= self
.GetChildren(itemToMoveIndex
[:-1])
47 oldParentChildren
.remove(itemToMove
)
50 class DemoTreeMixin(treemixin
.VirtualTree
, treemixin
.DragAndDrop
,
51 treemixin
.ExpansionState
):
52 def __init__(self
, *args
, **kwargs
):
53 self
.model
= kwargs
.pop('treemodel')
54 self
.log
= kwargs
.pop('log')
55 super(DemoTreeMixin
, self
).__init
__(*args
, **kwargs
)
56 self
.CreateImageList()
58 def CreateImageList(self
):
60 self
.imageList
= wx
.ImageList(*size
)
61 for art
in wx
.ART_FOLDER
, wx
.ART_FILE_OPEN
, wx
.ART_NORMAL_FILE
:
62 self
.imageList
.Add(wx
.ArtProvider
.GetBitmap(art
, wx
.ART_OTHER
,
64 self
.AssignImageList(self
.imageList
)
66 def OnGetItemText(self
, indices
):
67 return self
.model
.GetText(indices
)
69 def OnGetChildrenCount(self
, indices
):
70 return self
.model
.GetChildrenCount(indices
)
72 def OnGetItemFont(self
, indices
):
73 # Show how to change the item font. Here we use a small font for
74 # items that have children and the default font otherwise.
75 if self
.model
.GetChildrenCount(indices
) > 0:
78 return super(DemoTreeMixin
, self
).OnGetItemFont(indices
)
80 def OnGetItemTextColour(self
, indices
):
81 # Show how to change the item text colour. In this case second level
82 # items are coloured red and third level items are blue. All other
83 # items have the default text colour.
84 if len(indices
) % 2 == 0:
86 elif len(indices
) % 3 == 0:
89 return super(DemoTreeMixin
, self
).OnGetItemTextColour(indices
)
91 def OnGetItemBackgroundColour(self
, indices
):
92 # Show how to change the item background colour. In this case the
93 # background colour of each third item is green.
97 return super(DemoTreeMixin
,
98 self
).OnGetItemBackgroundColour(indices
)
100 def OnGetItemImage(self
, indices
, which
):
101 # Return the right icon depending on whether the item has children.
102 if which
in [wx
.TreeItemIcon_Normal
, wx
.TreeItemIcon_Selected
]:
103 if self
.model
.GetChildrenCount(indices
):
110 def OnDrop(self
, dropTarget
, dragItem
):
111 dropIndex
= self
.GetIndexOfItem(dropTarget
)
112 dropText
= self
.model
.GetText(dropIndex
)
113 dragIndex
= self
.GetIndexOfItem(dragItem
)
114 dragText
= self
.model
.GetText(dragIndex
)
115 self
.log
.write('drop %s %s on %s %s'%(dragText
, dragIndex
,
116 dropText
, dropIndex
))
117 self
.model
.MoveItem(dragIndex
, dropIndex
)
118 self
.GetParent().RefreshItems()
121 class VirtualTreeCtrl(DemoTreeMixin
, wx
.TreeCtrl
):
125 class VirtualTreeListCtrl(DemoTreeMixin
, wx
.gizmos
.TreeListCtrl
):
126 def __init__(self
, *args
, **kwargs
):
127 kwargs
['style'] = wx
.TR_DEFAULT_STYLE | wx
.TR_FULL_ROW_HIGHLIGHT
128 super(VirtualTreeListCtrl
, self
).__init
__(*args
, **kwargs
)
129 self
.AddColumn('Column 0')
130 self
.AddColumn('Column 1')
131 for art
in wx
.ART_TIP
, wx
.ART_WARNING
:
132 self
.imageList
.Add(wx
.ArtProvider
.GetBitmap(art
, wx
.ART_OTHER
,
135 def OnGetItemText(self
, indices
, column
=0):
136 # Return a different label depending on column.
137 return '%s, column %d'%\
138 (super(VirtualTreeListCtrl
, self
).OnGetItemText(indices
), column
)
140 def OnGetItemImage(self
, indices
, which
, column
=0):
141 # Also change the image of the other columns when the item has
144 return super(VirtualTreeListCtrl
, self
).OnGetItemImage(indices
,
146 elif self
.OnGetChildrenCount(indices
):
152 class VirtualCustomTreeCtrl(DemoTreeMixin
,
153 wx
.lib
.customtreectrl
.CustomTreeCtrl
):
154 def __init__(self
, *args
, **kwargs
):
156 kwargs
['ctstyle'] = wx
.TR_DEFAULT_STYLE | wx
.TR_HIDE_ROOT | \
157 wx
.TR_HAS_BUTTONS | wx
.TR_FULL_ROW_HIGHLIGHT
158 super(VirtualCustomTreeCtrl
, self
).__init
__(*args
, **kwargs
)
159 self
.Bind(wx
.lib
.customtreectrl
.EVT_TREE_ITEM_CHECKED
,
162 def OnGetItemType(self
, indices
):
163 if len(indices
) == 1:
165 elif len(indices
) == 2:
170 def OnGetItemChecked(self
, indices
):
171 return self
.checked
.get(indices
, False)
173 def OnItemChecked(self
, event
):
174 item
= event
.GetItem()
175 itemIndex
= self
.GetIndexOfItem(item
)
176 if self
.GetItemType(item
) == 2:
177 # It's a radio item; reset other items on the same level
178 for nr
in range(self
.GetChildrenCount(self
.GetItemParent(item
))):
179 self
.checked
[itemIndex
[:-1]+(nr
,)] = False
180 self
.checked
[itemIndex
] = True
184 class TreeNotebook(wx
.Notebook
):
185 def __init__(self
, *args
, **kwargs
):
186 treemodel
= kwargs
.pop('treemodel')
187 log
= kwargs
.pop('log')
188 super(TreeNotebook
, self
).__init
__(*args
, **kwargs
)
190 for class_
, title
in [(VirtualTreeCtrl
, 'TreeCtrl'),
191 (VirtualTreeListCtrl
, 'TreeListCtrl'),
192 (VirtualCustomTreeCtrl
, 'CustomTreeCtrl')]:
193 tree
= class_(self
, treemodel
=treemodel
, log
=log
)
194 self
.trees
.append(tree
)
195 self
.AddPage(tree
, title
)
196 self
.Bind(wx
.EVT_NOTEBOOK_PAGE_CHANGED
, self
.OnPageChanged
)
198 def OnPageChanged(self
, event
):
199 oldTree
= self
.GetPage(event
.OldSelection
)
200 newTree
= self
.GetPage(event
.Selection
)
201 newTree
.RefreshItems()
202 newTree
.SetExpansionState(oldTree
.GetExpansionState())
205 def GetIndicesOfSelectedItems(self
):
206 tree
= self
.trees
[self
.GetSelection()]
207 if tree
.GetSelections():
208 return [tree
.GetIndexOfItem(item
) for item
in tree
.GetSelections()]
212 def RefreshItems(self
):
213 tree
= self
.trees
[self
.GetSelection()]
218 class TestPanel(wx
.Panel
):
219 def __init__(self
, parent
, log
):
221 super(TestPanel
, self
).__init
__(parent
)
222 self
.treemodel
= TreeModel()
223 self
.CreateControls()
224 self
.LayoutControls()
226 def CreateControls(self
):
227 self
.notebook
= TreeNotebook(self
, treemodel
=self
.treemodel
,
229 self
.label
= wx
.StaticText(self
, label
='Number of children: ')
230 self
.childrenCountCtrl
= wx
.SpinCtrl(self
, value
='0', max=10000)
231 self
.button
= wx
.Button(self
, label
='Update children')
232 self
.button
.Bind(wx
.EVT_BUTTON
, self
.OnEnter
)
234 def LayoutControls(self
):
235 hSizer
= wx
.BoxSizer(wx
.HORIZONTAL
)
236 options
= dict(flag
=wx
.ALIGN_CENTER_VERTICAL|wx
.ALL
, border
=2)
237 hSizer
.Add(self
.label
, **options
)
238 hSizer
.Add(self
.childrenCountCtrl
, 2, **options
)
239 hSizer
.Add(self
.button
, **options
)
240 sizer
= wx
.BoxSizer(wx
.VERTICAL
)
241 sizer
.Add(self
.notebook
, 1, wx
.EXPAND
)
242 sizer
.Add(hSizer
, 0, wx
.EXPAND
)
245 def OnEnter(self
, event
):
246 indicesList
= self
.notebook
.GetIndicesOfSelectedItems()
247 newChildrenCount
= self
.childrenCountCtrl
.GetValue()
248 for indices
in indicesList
:
249 text
= self
.treemodel
.GetText(indices
)
250 oldChildrenCount
= self
.treemodel
.GetChildrenCount(indices
)
251 self
.log
.write('%s %s now has %d children (was %d)'%(text
, indices
,
252 newChildrenCount
, oldChildrenCount
))
253 self
.treemodel
.SetChildrenCount(indices
, newChildrenCount
)
254 self
.notebook
.RefreshItems()
257 def runTest(frame
, nb
, log
):
258 win
= TestPanel(nb
, log
)
262 if __name__
== '__main__':
264 run
.main(['', os
.path
.basename(sys
.argv
[0])] + sys
.argv
[1:])