GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Mon Sep 22, 2014 4:13 am

All times are UTC




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Need to force refresh of GtkImage
PostPosted: Thu Jun 09, 2011 8:43 pm 
Offline

Joined: Thu Jun 09, 2011 8:17 pm
Posts: 1
Hi all, my first post here. Bear with me, I'm also new to Gtk...

Rather than posting alot of code I'll try to describe my problem on a more conceptual level and would like to hear if what I'm trying to do and how I go about it seems sound.

I have an industrial camera from which I can manage to grab and save to disk as many pictures as I like. I do this in a loop which resides in a callback function which is called when the take pictures button is clicked. Number of pictures to take is specified by the user in a GtkTextEntry. So far so good. What I also want is that a GtkImage-widget should be updated to immediately display each new picture. This doesn't happen. Only the last picture taken will be displayed and this happens exactly when the "take pictures"-button callback returns. I guess the gtk-main loop has my request for widget update [gtk_image_set_from_pixbuf(snapshot, pixbuf)] queued and will do my request after it's done with the callback. I've tried some functions like gtk_widget_show_now and gtk_widget_queue_draw right after the call to gtk_image_set_from_pixbuf(snapshot, pixbuf), to no avail, obviously.

Any suggestions would be so welcome!

Take care folks,

Nanja


Top
 Profile  
 
 Post subject: Re: Need to force refresh of GtkImage
PostPosted: Fri Jun 10, 2011 8:46 am 
Offline
Never Seen the Sunlight

Joined: Wed Jul 23, 2008 10:31 am
Posts: 2406
Location: Slovenia
Hello and welcome to the GTK+ forums!

Your troubles are caused by the fact that GUI is only updated when main loop is idle (this way drawing operations can be optimized).

There are three possible solutions to this problem:
  1. ugly and simple, which is calling
    Syntax: [ Download ] [ Hide ]
    Using c Syntax Highlighting
    while (gtk_events_pending ()) gtk_main_iteration ();
    Parsed in 0.002 seconds, using GeSHi 1.0.8.4
  2. nice, but slow, which is getting images from within idle handler and letting GTK+ update itself in between
  3. nice, fast but complex, which is getting images in separate threads and delegating GUI updates to main thread
I would suggest second or third option.

Cheers,
Tadej


Top
 Profile  
 
 Post subject: Re: Need to force refresh of GtkImage
PostPosted: Fri Jun 10, 2011 5:28 pm 
Offline
GTK+ Guru

Joined: Fri Jan 04, 2008 3:17 pm
Posts: 183
Location: France (92340 Bourg La Reine)
A variant of getting the image in an idle function might be perhaps to ask the main loop to wait for input from your camera. If you have a real file descriptor from it, you might use g_io_add_watch on it.

Regards.

_________________
Basile Starynkevitch (France)
http://starynkevitch.net/Basile/


Top
 Profile  
 
 Post subject: Re: Need to force refresh of GtkImage
PostPosted: Sun Jun 19, 2011 6:14 am 
Offline
Never Seen the Sunlight

Joined: Thu Mar 24, 2011 2:10 pm
Posts: 328
Location: Sydney, Australia
The simplest option to me would be to only take one picture at a time, save and display it. Of course if your trying to take rapid shots then this is pretty useless advice as you don't want the GUI to limit the capture rate.


Top
 Profile  
 
 Post subject: Re: Need to force refresh of GtkImage
PostPosted: Fri Nov 04, 2011 10:06 pm 
Offline

Joined: Fri Nov 04, 2011 9:41 pm
Posts: 2
Hi there,
I hope I'm not digging out a thread from the depths :)
I have kind of same issue: I wanted to play a little with gtk lib and see how things work. So I wrote a sample code which, for each images in a folder, display a thumbnail and filename in a button, everything arranged in cols/rows. I also added a treeview to list the files, just for fun.
Here's the problem: I wanted to process image loading in another thread, so the main window shows, and thumbnails appear one at a time, allowing the user to do stuff meanwhile. But, I only got the few first thumbnails, and no widget is responding to mouse click or whatever.
I'm under Windows 7 32bits, VC++ 2008, and I use GTK+ 2.22. Here's the sample code :

Code:
#include <io.h>
#include <gtk/gtk.h>

#define TABLE_ROWS 10
#define TABLE_COLS 3

static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
    g_print("delete event occurred\n");

    return false;
}

static void destroy(GtkWidget *widget, gpointer data)
{
    gtk_main_quit ();
}

enum
{
   FILENAME_COLUMN = 0,

