RE: GtkTreeView column right-click



 -----Original Message-----

I'd like to popup a menu when the user right-clicks on a GtkTreeView's
column header.  Does anyone know of any example code for that, or even
an app that does that?

Obviously I don't want to access the private GtkTreeViewColumn::button.

-- 

This was discussed recently. Unfortunately you have to bring your own
button. Muppet rigged up an example, here's the relavent code followed
by the complete example:


#
# We must start off by setting a custom widget into the column.
# get_widget() will return undef unless we've previously called
set_widget(),
# so let's create a label we can use as the heading label.  This is
good,
# anyway, because we'll want to mangle the text of the heading to show
which
# virtual column is selected for sorting.
#

my $label = Gtk2::Label->new ($col->get_title." (0)");
$col->set_widget ($label);
$label->show;  # very important, show_all doesn't get this widget!

#
# And now, we need to find the button.  To avoid problems in the future
# should the actual layout of widgets change, we'll seek instead of just
# assuming it's always three layers deep.  If you're really paranoid, 
# you can modify this to avoid the possibility of infinite looping, but
# we know there's a button in the tree, so i won't muddy the code.
#
my $button = $col->get_widget; # not a button
do {
	$button = $button->get_parent;
} until ($button->isa ('Gtk2::Button'));

$button->signal_connect (button_release_event => sub {
	my (undef, $event) = @_;
	# Do completely normal things unless this is a right-button
click.
	return FALSE unless $event->button == 3;

	# otherwise, pop up a context menu that lets the user select the
	# virtual column on which to sort.
	my $menu = Gtk2::Menu->new;
	foreach (0, 1, 2) {
		my $item = Gtk2::MenuItem->new ($_);
		$menu->append ($item);
		$item->show;
		$item->signal_connect (activate => sub {
			my (undef, $sortkey) = @_;
			$col->set_sort_column_id ($sortkey);
			$model->set_sort_column_id ($sortkey,
	
$col->get_sort_order);
			$model->sort_column_changed;
			# update the column heading to show which
virtual
			# column is active.
			$label->set_text ($col->get_title."
($sortkey)");
		}, $_);
	}
	$menu->popup (undef, undef, undef, undef,
	              $event->button, $event->time);
	return TRUE; # stop propagation!
});


_______________________________________________
#!/bin/env perl -

=doc

Say you have some sophisticated sort algorithm you need to apply to a
column
of data in a tree, and the sort algorithm takes parameters that you can
tweak.
You'd like to allow the user to select those parameters from a context
menu
that pops up from the header button, that same button you click to
change
sort column and sort order.

That's getting into some deep arcana, so here's a contrived example.

 -- muppet, 30 mar 04

=cut

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

#
# We'll start with a single-column model with some "interesting" data.
# This data is three "virtual" columns that can be sorted.  There are
# plenty of ways we could store this that would be easier, but they'd
# also make it pointless to do what we're about to do, so bear with me.
#
my $model = Gtk2::ListStore->new (qw(Glib::String));
for (my $i = 0; $i < 5 ; $i++) {
 for (my $j = 0; $j < 5 ; $j++) {
  for (my $k = 0; $k < 5 ; $k++) {
    $model->set ($model->append, 0, "$i, $j, $k");
  }
 }
}

#
# And a custom sort func that sorts on the virtual column.
# Yes, this is very slow.  Like i said, it's a contrived example.
#
sub foosort {
	my ($liststore, $itera, $iterb, $sortkey) = @_;
	my @a = split /,\s*/, $liststore->get ($itera, 0);
	my @b = split /,\s*/, $liststore->get ($iterb, 0);
	return $a[$sortkey] <=> $b[$sortkey];
}
# Use different sort column ids for the different sort options.
$model->set_sort_func (0, \&foosort, 0);
$model->set_sort_func (1, \&foosort, 1);
$model->set_sort_func (2, \&foosort, 2);


#
# Now put that model into a view...  mostly boilerplate here.
#
my $treeview = Gtk2::TreeView->new ($model);
$treeview->set_headers_visible (1);

my $col = Gtk2::TreeViewColumn->new_with_attributes
				('Fancy sortable column', 
				 Gtk2::CellRendererText->new,
				 text => 0);
$treeview->append_column ($col);

# Select the initial sort id.
$col->set_sort_column_id (0);


#
# Now, here comes the heavy wizardry.  We want to allow the user to
# right-click on the column heading to pop up a context menu.  To do
# this, we need to get a hold of the button that's used as the column
# header.  I've looked far and wide and have not found a sanctioned
# "clean" way to get this button, but as mentioned here:
# http://mail.gnome.org/archives/gtk-list/2003-November/msg00175.html
# we can cheat by seeking up the widget hierarchy for it.
#
# We must start off by setting a custom widget into the column.
# get_widget() will return undef unless we've previously called
set_widget(),
# so let's create a label we can use as the heading label.  This is
good,
# anyway, because we'll want to mangle the text of the heading to show
which
# virtual column is selected for sorting.
#

my $label = Gtk2::Label->new ($col->get_title." (0)");
$col->set_widget ($label);
$label->show;  # very important, show_all doesn't get this widget!

#
# And now, we need to find the button.  To avoid problems in the future
# should the actual layout of widgets change, we'll seek instead of just
# assuming it's always three layers deep.  If you're really paranoid, 
# you can modify this to avoid the possibility of infinite looping, but
# we know there's a button in the tree, so i won't muddy the code.
#
my $button = $col->get_widget; # not a button
do {
	$button = $button->get_parent;
} until ($button->isa ('Gtk2::Button'));

$button->signal_connect (button_release_event => sub {
	my (undef, $event) = @_;
	# Do completely normal things unless this is a right-button
click.
	return FALSE unless $event->button == 3;

	# otherwise, pop up a context menu that lets the user select the
	# virtual column on which to sort.
	my $menu = Gtk2::Menu->new;
	foreach (0, 1, 2) {
		my $item = Gtk2::MenuItem->new ($_);
		$menu->append ($item);
		$item->show;
		$item->signal_connect (activate => sub {
			my (undef, $sortkey) = @_;
			$col->set_sort_column_id ($sortkey);
			$model->set_sort_column_id ($sortkey,
	
$col->get_sort_order);
			$model->sort_column_changed;
			# update the column heading to show which
virtual
			# column is active.
			$label->set_text ($col->get_title."
($sortkey)");
		}, $_);
	}
	$menu->popup (undef, undef, undef, undef,
	              $event->button, $event->time);
	return TRUE; # stop propagation!
});



# The rest is just boilerplate to get everything onscreen.
my $scroller = Gtk2::ScrolledWindow->new;
$scroller->set_policy ('never', 'always');
$scroller->add ($treeview);
my $win = Gtk2::Window->new;
$win->signal_connect (destroy => sub {Gtk2->main_quit});
$win->add ($scroller);
$win->set_default_size (75, 150);
$win->show_all;
Gtk2->main;





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