llancet has asked for the wisdom of the Perl Monks concerning the following question:

I want to create a table of laptops. One of the column is the type of CPU, so I want to only allow user to select one from a list of given CPUs. I made something like this:

Firstly, a ListStore of CPUs, and a ListStore of the big table, defined in glade:
...... <object class="GtkTreeView" id="ModelTable"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="model">ModelListStore</property> <child internal-child="selection"> <object class="GtkTreeSelection" id="treeview-selection1 +"/> </child> </object> ...... <object class="GtkListStore" id="CPUListStore"> <columns> <!-- column-name col_cpu --> <column type="gchararray"/> </columns> </object> <object class="GtkListStore" id="ModelListStore"> <columns> <!-- column-name name --> <column type="gchararray"/> <!-- column-name cpu_name --> <column type="gchararray"/> <!-- column-name gpu_name --> <column type="gchararray"/> <!-- column-name mem_sz --> <column type="gfloat"/> <!-- column-name mem_freq --> <column type="gint"/> <!-- column-name disk_sz --> <column type="gint"/> <!-- column-name disk_rot --> <column type="gint"/> <!-- column-name screen_sz --> <column type="gfloat"/> <!-- column-name price --> <column type="gfloat"/> </columns> </object>
then create the GUI in perl:
# this is the table $model_table = $builder->get_object('ModelTable'); # cell renderer # 0th column of "CPUListStore" is used, as it has only that column. my $renderer_table_cpu = Gtk2::CellRendererCombo->new; $renderer_table_cpu->set(model=>$builder->get_object('CPUListStore')); $renderer_table_cpu->set(text_column=>0); $renderer_table_cpu->set(has_entry=>TRUE); # the TreeViewColumn # it corresponds to the COL_CPU_NAME column of the big table my $col_cpu = Gtk2::TreeViewColumn->new; $col_cpu->pack_start($renderer_table_cpu,TRUE); $col_cpu->add_attribute($renderer_table_cpu,'text',COL_CPU_NAME);

The problem is: when I change the value in combo, the table won't get modified. It seems the change of selection in the combobox does not correctly passed to the model of table. So how to use CellRendererCombo correctly? Thanks a lot!

Replies are listed 'Best First'.
Re: Hwo to correctly use Gtk2::CellRendererCombo?
by zentara (Cardinal) on Feb 07, 2012 at 10:52 UTC
    I don't use Glade, but here is how it's done in plain Gtk2. Check out the 3rd column.
    #!/usr/bin/perl use warnings; use strict; use Gtk2 -init; use Glib qw/TRUE FALSE/; # Someone 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 t +he 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 po +ssible 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 valu +e if ( !$found_match ) { $renderer->set( text => "" ); } }

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh