Re: FreezePane using Gtk2::TreeStore



--- Ross McFarland <rwmcfa1 neces com> wrote:
On Thu, 2004-06-17 at 03:53, A. Pagaltzis wrote:
* Ross McFarland <rwmcfa1 neces com> [2004-06-16 23:29]:
i would be reluctant to include this in the examples mainly due
to it's dependency on XML::Simple. i'd rather not have examples
that require extra modules, especially if they aren't essential
to the functionality of the example. (not saying that
XML::Simple isn't cool and a good thing to do in situations
like this)

Would it help if there was a XML::LibXML version (which is a
GNOME project lib)? :-)

only if XML::LibXML had a binding that was already installed in order to
get Gtk2 going, so probably not. :-)

...hmmm. If XML::Simple is the only thing in the way, then may be I should remove that dependency
by hard coding the data-structure in the example :) I have added a note below the __END__
suggesting that XML::Simple is the 'better' way to go...

Also, I have included synchronization of selected rows between the trees... Attaching the new code
in a file, as you had suggested... And pasting it below for google sake :)

(...I am not pushing for this to be included in docs/examples. Sending it out just for fun :). The
decision is yours.)

_Ofey

----------------
And here comes the code
----------------
use strict;
use warnings;
use constant TRUE => 1;
use constant FALSE => !TRUE;
use Gtk2 -init;

# Since we are using a hierarchical data structure for $data_tree
# it may make more sense representing the data_tree in an XML form and
# then reading it in using the awesome XML::Simple module
# Look below __END__ for a detailed explanation

# my $data_tree = XMLin('data.xml', forcearray => 1);

my $data_tree = {
          'Node' => [
                    {
                      'Node' => [
                                {
                                  'Price' => '100.00',
                                  'Taste' => 'Sweet',
                                  'Name' => 'Apple',
                                  'Color' => 'Red'
                                },
                                {
                                  'Price' => '78.10',
                                  'Taste' => 'Sour',
                                  'Name' => 'Lemon',
                                  'Color' => 'Yellow'
                                }
                              ],
                      'Name' => 'Fruits'
                    },
                    {
                      'Node' => [
                                {
                                  'Price' => '100.00',
                                  'Source' => 'Idaho',
                                  'Name' => 'Potato',
                                  'Color' => 'Brown'
                                },
                                {
                                  'Taste' => 'Pungent',
                                  'Name' => 'Onion',
                                  'Color' => 'Yellow'
                                }
                              ],
                      'Name' => 'Vegetables'
                    }
                  ],
          'Name' => 'Food Products'
        };
        
# Define the columns in the order to be seen
my $all_columns = [
        { ColumnName => 'Name' }, 
        { ColumnName => 'Color'},
        { ColumnName => 'Price'}, 
        { ColumnName => 'Taste'},
        { ColumnName => 'Source'}
        ];

# Let us choose to freeze the first column
my $frozen_columns = [$all_columns->[0]];

# Create two arrays for sending into the Gtk2::TreeStore->new method
my @tree_store_full_types = map {'Glib::String'} @$all_columns;
my @tree_store_frozen_types = map {'Glib::String'} @$frozen_columns;

# Create the 'full' tree on the right side pane
my $tree_store_full = Gtk2::TreeStore->new(@tree_store_full_types);
my $tree_view_full = Gtk2::TreeView->new($tree_store_full);
my $column_count = 0;
for my $column (@$all_columns) {
        my $column_name =  $column->{ColumnName};
        my $column = Gtk2::TreeViewColumn->new_with_attributes(
                $column_name, Gtk2::CellRendererText->new(), text => $column_count);
        $column->set_resizable(TRUE);
        $tree_view_full->append_column($column);
        
        # Hide the first column
        # Ensure that the expander is fixed to the first column 
        # (and hence is hidden too)
        if ($column_count == 0) {
                $column->set_visible(FALSE);
                $tree_view_full->set_expander_column($column);
        }
        $column_count++;
}

# Create the single column tree for the left side pane
my $tree_store_frozen = Gtk2::TreeStore->new(@tree_store_frozen_types);
my $tree_view_frozen = Gtk2::TreeView->new($tree_store_frozen);
# There is only one column (the first column) in this case
my $column_name =  $frozen_columns->[0]->{ColumnName};
my $column = Gtk2::TreeViewColumn->new_with_attributes(
                $column_name, Gtk2::CellRendererText->new(), text => 0);
$column->set_resizable(TRUE);
$tree_view_frozen->append_column($column);

