if so, how do i do it - at a guess, Gtk2::SimpleList->add_column_type would be used, but the documentation is fairly minimal and i can't figure it out.
back-story: i'm writing a very quick and dirty POS system using perl, gtk2, and postgres to replace a completely bletcherous ancient DOS + COBOL program that came on the windows box when we bought our bookshop. i want to get rid of the windows box and replace it with a linux box. more importantly, i want access to our sales data so i can write whatever queries we need.
all the POS system needs to do is allow the user to enter sales items, calculate totals, print receipts, and store the transaction in postgres. the reports will be completely separate, and probably web-based.
so, i've figured out how to do menus, and SimpleLists to display the items. now i want the user to be able to override the RRP with either a fixed-price or a percentage discount for each item. that requires a "discount field" and a discount type field (popup menu: "None", "Fixed", "Percentage").
Gtk2::SimpleList->add_column_type ($type_name, ...) $type_name (string)
Which lets you add any custom type column, and you want to add a CellRendererCombo.
Now it just so happens, that a Gtk2-perl developer , Daniel Kasak just posted a sample script to the Gtk2-perl maillist, where he questioned whether such a combo cell acted buggy in a plain ListStore. You could either drop the requirement for SimpleList and go with ListStore, or pull the drop down combo model code from the script below, and add it as a column type to your SimpleList. I'll see if I can get it working later today, if not, muppet on the maillist would know. (but I hate to overwork the poor guy, :-) )
So here is the ListStore example, from which you could extract the combo model for the drop down.
#!/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 => "" );
}
}
btw, speaking of Class::DBI, i notice that there's also DBIx::Class which says it is inspired by Class::DBI (compatible with it but adding some new features). anyone know if there is any really compelling reason to use one over the other? DBIx::Class claims to do more, but Class::DBI seems to have much better documentation - which is a winner for me.
#!/usr/bin/perl
use warnings;
use strict;
use Gtk2 -init;
use Glib qw/TRUE FALSE/;
my $window = Gtk2::Window->new( "toplevel" );
$window->signal_connect( "destroy", sub { Gtk2->main_quit(); } );
$window->set_default_size(600,200);
my $vbox = Gtk2::VBox->new( 0, 5 );
$vbox->set_size_request(0,0);
my $model = Gtk2::ListStore->new(
"Glib::String",
"Glib::String",
"Glib::String", # easy to use string for ints
"Glib::String",
"Glib::String",
"Glib::Boolean",
"Glib::Double",
'Gtk2::Gdk::Pixbuf',
);
my $pixbuf = Gtk2::Button->new->render_icon ('gtk-home', 'large-toolbar');
$model->set( $model->append, 0 => 'Joe',
1 => 'Schmoe',
2 => 1,
3 => 'two',
4 => 'foo',
5 => 1,
6 => 42.42 ,
7 => $pixbuf
);
$model->set( $model->append, 0 => 'Billy',
1 => 'Bobo',
2 => 3,
3 => 'five',
4 => 'bar',
5 => 0,
6 => 24.42,
7 => $pixbuf
);
############ Column0 setup ##############################################
###########################################################################
my $col0 = 0;
my $renderer_0 = Gtk2::CellRendererText->new;
$renderer_0->set( editable => TRUE );
$renderer_0->signal_connect( edited => sub { &process_editing( @_, $col0 ); } );
############################################################################
my $column_0 = Gtk2::TreeViewColumn->new_with_attributes(
" Text1 ",
$renderer_0,
'text' => $col0
);
###########################################################################
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
############ Column1 setup ##############################################
my $col1 = 1;
my $renderer_1 = Gtk2::CellRendererText->new;
$renderer_1->set( editable => TRUE );
$renderer_1->signal_connect( edited => sub { &process_editing( @_, $col1 ); } );
##########################################################################
my $column_1 = Gtk2::TreeViewColumn->new_with_attributes(
" Text2 ",
$renderer_1,
'text' => $col1
);
#############################################################################
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
############ Column2 setup ##############################################
#############################################################################
my $col2 = 2;
my $combo_model = Gtk2::ListStore->new(
"Glib::String"
);
foreach my $choice (1,2,3,4,5,){
$combo_model->set($combo_model->append,0,$choice );
}
my $renderer_2 = Gtk2::CellRendererCombo->new;
$renderer_2->set(
editable => TRUE,
text_column => 0,
has_entry => TRUE,
model => $combo_model
);
$renderer_2->signal_connect( edited => sub { &process_editing( @_, $col2 ); } );
my $column_2 = Gtk2::TreeViewColumn->new_with_attributes(
"Combo Drop",
$renderer_2,
text => $col2
);
#############################################################################
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
############ Column3 setup ##############################################
my $col3 = 3;
my $combo_model1 = Gtk2::ListStore->new( "Glib::String" );
foreach my $choice ('one','two','three','four','five'){
$combo_model1->set($combo_model1->append,0,$choice );
}
my $renderer_3 = Gtk2::CellRendererCombo->new;
$renderer_3->set(
editable => TRUE,
text_column => 0,
has_entry => TRUE,
model => $combo_model1
);
$renderer_3->signal_connect( edited => sub { &process_editing( @_, $col3 ); } );
my $column_3 = Gtk2::TreeViewColumn->new_with_attributes(
"Combo Drop",
$renderer_3,
text => $col3
);
###################################################################################
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
############ Column4 setup ##############################################
my $col4 = 4;
my $combo_model2 = Gtk2::ListStore->new( "Glib::String" );
foreach my $choice ('foo','bar','baz','buz','fum'){
$combo_model2->set($combo_model2->append,0,$choice );
}
my $renderer_4 = Gtk2::CellRendererCombo->new;
$renderer_4->set(
editable => TRUE,
text_column => 0,
has_entry => FALSE, #makes a pure popup
model => $combo_model2
);
$renderer_4->signal_connect( edited => sub { &process_editing( @_, $col4 ); } );
my $column_4 = Gtk2::TreeViewColumn->new_with_attributes(
"Combo PoP",
$renderer_4,
text => $col4
);
###################################################################################
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
############ Column5 setup ##############################################
my $col5 = 5;
my $togglemodel = Gtk2::ListStore -> new(qw(Glib::Boolean));
my $renderer_5 = Gtk2::CellRendererToggle->new();
$renderer_5->set( activatable => 1 );
$renderer_5->signal_connect(
toggled => sub { &process_toggle(@_, $col5) }
);
my $column_5 = Gtk2::TreeViewColumn->new_with_attributes (
' On/Off ',
$renderer_5,
);
$column_5->set_resizable (TRUE);
# set initial value on display
$column_5->set_cell_data_func( $renderer_5, sub { &render_toggle_cell( @_, $col5 ); } );
###############################################################################
##############################################################################
# main program starts
my $treeview = Gtk2::TreeView->new( $model );
# a TreeSelection
$treeview->get_selection->set_mode ('extended');
$treeview->set_rules_hint( TRUE );
$treeview->append_column( $column_0 );
$treeview->append_column( $column_1 );
$treeview->append_column( $column_2 );
$treeview->append_column( $column_3 );
$treeview->append_column( $column_4 );
$treeview->append_column( $column_5 );
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, 1, 1, 0 );
my $button = Gtk2::Button->new( "Dump Values" );
$button->signal_connect( "clicked" => sub { &dump_values(@_); } );
$vbox->pack_start( $button, 0, 0, 0 );
$window->add( $vbox );
$window->show_all;
Gtk2->main;
############################################################################
sub process_editing {
my ( $renderer, $text_path, $new_text, $column ) = @_;
my $path = Gtk2::TreePath->new_from_string ($text_path);
my $iter = $model->get_iter ($path);
#update the underlying model
$model->set( $iter, $column, $new_text);
}
##############################################################################
sub process_toggle{
my ($cell, $row_num, $column) = @_;
my $path = Gtk2::TreePath->new_from_string ($row_num);
# get toggled iter
my $iter = $model->get_iter($path);
my ($toggle_item) = $model->get ($iter,$column);
# flip the value
$toggle_item ^= 1;
# set new value in underlying model
$model->set ($iter, $column, $toggle_item);
}
###############################################################################
sub render_toggle_cell {
my($tcolview,$cell,$model,$iter, $column) = @_;
# print "$tcolview, $cell, $model, $iter, $column\n";
my ($toggle_item) = $model->get ($iter, $column);
if($toggle_item){
$cell->set_active(1);
}else{$cell->set_active(0)}
}
##############################################################################
sub dump_values {
my $treeselection = $treeview->get_selection;
# print "$treeselection\n";
#for a single selection mode
# my $iter = $treeselection->get_selected;
# my $iter = $model->get_iter_first;
#for multiple selection mode
my @selpaths = $treeselection->get_selected_rows;
# read perldoc Gtk2::Tree::Model Gtk2::Tree::Selection
foreach my $tpath(@selpaths){
my $iter = $model->get_iter($tpath);
print $model->get( $iter, 0 ) . '--';
print $model->get( $iter, 1 ) . '--';
print $model->get( $iter, 2 ) . '--';
print $model->get( $iter, 3 ) . '--';
print $model->get( $iter, 4 ) . '--';
print $model->get( $iter, 5 ) . '--';
print "\n";
}
}
perlmonks.org content © perlmonks.org and cas2006, zentara
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03