RE: Directory/file browser as TreeView

When I navigated to /home/zentara, it took 12 seconds from the time I
the triangle icon, to the point where it was finished.  That is
because I'm tempted to think I missed the small icon, and click multiple

When I use my canvas based model( on Tk) it was less than a second.

I've just downloaded your Tk version. Two minor points
 - it seems to have failed an automatic CPAN make test because you didn't list the Tk dependency.
 - I had to comment out the first line of the Makefile.PL to get it to make on my machine

But like I said, it's just for the sake of discussion, because maybe you
figure a way to limit that recursion somehow with treeview.... I couldn't.

OK. I realised that fully populating the subdirectories to show the arrow might be slow. Here is a version 
that just looks far enough ahead to see whether there is a subdirectory there and puts a dummy child in the 
tree, only filling it fully when required.

As you will see from the debugging messages I have put in, the tree is being properly populated. But for 
reasons I don't understand, you can't expand the tree.

Any ideas?


use warnings;
use strict;
use Gtk2 -init;
use Gtk2::SimpleList;
use Glib qw(TRUE FALSE);

my $window = Gtk2::Window -> new;
$window -> signal_connect ( destroy => sub { Gtk2 -> main_quit; } );
$window -> set_default_size (800, 600);
my $hpaned = Gtk2::HPaned -> new;
$window -> add ( $hpaned );

my $scwin_dirs = Gtk2::ScrolledWindow -> new;
$scwin_dirs -> set_policy ('automatic', 'automatic');
$hpaned -> pack1 ($scwin_dirs, TRUE, TRUE);

# Directory name, full path
my $tree_store = Gtk2::TreeStore->new('Glib::String', 'Glib::String');
my $tree_view = Gtk2::TreeView->new($tree_store);
my $column = Gtk2::TreeViewColumn->new_with_attributes('', Gtk2::CellRendererText->new(), text => "0");
$tree_view->signal_connect (button_release_event => \&cd);
$tree_view->signal_connect ('row-expanded' => \&populate_tree);

my $child = $tree_store->append(undef);
$tree_store->set($child, 0, '/', 1, '/');
$tree_store->append($child) if (has_subdir('/'));

$scwin_dirs -> add($tree_view);

my $scwin_files = Gtk2::ScrolledWindow -> new;
$scwin_files -> set_policy ('automatic', 'automatic');
$hpaned -> pack2 ($scwin_files, TRUE, TRUE);

my $slist = Gtk2::SimpleList -> new('Filename' => 'text');
$scwin_files -> add_with_viewport($slist);

$window -> show_all;
Gtk2 -> main;

# Add to directory treeview

sub add_to_tree {
 my ($tree_store, $parent, $dir, $abs_path) = @_;
 my $tree_model = $tree_view->get_model();

# If $parent already has children, then remove them first
 my $child = $tree_model->iter_children ($parent);
 while ($child) {
  $tree_store->remove ($child);
  $child = $tree_model->iter_children ($parent);

# Add children from directory listing
 opendir(DIRHANDLE, $abs_path) || die "Cannot open directory: $!\n";
 foreach my $subdir (sort readdir(DIRHANDLE)) {
  if ($subdir ne '.' and $subdir ne '..'
                            and -d $abs_path.$subdir and -r $abs_path.$subdir) {
print "adding $subdir\n";
   my $child = $tree_store->append($parent);
   $tree_store->set($child, 0, $subdir, 1, "$abs_path$subdir/");

# Directory expanded. Populate directory and check for subdirectories

sub populate_tree {

# $iter has been expanded
 my ($tree_view, $iter, $tree_path) = @_;
 my $tree_model = $tree_view->get_model();
 my ($dir, $abs_path) = $tree_model->get($iter);
print "populating $abs_path\n";
 add_to_tree($tree_store, $iter, $dir, $abs_path);

# for each of $iter's children add any subdirectories
 my $child = $tree_model->iter_children ($iter);
 while ($child) {
  my ($dir, $abs_path) = $tree_model->get($child, 0, 1);
  $tree_store->append($child) if (has_subdir($abs_path));
print "$abs_path has subdir\n" if (has_subdir($abs_path));
  $child = $tree_model->iter_next ($child);

sub print_tree {
 my ($parent) =  @_;
 my $tree_model = $tree_view->get_model();
 my $child = $tree_model->iter_children ($parent);
 while ($child) {
  my $dir = $tree_model->get($child, 1);
  if ($dir) {
   print "$dir\n";
  else {
   print "subdir\n";
  $child = $tree_model->iter_next ($child);

sub has_subdir {
 my ($dir) = @_;
 opendir my $dh, $dir or die "Cannot open directory: $!\n";
 while ( my $file = readdir($dh) ) {
  if ($file !~ /^\.{1,2}$/ and -d "$dir/$file") {
   closedir $dh;
   return TRUE;
 closedir $dh;

# Load $slist with all filenames in selected directory

sub cd {
 my $tree_model = $tree_view->get_model();
 my $selection = $tree_view->get_selection();
 my $iter = $selection->get_selected();

 return if (!($iter));

 my $abs_path = $tree_model->get($iter, 1);

# Display list of files
 chdir $abs_path;
 my @data;
 foreach (<*>) {

# Ignoring directories
  push @data, $_ if (! -d $_);
 @{$slist->{data}} = @data;

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]