Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a simple file browser using python and gtkTreeView

I am trying to create a simple file browser using python and GTK3. Inspired by an another question here I was able to make a small working example

#!/usr/bin/python
import os
from gi.repository import Gtk

window = Gtk.Window()
window.connect("delete-event", Gtk.main_quit)


filesystemTreeStore = Gtk.TreeStore(str)
parents = {}

for (path, dirs, files) in os.walk("/home"):
    for subdir in dirs:
        parents[os.path.join(path, subdir)] = filesystemTreeStore.append(parents.get(path, None), [subdir])
    for item in files:
        filesystemTreeStore.append(parents.get(path, None), [item])

filesystemTreeView = Gtk.TreeView(filesystemTreeStore)
renderer = Gtk.CellRendererText()
filesystemColumn = Gtk.TreeViewColumn("Title", renderer, text=0)
filesystemTreeView.append_column(filesystemColumn)

window.add(filesystemTreeView)


window.show_all()
Gtk.main()

The code works, but the result feels not much effective. I was able to read and display the whole linux filesystem, but it took a very long time. One reason could be the usage of os.walk.

Another thing is, that such code does not allow opening empty directories.

For this reason I would like to display only the content of the parent directory for which the listing is made and expand the tree gradually as the user is exploring the tree structure.

I was not able to find a solution for this yet using Python and GTK3. There is a similar solution but for Tkinter

like image 691
karlitos Avatar asked Mar 20 '23 17:03

karlitos


1 Answers

i was able to come with a solution. There could be a better solution, but I am quite happy that it is working as I expected. I append "dummy" nodes to make the folders expandable, even if the are ampty. Had to deal with adding and removing the tree content on expanding/collapsing the treeView.

Here is my solution:

#!/usr/bin/python
import os, stat
from gi.repository import Gtk
from gi.repository.GdkPixbuf import Pixbuf

def populateFileSystemTreeStore(treeStore, path, parent=None):
    itemCounter = 0
    # iterate over the items in the path
    for item in os.listdir(path):
        # Get the absolute path of the item
        itemFullname = os.path.join(path, item)
        # Extract metadata from the item
        itemMetaData = os.stat(itemFullname)
        # Determine if the item is a folder
        itemIsFolder = stat.S_ISDIR(itemMetaData.st_mode)
        # Generate an icon from the default icon theme
        itemIcon = Gtk.IconTheme.get_default().load_icon("folder" if itemIsFolder else "empty", 22, 0)
        # Append the item to the TreeStore
        currentIter = treeStore.append(parent, [item, itemIcon, itemFullname])
        # add dummy if current item was a folder
        if itemIsFolder: treeStore.append(currentIter, [None, None, None])
        #increment the item counter
        itemCounter += 1
    # add the dummy node back if nothing was inserted before
    if itemCounter < 1: treeStore.append(parent, [None, None, None])

def onRowExpanded(treeView, treeIter, treePath):
    # get the associated model
    treeStore = treeView.get_model()
    # get the full path of the position
    newPath = treeStore.get_value(treeIter, 2)
    # populate the subtree on curent position
    populateFileSystemTreeStore(treeStore, newPath, treeIter)
    # remove the first child (dummy node)
    treeStore.remove(treeStore.iter_children(treeIter))

def onRowCollapsed(treeView, treeIter, treePath):
    # get the associated model
    treeStore = treeView.get_model()
    # get the iterator of the first child
    currentChildIter = treeStore.iter_children(treeIter)
    # loop as long as some childern exist
    while currentChildIter:
        # remove the first child
        treeStore.remove(currentChildIter)
        # refresh the iterator of the next child
        currentChildIter = treeStore.iter_children(treeIter)
    # append dummy node
    treeStore.append(treeIter, [None, None, None])

window = Gtk.Window()
window.connect("delete-event", Gtk.main_quit)

# initialize the filesystem treestore
fileSystemTreeStore = Gtk.TreeStore(str, Pixbuf, str)
# populate the tree store
populateFileSystemTreeStore(fileSystemTreeStore, '/home')
# initialize the TreeView
fileSystemTreeView = Gtk.TreeView(fileSystemTreeStore)

# Create a TreeViewColumn
treeViewCol = Gtk.TreeViewColumn("File")
# Create a column cell to display text
colCellText = Gtk.CellRendererText()
# Create a column cell to display an image
colCellImg = Gtk.CellRendererPixbuf()
# Add the cells to the column
treeViewCol.pack_start(colCellImg, False)
treeViewCol.pack_start(colCellText, True)
# Bind the text cell to column 0 of the tree's model
treeViewCol.add_attribute(colCellText, "text", 0)
# Bind the image cell to column 1 of the tree's model
treeViewCol.add_attribute(colCellImg, "pixbuf", 1)
# Append the columns to the TreeView
fileSystemTreeView.append_column(treeViewCol)
# add "on expand" callback
fileSystemTreeView.connect("row-expanded", onRowExpanded)
# add "on collapse" callback
fileSystemTreeView.connect("row-collapsed", onRowCollapsed)
scrollView = Gtk.ScrolledWindow()
scrollView.add(fileSystemTreeView)

# append the scrollView to the window (this)
window.add(scrollView)

window.connect("delete-event", Gtk.main_quit)
window.show_all()
Gtk.main()
like image 95
karlitos Avatar answered Apr 25 '23 08:04

karlitos