   COLUMN_NUMBER,
};

class CWorkerThread
{
public:
   CWorkerThread(std::vector<std::string>& a_rvFilename, std::vector<GtkWidget*>& a_rvWidget)
   {
      m_vFilename = a_rvFilename;
      m_vWidget = a_rvWidget;
   }

   void operator()()
   {
      printf("Debut chargement images\n");

      // pour chaque couple filename/widget
      unsigned int const uiLength = m_vFilename.size();

      for(unsigned int uiIndex = 0; uiIndex < uiLength; uiIndex++)
      {
         // affiche une image miniature
         std::string& strFilename = m_vFilename[uiIndex];
         GtkWidget* pImage = m_vWidget[uiIndex];
         GdkPixbuf* pPixbuf = gdk_pixbuf_new_from_file_at_scale(strFilename.c_str(), 128, 128, true, NULL);
         gtk_image_set_from_pixbuf(GTK_IMAGE(pImage), pPixbuf);
      }

      printf("Fin chargement images\n");
   }

private:
   std::vector<GtkWidget*> m_vWidget;
   std::vector<std::string> m_vFilename;
};

void LoadThumbnail(void* a_pObject)
{
   CWorkerThread* pWorkerThread = (CWorkerThread*)a_pObject;
   (*pWorkerThread)();
}

int main(int argc, char *argv[])
{
   gtk_init(&argc, &argv);

   // init les threads
   if(g_thread_supported() == true)
   {
      g_thread_init(NULL);
      gdk_threads_init();
   }
   else
   {
      printf("No threads !");
      return 1;
   }

   // window
   GtkWidget* pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   gtk_window_set_default_size((GtkWindow*)pWindow, 1280, 960);
   gtk_container_set_border_width(GTK_CONTAINER(pWindow), 10);
   gtk_widget_show(pWindow);
   g_signal_connect(pWindow, "delete-event", G_CALLBACK(delete_event), NULL);
   g_signal_connect(pWindow, "destroy", G_CALLBACK(destroy), NULL);

   // h paned
   GtkWidget* pHPaned = gtk_hpaned_new();
   gtk_widget_show(pHPaned);
   gtk_container_add(GTK_CONTAINER(pWindow), pHPaned);

   // tree view
   GtkTreeStore* pTreeStore = gtk_tree_store_new(COLUMN_NUMBER, G_TYPE_STRING);

   // scrolledwindow
   GtkWidget* pScrolledWindow = gtk_scrolled_window_new(NULL, NULL);
   gtk_paned_add2((GtkPaned*)pHPaned, pScrolledWindow);
   gtk_widget_show(pScrolledWindow);

   // table
   GtkWidget* pTable = gtk_table_new(TABLE_ROWS, TABLE_COLS, true);
   gtk_table_set_col_spacings(GTK_TABLE(pTable), 10);
   gtk_table_set_row_spacings(GTK_TABLE(pTable), 10);
   gtk_container_set_border_width(GTK_CONTAINER(pTable), 10);
   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(pScrolledWindow), pTable);
   gtk_widget_show(pTable);

   // cherche tous les jpeg dans le rep
   const char* szSearchFile = "d:\\images\\alice\\*.jpg";
   const char* szPath = "d:\\images\\alice\\";

   std::vector<std::string> vShortFilename;
   std::vector<std::string> vFullFilename;
   _finddata_t sFindData;
   long hFindHandle = _findfirst(szSearchFile, &sFindData);

   if(hFindHandle != -1L)
   {
      do
      {
         std::string strFilename(szPath);
         strFilename.append(sFindData.name);
         vFullFilename.push_back(strFilename);
         vShortFilename.push_back(sFindData.name);
      }
      while(_findnext(hFindHandle, &sFindData) != -1L);
   }

   std::vector<GtkWidget*> vImageWidget;

   for(int iRowIndex = 0; iRowIndex < TABLE_ROWS; iRowIndex++)
   {
      for(int iColIndex = 0; iColIndex < TABLE_COLS; iColIndex++)
      {
         int const iFileIndex = iRowIndex * TABLE_COLS + iColIndex;

         if(iFileIndex < vFullFilename.size())
         {
            std::string& strShortFilename = vShortFilename[iFileIndex];

            // ajoute au tree view
            GtkTreeIter itTreeStore;
            gtk_tree_store_append(pTreeStore, &itTreeStore, NULL);
            gtk_tree_store_set(pTreeStore, &itTreeStore, FILENAME_COLUMN, strShortFilename.c_str(), -1);

            // ajoute à la vue principale
            GtkWidget* pButton = gtk_toggle_button_new();
            gtk_table_attach_defaults(GTK_TABLE(pTable), pButton, iColIndex, iColIndex+1, iRowIndex, iRowIndex+1);
            gtk_widget_show(pButton);

            GtkWidget* pVBox = gtk_vbox_new(false, 5);
            gtk_container_add(GTK_CONTAINER(pButton), pVBox);
            gtk_widget_show(pVBox);

            // crée une image pour la miniature
            GtkWidget* pImage = gtk_image_new();
            gtk_container_add(GTK_CONTAINER(pVBox), pImage);
            gtk_widget_show(pImage);
            vImageWidget.push_back(pImage);

            // affiche le nom du fichier
            GtkWidget* pLabel = gtk_label_new(strShortFilename.c_str());
            gtk_widget_show(pLabel);
            gtk_container_add(GTK_CONTAINER(pVBox), pLabel);

         }
      }
   }

   // create tree view
   GtkWidget* pTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pTreeStore));
   GtkCellRenderer* pCellRenderer = gtk_cell_renderer_text_new();
   GtkTreeViewColumn* pTreeViewColumn = gtk_tree_view_column_new_with_attributes("Filename", pCellRenderer, "text", FILENAME_COLUMN, NULL);
   gtk_tree_view_append_column(GTK_TREE_VIEW(pTreeView), pTreeViewColumn);
   gtk_paned_add1(GTK_PANED(pHPaned), pTreeView);
   gtk_widget_show(pTreeView);

   // démarre le thread de chargement des images
   CWorkerThread oWorkerThread(vFullFilename, vImageWidget);
   GError* pError = NULL;
   GThread* pThread = g_thread_create((GThreadFunc)LoadThumbnail, (void*)&oWorkerThread, true, &pError);
   if(pThread == NULL)
   {
      printf("Echec a la creation du thread: %s\n", pError->message);
      g_error_free(pError);
   }

   printf("Debut GTK Main\n");

   gtk_main();

   return 0;
}


