#!/usr/bin/perl use warnings; use strict; use Gtk2 -init; use Glib qw/TRUE FALSE/; # Danial Kasak posted this as having # some sort of bug, but it works fine for me. # if you select a number in the 3rd column combobox, # then hit dump, before hitting enter in the cell, # or click somewhere in the treeview, the number # change won't take effect. Seems like a feature to me :-) my $window = Gtk2::Window->new( "toplevel" ); $window->signal_connect( "destroy", sub { Gtk2->main_quit(); } ); my $vbox = Gtk2::VBox->new( 0, 5 ); my $model = Gtk2::ListStore->new( "Glib::String", "Glib::String", "Glib::Int" ); $model->set( $model->append, 0, "Hi", 1, "There", 2, 5 ); my $renderer_1 = Gtk2::CellRendererText->new; $renderer_1->set( editable => TRUE ); $renderer_1->signal_connect( edited => sub { &process_editing( @_, 0 ); } ); my $renderer_2 = Gtk2::CellRendererText->new; $renderer_2->set( editable => TRUE ); $renderer_2->signal_connect( edited => sub { &process_editing( @_, 1 ); } ); my $column_1 = Gtk2::TreeViewColumn->new_with_attributes( "Some Text", $renderer_1, 'text' => 0 ); my $column_2 = Gtk2::TreeViewColumn->new_with_attributes( "More Text", $renderer_2, 'text' => 1 ); my $combo_model = Gtk2::ListStore->new( "Glib::Int", "Glib::String" ); foreach my $thingy ( [ 1, "one" ], [ 2, "two" ], [ 3, "three" ], [ 4, "four" ], [ 5, "five" ] ) { $combo_model->set( $combo_model->append, 0, $$thingy[ 0 ], 1, $$thingy[ 1 ] ); } my $renderer_3 = Gtk2::CellRendererCombo->new; $renderer_3->set( editable => TRUE, text_column => 1, has_entry => TRUE, model => $combo_model ); $renderer_3->signal_connect( edited => sub { &process_editing( @_, 2 ); } ); my $column_3 = Gtk2::TreeViewColumn->new_with_attributes( "A Combo", $renderer_3, text => 2 ); $column_3->set_cell_data_func( $renderer_3, sub { &render_combo_cell( @_ ); } ); my $treeview = Gtk2::TreeView->new( $model ); $treeview->set_rules_hint( TRUE ); $treeview->append_column( $column_1 ); $treeview->append_column( $column_2 ); $treeview->append_column( $column_3 ); my $sw = Gtk2::ScrolledWindow->new( undef, undef ); $sw->set_shadow_type( "etched-in" ); $sw->set_policy( "never", "always" ); $sw->add( $treeview ); $vbox->pack_start( $sw, TRUE, TRUE, 0 ); my $button = Gtk2::Button->new( "Dump Values" ); $button->signal_connect( "clicked" => sub { &dump_values( @_ ); } ); $vbox->pack_start( $button, TRUE, TRUE, 0 ); $window->add( $vbox ); $window->show_all; Gtk2->main; sub process_editing { my ( $renderer, $text_path, $new_text, $columnno ) = @_; my $path = Gtk2::TreePath->new_from_string( $text_path ); my $iter = $model->get_iter( $path ); if ( $columnno == 2 ) { # Column 2 is a combo - we need to fetch the ID from the combo's model my $combo_model; $combo_model = $renderer->get( "model" ); my $combo_iter = $combo_model->get_iter_first; my $found_match = FALSE; while ( $combo_iter ) { if ( $combo_model->get( $combo_iter, 1 ) eq $new_text ) { $found_match = TRUE; $new_text = $combo_model->get( $combo_iter, 0 ) ; # It's possible that this is a bad idea last; } $combo_iter = $combo_model->iter_next( $combo_iter ); } # If we haven't found a match, default to a zero if ( !$found_match ) { $new_text = 0; } } $model->set( $iter, $columnno, $new_text ); } sub dump_values { my $iter = $model->get_iter_first; print "Column 0 contains: " . $model->get( $iter, 0 ) . "\n"; print "Column 1 contains: " . $model->get( $iter, 1 ) . "\n"; print "Column 2 contains: " . $model->get( $iter, 2 ) . "\n"; print "\n"; } sub render_combo_cell { my ( $tree_column, $renderer, $model, $iter ) = @_; # Get the ID that represents the text value to display my $key_value = $model->get( $iter, 2 ); # Loop through our combo's model and find a match for the above ID to get our text value my $combo_iter = $combo_model->get_iter_first; my $found_match = FALSE; while ( $combo_iter ) { if ( $combo_model->get( $combo_iter, 0 ) && $key_value && $combo_model->get( $combo_iter, 0 ) == $key_value ) { $found_match = TRUE; $renderer->set( text => $combo_model->get( $combo_iter, 1 ) ); last; } $combo_iter = $combo_model->iter_next( $combo_iter ); } # If we haven't found a match, default to displaying an empty value if ( !$found_match ) { $renderer->set( text => "" ); } }