# Synchronize the frozen-tree with the full-tree
# First, we will synchronize the row-expansion/collapse
$tree_view_frozen->signal_connect('row-expanded' =>
                        sub {
                                my ($view, $iter, $path) = @_;
                                $tree_view_full->expand_row($path,0);
                        }
                        );      
$tree_view_frozen->signal_connect('row-collapsed' =>
                        sub {
                                my ($view, $iter, $path) = @_;
                                $tree_view_full->collapse_row($path);
                        }
                        );      

# Next, we will synchronize the row selection
$tree_view_frozen->get_selection->signal_connect('changed' =>
                        sub {
                                my ($selection) = @_;
                                sync_selection($tree_view_frozen, $tree_view_full, $selection);
                        }
                        );      
$tree_view_full->get_selection->signal_connect('changed' =>
                        sub {
                                my ($selection) = @_;
                                sync_selection($tree_view_full, $tree_view_frozen, $selection);
                        }
                        );      

# Recursive function to actually create the tree                                
append_children($tree_view_full->get_model(), undef, 
                                                                                        $data_tree, 
$all_columns);      
append_children($tree_view_frozen->get_model(), undef, 
                                                                                        $data_tree, 
$frozen_columns);   

# Add the frozen-tree to the left side of the pane
my $paned = Gtk2::HPaned->new;
$paned->add1 ($tree_view_frozen);

# we set the vertical size request very small, and it will fill up the
# available space when we set the default size of the window.
$tree_view_frozen->set_size_request (-1, 10);

# Add the full-tree to a scrolled window in the right pane
my $scroll = Gtk2::ScrolledWindow->new;
$scroll->add ($tree_view_full);
$paned->add2 ($scroll);

# Synchronize the scrolling
$tree_view_frozen->set(vadjustment => $tree_view_full->get_vadjustment);

# Create a new window and add the pane into it
my $window = Gtk2::Window->new;
$window->signal_connect(destroy => sub { Gtk2->main_quit; });
$window->add($paned);
$window->set_default_size(300, 100);
$window->show_all;
Gtk2->main;

# The obligatory recursive function to display the tree
# I don't know the performance implications of using recursion,
#   but it seems easy to write and understand
sub append_children {
        my ($tree_store, $iter, $data_tree, $columns) = @_;
        if ($data_tree) {               
                my $count = 0;          
                my $child_iter = $tree_store->append ($iter);
                for my $column(@$columns) {
                        my $column_name = $column->{ColumnName};
                        if ($data_tree->{$column_name}) {
                                $tree_store->set($child_iter, $count, $data_tree->{$column_name});
                        }
                        $count++;
                }
                foreach my $child(@{$data_tree->{'Node'}}) {
                        append_children($tree_store, $child_iter, $child, $columns);
                }
        }
}

# Synchronize the tree selections
sub sync_selection {
        my ($thisview, $otherview, $this_selection) = @_;
        my ($selected_model, $selected_iter) = $this_selection->get_selected;
        $otherview->get_selection->select_path ($selected_model->get_path($selected_iter));
}

__END__

Since we are representing hierarchical data here, it may make more sense to use 
XML to represent the input data. This code was initially written using XML::Simple
module in mind. The data structure you see used for my $data_tree can be created 
easily as follows.
-------------------------
Save the following xml string into data.xml
-------------------------
<Node Name="Food Products">
        <Node Name="Fruits">
                <Node Name="Apple"
                        Color = "Red"
                        Price = "100.00"
                        Taste = "Sweet"
                />
                <Node Name="Lemon"
                        Color = "Yellow" 
                        Price = "78.10"
                        Taste = "Sour"
                />      
        </Node>
        <Node Name="Vegetables">
                <Node Name="Potato"
                        Color = "Brown" 
                        Price = "100.00"
                        Source = "Idaho"
                />
                <Node Name="Onion"
                        Color = "Yellow" 
                        Taste = "Pungent"
                />      
        </Node>
</Node>

-------------------------
Read the xml string into the data_tree as follows using XML::Simple
-------------------------
use XML::Simple;
my $tree_xml_file = 'data.xml';
my $data_tree = XMLin($tree_xml_file, forcearray => 1);

Now the $data_tree should have the same structure as the one hard-coded in 
this example.


                
__________________________________
Do you Yahoo!?
Yahoo! Mail is new and improved - Check it out!
http://promotions.yahoo.com/new_mail

Attachment: tree_freeze_pane.pl
Description: tree_freeze_pane.pl



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