--- 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