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? :)