http://www.perlmonks.org?node_id=975009

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

Hello,
I am attempting to create a GUI using GTK2 that will display images stored on disk.

I have followed the example given in the link below.

http://gtk2-perl.sourceforge.net/doc/gtk2-perl-study-guide/c2349.html

I would like for my GUI to update an image, if the file has been updated on disk.

I have tried many things including using timeouts, add_watch etc. and I have trolled the web trying to find an example for this (most searches take me to perlmonks!).

It sounds simple enough to implement, but it has beaten me. Any assistance or pointers to example code would be very much appreciated.

  • Comment on GTK2 - Load updated image file into a frame

Replies are listed 'Best First'.
Re: GTK2 - Load updated image file into a frame
by zentara (Archbishop) on Jun 07, 2012 at 21:32 UTC
    Hi,

    To amplify on what Anonymous Monk said, here is how to do it. You do not want to rebuild the $hbox, only the image. I also cleaned up your code, you had many useless lines. The script below will cycle thru all jpg's in the script's directory for the demo. I improved on your use of "cat" to load the file, that code looked familiar to me, and is not very advanced. :-) The code below is much better, and it can be improved a bit, but it does show you the idea.

    #!/usr/bin/perl -w use Glib qw/TRUE FALSE/; use Gtk2 '-init'; use strict; # load all jpgs in directory for this demo my @files = <*.jpg>; #print "@files\n"; my $window = Gtk2::Window->new('toplevel'); $window->signal_connect(delete_event => sub { Gtk2->main_quit; return +FALSE; }); $window->set_title("Test set up"); $window->set_border_width(0); # create your first image and pass it to $hbox my $img1 = load_first_image(); my $hbox = &make_gui_frame($img1); $window->add($hbox); Glib::Timeout->add(1000, \&update_image); $window->show; Gtk2->main; 0; sub load_first_image{ my $file = $files[0]; my $pixbuf = Gtk2::Gdk::Pixbuf->new_from_file_at_scale($file,300,3 +00,1); return Gtk2::Image->new_from_pixbuf($pixbuf); } sub update_image { # circular list of images just for demo push (@files,shift(@files)); my $file = $files[0]; my $pixbuf = Gtk2::Gdk::Pixbuf->new_from_file_at_scale($file,300,300 +,1); $img1->set_from_pixbuf ($pixbuf); $window->show_all(); return 1; } sub make_gui_frame { my $img1 = shift; ## MAIN HBOX $hbox = Gtk2::HBox->new(FALSE, 20); my $frame = Gtk2::Frame->new('Data control'); $frame->set_shadow_type ('out'); #method of Gtk2::Container $frame->set_border_width(5); my $box1 = Gtk2::VBox->new(FALSE, 10); my $box2 = Gtk2::VBox->new(FALSE, 10); $box2->set_border_width(10); $box1->pack_start($box2, TRUE, TRUE, 0); my $button = Gtk2::Button->new("close"); $button->signal_connect(clicked => sub { Gtk2->main_quit; }); $box2->pack_start($button, TRUE, TRUE, 0); $button->can_default(TRUE); $frame->add($box1); $hbox->pack_start($frame, FALSE, FALSE,0); $frame = Gtk2::Frame->new('Data output and Overlay'); $frame->set_shadow_type ('out'); #method of Gtk2::Container $frame->set_border_width(5); my $vbox_image = Gtk2::VBox->new(FALSE, 10); $vbox_image->pack_start($img1,FALSE,FALSE,0); $frame->add($vbox_image); $hbox->pack_start($frame, FALSE, FALSE,0); $hbox->show_all(); return $hbox; }

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
      That worked a treat. Thanks for you help. The line $window->show_all() in sub update_image() was not obvious from the documentation on the web. This would be a good example. Thanks again.
