--- 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_mailAttachment:
tree_freeze_pane.pl
Description: tree_freeze_pane.pl