It's pretty hard to say what your exact problem is without seeing a minimal working code example, but using the ESP module, I think what you are looking for is a single usuable thread, that processes the images(looping thru them), then use an Idle->add in the thread after each thumbnail is created, to add it to the widget in the main Gtk2 thread. Here is the basic idea of using Idle->add, it is the preferred way for threads to manipulate widgets in the main thread. The 2 second wait, you mention, hints at the eventloop being lazy in updating everything. The Idle->add will instruct the eventloop to add the new thumbnail to the display widget, at the first possible opening in event processing. Glib::Idle->add is the great advance that Gtk2 made over Tk, to allow threads to access the gui widgets safely. And DO NOT spawn a new thread to process each image, that will be very slow. Reuse a single (or maybe a couple) of threads.
#!/usr/bin/perl
use warnings;
use strict;
use threads;
use threads::shared;
use Glib qw/TRUE FALSE/;
use Gtk2 qw/-init -threads-init/;
Glib::Object->set_threadsafe (TRUE);
#setup shared hash
my %shash;
share(%shash); #will work for first level keys
$shash{'go'} = 0;
$shash{'work'} = '';
$shash{'die'} = 0;
my $num:shared = 0;
my $window = Gtk2::Window->new('toplevel');
$window ->signal_connect( 'destroy' => \&delete_event );
$window->set_border_width(10);
$window->set_size_request(300,300);
my $vbox = Gtk2::VBox->new( FALSE, 6 );
$window->add($vbox);
$vbox->set_border_width(2);
my $hbox= Gtk2::HBox->new( FALSE, 6 );
my $hbox1 = Gtk2::HBox->new( FALSE, 6 );
$vbox->pack_end($hbox,FALSE,FALSE,0);
$vbox->pack_end (Gtk2::HSeparator->new, FALSE, FALSE, 0);
$vbox->pack_end($hbox1,FALSE,FALSE,0);
$hbox->set_border_width(2);
$vbox->pack_end (Gtk2::HSeparator->new, FALSE, FALSE, 0);
my $ebutton = Gtk2::Button->new_from_stock('gtk-quit');
$hbox->pack_end( $ebutton, FALSE, FALSE, 0 );
$ebutton->signal_connect( clicked => \&delete_event );
my $pbar = Gtk2::ProgressBar->new();
$pbar->set_pulse_step(.1);
$hbox->pack_start($pbar,1,1,0);
my $label_w_markup = Gtk2::Label->new();
$label_w_markup->set_markup("<span foreground=\"yellow1\"
size=\"40000\">$num</span>");
$vbox->pack_end($label_w_markup,FALSE,FALSE,4);
######################################################
my $tbutton = Gtk2::Button->new_with_label('Run Thread');
$hbox1->pack_start($tbutton , 1, 1, 0 );
my $lconnect = $tbutton->signal_connect( clicked => sub{ launch() });
my $sconnect;
$window->show_all();
$pbar->hide; #needs to be called after show_all
#create 1 sleeping thread passing it the label and pbar to control
my $thread = threads->new(\&work, $label_w_markup, $pbar);
Gtk2->main;
######################################
sub delete_event {
$shash{'go'} = 0;
$shash{'die'} = 1;
$thread->join;
Gtk2->main_quit;
return FALSE;
}
#######################################
sub launch{
$pbar->show;
$tbutton->set_label('Stop Thread');
$tbutton->signal_handler_block($lconnect);
$sconnect = $tbutton->signal_connect( clicked => sub{ stop() });
$shash{'go'} = 1;
}
##################################################
sub stop{
print "stopped\n";
$shash{'go'} = 0;
$pbar->hide;
$tbutton->set_label('Run Thread');
$tbutton->signal_handler_block ($sconnect);
$tbutton->signal_handler_unblock ($lconnect);
}
#########################################################
sub work{
my ($label,$pbar) = @_;
$|++;
while(1){
if($shash{'die'} == 1){ return };
if ( $shash{'go'} == 1 ){
$num = 0;
while(1){
$num++;
if($num > 30){last}
Glib::Idle->add(
sub{
if($shash{'die'} == 1){ return };
$label->set_markup("<span foreground=\"yellow1\"
size=\"40000\">$num</span>");
$pbar->pulse;
return FALSE;
});
select(undef,undef,undef, .1);
if($shash{'go'} == 0){last}
if($shash{'die'} == 1){ return };
}
#if reach this point, the thread has finished
print "my results = $num\n";
Glib::Idle->add(
sub{
if($shash{'die'} == 1){ return };
$label->set_markup("<span foreground=\"green\"
size=\"60000\">$num</span>");
$pbar->hide;
return FALSE;
});
$shash{'go'} = 0; #turn off self before returning
}else
{ select(undef,undef,undef,.1) } #sleep time
}
}
| [reply] [d/l] |
From what I've gathered, in most GTK bindings for most languages, you can't/shouldn't call GTK routines from different threads - in other words: all GUI interactions should be handled by the same thread (but you can probably off-load a lot of non-GUI processing to other threads).
Whether or not threads and the way you're using them is even the right way to go about whatever it is that you're doing is another subject and I'm not going into that. I'm assuming you know what you're doing.
| [reply] |
You don't even need threads, you can load the images in a idle callback.
Here is an example I've made some time ago. It's a much more complex example, because it doesn't use a IconView, and it's not very clean, as the code comes from a much bigger program and I just made some quick modifications to make it work by itself, but it works very nicely.
To use it, pass it a list of files in standard input, for example with find :
find ~/Pictures/ -iname \*.jpg | perl mosaic_standalone.pl
It is made to display HUGE list of pictures, that's one of the reason it doesn't use Gtk2::IconView. But the principle of loading the pictures in a idle callback can be used with Gtk2::IconView.
You can find it here
| [reply] |
| [reply] |