From 0a7df95dcfb399571be33a4dd465dce35d5773a5 Mon Sep 17 00:00:00 2001 From: jwansek Date: Wed, 24 Oct 2018 16:34:56 +0100 Subject: added expand on click --- tkFileBrowser.py | 98 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 75 insertions(+), 23 deletions(-) (limited to 'tkFileBrowser.py') diff --git a/tkFileBrowser.py b/tkFileBrowser.py index 3f18d19..a98c2fe 100644 --- a/tkFileBrowser.py +++ b/tkFileBrowser.py @@ -9,9 +9,11 @@ import win32ui import win32gui import os +#TODO: refresh tree + class TkFileBrowser(tk.Frame): - open = "" + _open = [] def __init__(self, parent, command, refresh = 20, types = [], showhidden = False): """Widget for browsing a windows filesystem. @@ -38,14 +40,32 @@ class TkFileBrowser(tk.Frame): self._book.pack(fill = tk.BOTH, expand = True) self.after(self._refresh, self.refresh) - def open_to(self, path): + def see(self, path): """Open the tree and book to this folder Arguments: path {str} -- path to open to """ - #TODO: make this function - raise NotImplementedError + #open the correct book tab + split = path.replace("\\", "/").split("/") + + #if requested is file, go to the folder in which it's in + if os.path.isfile(path): + del split[-1] + + drive = split[0] + "\\" + self._book.select(self._book._get_drives().index(drive)) + + try: + self._book._tabs[drive]._tree.see("\\".join(split)) + except tk.TclError: + #the node probably isn't loaded yet so we have to make it load before + #using .see() + for i in range(len(split) - 1): + self._book._tabs[drive]._populate_path("\\".join(split[:i+2])) + self._book._tabs[drive]._tree.item("\\".join(split[:i+2]), open = True) + + self._book._tabs[drive]._tree.see("\\".join(split)) def refresh(self): @@ -102,8 +122,9 @@ class TkFileBrowser(tk.Frame): class DriveBook(ttk.Notebook): - foldericons = {} - fileicons = {} + _foldericons = {} + _fileicons = {} + _tabs = {} def __init__(self, parent): ttk.Notebook.__init__(self) @@ -114,10 +135,11 @@ class DriveBook(ttk.Notebook): def _draw_tabs(self): self._drive_icons = self._get_icons() #store to attribute so it doesn't get removed by garbage deletion for drive in self._drive_icons: + self._tabs[drive[0]] = FileTree(self, drive[0]) if os.path.split(drive[0])[1] != "": - self.add(FileTree(self, drive[0]), text = "Home", image = drive[1], compound = tk.LEFT) + self.add(self._tabs[drive[0]], text = "Home", image = drive[1], compound = tk.LEFT) else: - self.add(FileTree(self, drive[0]), text = drive[0], image = drive[1], compound = tk.LEFT) + self.add(self._tabs[drive[0]], text = drive[0], image = drive[1], compound = tk.LEFT) def _refresh(self): """Checks if a drive as been added or removed. If it has, tabs are refreshed. @@ -169,10 +191,17 @@ class FileTree(tk.Frame): def _on_click(self, event): id = os.path.normpath(self._tree.focus()) + print(id) if os.path.isfile(id): self._command(id) else: - self._populate_path(id) + try: + self._populate_path(id) + except tk.TclError: + #this node has already been opened, so delete children and load again + for child in self._tree.get_children(id): + self._tree.delete(child) + self._populate_path(id) def _get_size(self, path): """Returns the size of a file. From: @@ -199,46 +228,61 @@ class FileTree(tk.Frame): return ('{} bytes').format(size) def _populate_path(self, path): - print("path:", path) - if path in self._parent._get_drives(): + #if the tree is blank, write to the root + if self._tree.get_children() == (): node = "" else: node = path folders, files = self._get_dirs_in_path(path) - print("node:", node) for folder in folders: fullpath = os.path.join(path, folder) - print("fullpath:", fullpath) self._tree.insert( parent = node, index = tk.END, iid = fullpath, tag = fullpath, text = folder, - image = self._parent.foldericons[fullpath], + image = self._parent._foldericons[fullpath], values = [folder, "", ""]) + #setup a dummy so the '+' appears before it's loaded. Child stuff will be loaded when the user + #clicks on the plus self._tree.insert(parent = fullpath, index = tk.END, tag = "dummy", text = "No avaliable files") for file in files: fullpath = os.path.join(path, file) name, type_ = os.path.splitext(file) + #if the type is a shortcut, get the whole path as a key + if type_ == ".lnk" or type_ == ".exe": + icon = self._parent._fileicons[fullpath] + else: + icon = self._parent._fileicons[type_] self._tree.insert( parent = node, index = tk.END, iid = fullpath, tag = fullpath, text = file, - image = self._parent.fileicons[type_], + image = icon, values = [file, "", self._get_size(fullpath)]) + #if there is more than one child, delete every child that isn't a path + #and hence delete the dummy + children = self._tree.get_children(node) + if len(children) > 1: + for child in children: + if not os.path.exists(child): + self._tree.delete(child) + def _get_dirs_in_path(self, path): """Returns two lists, the first is a list of all folders in a directory, the second is a list of files. Also loads the icons for these files and folders. - For folders, it puts a tk.PhotoImage as the value of the foldericons dictionary - with the key being the full folder path. For files, it uses the fileicons dictionary, - with they key being the filetype, e.g. "mp4". + For folders, it puts a tk.PhotoImage as the value of the _foldericons dictionary + with the key being the full folder path. For files, it uses the _fileicons dictionary, + with they key being the filetype, e.g. "mp4". If the file is a shortcut (".lnk") or + executable (".exe"), set the whole path as the key, since the icon is different for + every file of that type. Arguments: path {str} -- full path to the folder @@ -249,9 +293,15 @@ class FileTree(tk.Frame): def add(p, type_): files.append(p) - if type_ not in self._parent.fileicons: - self._parent.fileicons[type_] = ImageTk.PhotoImage( + + #if the file is a shortcut, set the key as the whole path + if type_ == ".lnk" or type_ == ".exe": + self._parent._fileicons[os.path.join(path, p)] = ImageTk.PhotoImage( self._parent._parent._get_icon(os.path.join(path, p), "small")) + else: + if type_ not in self._parent._fileicons: + self._parent._fileicons[type_] = ImageTk.PhotoImage( + self._parent._parent._get_icon(os.path.join(path, p), "small")) files = [] folders = [] @@ -269,8 +319,8 @@ class FileTree(tk.Frame): else: folders.append(p) - if os.path.join(path, p) not in self._parent.foldericons: - self._parent.foldericons[os.path.join(path, p)] = ImageTk.PhotoImage( + if os.path.join(path, p) not in self._parent._foldericons: + self._parent._foldericons[os.path.join(path, p)] = ImageTk.PhotoImage( self._parent._parent._get_icon(os.path.join(path, p), "small")) #print("\n\nfolders: ", folders, "\nfiles: ", files) @@ -283,6 +333,8 @@ def on_click(path): if __name__ == "__main__": root = tk.Tk() browser = TkFileBrowser(root, on_click) - browser.pack() + browser.pack(side = tk.LEFT) + + ttk.Button(root, text = "Goto", command = lambda: browser.see(r"C:\Users\Edward\Documents\random_pyapps")).pack(side = tk.LEFT) root.mainloop() \ No newline at end of file -- cgit v1.2.3