import os import wx import wx.lib.customtreectrl as customtree try: from agw import customtreectrl as CT except ImportError: # if it's not there locally, try the wxPython lib. import wx.lib.agw.customtreectrl as CT #---- Recipe Code ----# class FileBrowser(customtree.CustomTreeCtrl): FOLDER, \ ERROR, \ FILE = range(3) def __init__(self, parent, rootdir, *args, **kwargs): super(FileBrowser, self).__init__(parent, *args, **kwargs) assert os.path.exists(rootdir),\ "Invalid Root Directory!" assert os.path.isdir(rootdir),\ "rootdir must be a Directory!" # Attributes self._il = wx.ImageList(16, 16) self._root = rootdir self._rnode = None rootdir = '../work' # Setup for art in (wx.ART_FOLDER, wx.ART_ERROR, wx.ART_NORMAL_FILE): bmp = wx.ArtProvider.GetBitmap(art, size=(16,16)) self._il.Add(bmp) self.SetImageList(self._il) self._rnode = self.AddRoot(os.path.basename(rootdir), image=FileBrowser.FOLDER, data=self._root) self.SetItemHasChildren(self._rnode, True) # Use Windows Vista style selections # self.EnableSelectionVista(True) # Event Handlers self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnExpanding) self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnCollapsed) def _GetFiles(self, path): try: files = [fname for fname in os.listdir(path) if fname not in ('.', '..')] except OSError: files = None return files def OnCollapsed(self, event): item = event.GetItem() self.DeleteChildren(item) def OnCompareItems(self, item1, item2): pydata1 = self.GetPyData(item1) pydata2 = self.GetPyData(item2) if os.path.isdir(pydata1) and os.path.isdir(pydata2): return cmp(pydata1, pydata2) elif os.path.isdir(pydata1) and os.path.isfile(pydata2): return -1 elif os.path.isfile(pydata1) and os.path.isdir(pydata2): return 1 return cmp(pydata1, pydata2) def OnExpanding(self, event): item = event.GetItem() path = self.GetPyData(item) files = self._GetFiles(path) if files is None: self.SetItemImage(item, FileBrowser.ERROR) self.SetItemHasChildren(item, False) return for fname in files: fullpath = os.path.join(path, fname) if os.path.isdir(fullpath): self.AppendDir(item, fullpath) else: self.AppendFile(item, fullpath) self.SortChildren(item) # pt = self.GetPosition(); # item, flags = self.HitTest(pt) # if item: # parent = self.GetItemParent(item) # if parent.IsOk(): # self.SortChildren(parent) def AppendDir(self, item, path): """Add a directory node""" assert os.path.isdir(path), "Not a valid directory!" name = os.path.basename(path) nitem = self.AppendItem(item, name, image=FileBrowser.FOLDER, data=path) self.SetItemHasChildren(nitem, True) def AppendFile(self, item, path): """Add a file to a node""" assert os.path.isfile(path), "Not a valid file!" name = os.path.basename(path) self.AppendItem(item, name, image=FileBrowser.FILE, data=path) def GetSelectedPath(self): """Get the selected path""" sel = self.GetSelection() path = self.GetItemPyData(sel) return path def GetSelectedPaths(self): """Get a list of selected paths""" sels = self.GetSelections() paths = [self.GetItemPyData(sel) for sel in sels ] return paths #---- End Recipe Code ----# #---- Sample Application ----# class MyApp(wx.App): def OnInit(self): self.frame = MyFrame(None, title="CustomTreeCtrl", size=(300,400)) self.SetTopWindow(self.frame) self.frame.Show() return True class MyFrame(wx.Frame): def __init__(self, parent, *args, **kwargs): super(MyFrame, self).__init__(parent, *args, **kwargs) # Attributes self.panel = MyPanel(self) # Layout sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.panel, 1, wx.EXPAND) self.SetSizer(sizer) self.CreateStatusBar() class MyPanel(wx.Panel): def __init__(self, parent): super(MyPanel, self).__init__(parent) # Attributes self.browser = FileBrowser(self, wx.GetHomeDir()) # Setup # Layout sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.browser, 1, wx.EXPAND) self.SetSizer(sizer) # Event Handlers self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated) def OnItemActivated(self, event): path = self.browser.GetSelectedPath() self.GetTopLevelParent().PushStatusText(path) if __name__ == "__main__": app = MyApp(False) app.MainLoop()