Re: GTK2 - Load updated image file into a frame
by Anonymous Monk on Jun 07, 2012 at 18:59 UTC

    I have tried many things including using timeouts, add_watch etc.

    You tried what? What was the problem?

      My apologies, indeed I didn't state my problem.

      I have attached the code below. I would like for this simple GUI to always display the latest image file on disk, see below

       (my $raw_data1 = `cat ../test1.jpg`;)

      For this I believe you have to loop over the mainloop.

      As a simple solution I thought that I could use a timeout and call the subroutine make_gui_frame(). However, using the Timeout, I can't seem to figure out how to update what should be returned ($hbox).

      If I move all the $window calls in main to the subroutine make_new_window() (see below) and then call

      Glib::Timeout->add(1000,\&make_new_window);

      then after every Timeout call I get a new window that will always load the latest image file on disk.

      So I think my issue is how to return and update $hbox so that after every Timeout I can update $window ????

      #!/usr/bin/perl -w use Glib qw/TRUE FALSE/; use Gtk2 '-init'; use Gtk2::Gdk::Keysyms; use threads; use threads::shared; #use threads::Queue; Glib::Object->set_threadsafe (TRUE); $window = Gtk2::Window->new('toplevel'); $window->signal_connect(delete_event => sub { Gtk2->main_quit; return +FALSE; }); $window->set_title("Test set up"); $window->set_border_width(0); my $hbox=&make_gui_frame(); #### HOW DO I ACCESS $hbox using a timeout ? Glib::Timeout->add(1000,\&make_gui_frame); ##### $window->add($hbox); $window->show; Gtk2->main; 0; sub make_gui_frame { print "LOOPING HERE \n"; ## MAIN HBOX $hbox = Gtk2::HBox->new(FALSE, 20); my $frame = Gtk2::Frame->new('Data control'); $frame->set_shadow_type ('out'); #method of Gtk2::Container $frame->set_border_width(5); my $box1 = Gtk2::VBox->new(FALSE, 10); my $box2 = Gtk2::VBox->new(FALSE, 10); $box2->set_border_width(10); $box1->pack_start($box2, TRUE, TRUE, 0); $button = Gtk2::Button->new("close"); $button->signal_connect(clicked => sub { Gtk2->main_quit; }); $box2->pack_start($button, TRUE, TRUE, 0); $button->can_default(TRUE); $frame->add($box1); $hbox->pack_start($frame, FALSE, FALSE,0); $frame = Gtk2::Frame->new('Data output and Overlay'); $frame->set_shadow_type ('out'); #method of Gtk2::Container $frame->set_border_width(5); my $vbox_image = Gtk2::VBox->new(FALSE, 10); #the Gtk2::Gdk::PixbufLoader is used in # the acquisition of images in "raw" format. #This will typically be data from a database ################################################ ### THIS IS THE IMAGE I WANT TO HAVE LOADED ################################################ my $pixbufloader1 = Gtk2::Gdk::PixbufLoader->new; my $raw_data1 = `cat ../test1.jpg`; $pixbufloader1->write($raw_data1); $pixbufloader1->close; my $pixbuf1 = $pixbufloader1->get_pixbuf; my $img_orig1 = Gtk2::Image->new_from_pixbuf($pixbuf1); my $pixbuf1_smaller = $pixbuf1->scale_simple(300,300,'bilinear'); my $img1 = Gtk2::Image->new_from_pixbuf($pixbuf1_smaller); $vbox_image->pack_start($img1,FALSE,FALSE,0); $frame->add($vbox_image); $hbox->pack_start($frame, FALSE, FALSE,0); $hbox->show_all(); return $hbox; } sub make_new_window { $window = Gtk2::Window->new('toplevel'); $window->signal_connect(delete_event => sub { Gtk2->main_quit; return +FALSE; }); $window->set_title("Test set up"); $window->set_border_width(0); my $hbox=&make_gui_frame(); $window->add($hbox); $window->show; }

        My idea, use timer, but only do this in timer

        $image->clear; $image->set_from_file( 'test.jpg' );

        where $image is a global variable