The object CWorkerThread was written as I first tried to use boost::thread with a functor, to see if mixing the 2 libs mess up. So far, the result is the same.

So, as you can see, I'm setting a gtkpixbuf to a gtkimage in the thread. I even tried adding "gtk_widget_queue_draw(pImage);" right after, to see if it forces an update. No change.
I was unable to find any relevant help/documentation by googling "gtkimage update from thread". I think the problem might come from the fact we enter gtk_main before the thread ends.

Anyone has already made this or experienced this issue? Especially tadeboro, whose third suggestion to nanjamonja's problem is the way I wrote my code? :)


Top
 Profile  
 
 Post subject: Re: Need to force refresh of GtkImage
PostPosted: Sat Nov 05, 2011 7:38 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 746
Location: UK
Hi,

You have two problems here. The first is that GTK+ can only be called from one thread at a time, so you must use its own internal locking system to ensure that happens. The two functions to lock and unlock from other threads is gdk_threads_enter() and gdk_threads_leave().

Your second problem is that using GTK+ under MS Windows and the calling of GDK and GTK+ functions from multiple threads is not supported. If you do then you will end up with unpredictable results.

You also have a race condition where you have started the thread before entering the GTK main loop.

In your case it would be better to use the "Idle" method to load the images one at a time.

E.

_________________
E.


Top
 Profile  
 
 Post subject: Re: Need to force refresh of GtkImage
PostPosted: Sat Nov 05, 2011 8:22 pm 
Offline

Joined: Fri Nov 04, 2011 9:41 pm
Posts: 2
Hi !
Thanks a lot errol, your answer helped me understanding a little bit more GTK+ !
After some searches, I understand the first problem: GTK+ functions can only be called by one thread at a time. I fixed the code to surround the gtk_image_set_from_pixbuf call with gdk_threads_enter/gdk_threads_leave, and it works like a charm !
I have to admit that at first glance, this one thread restriction was a quite creepy, but actually, there's a lot of code in threads not concerning directly gtkwidget and such.

However, would you give me the big lines about the second problem ? What might I experience by calling GDK and GTK functions from different threads ? So far, I haven't found any infos about this.

Also, if gtk calls in threads are surrounded by gdk_threads_enter/gdk_threads_leave, which race condition problems would I encounter ?

Regards.


edit: I might have figured out one race condition problem actually, occuring if GTKImages are destroyed outside of the thread, and the thread trying to set a pixbuf to it.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group