Click here to Skip to main content
15,887,135 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am trying to make an application which renders a window of several rows and columns, and update it using some input I receive from command line. I am able to add rows based on the input, but the problem I am facing is that the GUI only shows up in the end once it(i.e GtkListStore) is updated.

I have found that is expected, and to make it work as expected(i.e updating the GUI on the go, as the gtkListStore is being updated) I need to use threads, I have found some tutorials but they are all explained in python. Since I am extremely new to gtk and already know very less about it, I am unable to connect and understand what do I exactly need to do to make my gtk application written in C work as expected.

What I have tried:

This is the code, apologies for the large block of code.
C++
#include <stdio.h>
#include <gtk/gtk.h>
#include <stdlib.h>

struct retObj {
	GtkListStore *store;
	GtkWidget* wid;
	GtkTreeIter* iter;
};

struct retObj create_and_fill_model (void) {
  GtkListStore *store;
  GtkTreeIter iter;

	store =
    	gtk_list_store_new (3, G_TYPE_INT, G_TYPE_INT,
			G_TYPE_INT);

	for (int a = 0; a < 4; a++)    {
      	gtk_list_store_append (store, &iter);
      	gtk_list_store_set (store, &iter, 
			  0, 1,
			  1, 2,
			  2, 3,
			  -1);
	}
	struct retObj tempret;
	tempret.store = store;
	tempret.iter = &iter; 
	return tempret;
}

struct retObj create_view_and_model (void) {
   
  struct retObj ro; 
  GtkCellRenderer *renderer;
  GtkTreeModel *model;
  GtkWidget *view;
  view = gtk_tree_view_new ();

  renderer = gtk_cell_renderer_text_new ();
  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
					       -1,
					       "First column",
					       renderer,
					       "text", 0, NULL);
  renderer = gtk_cell_renderer_text_new ();
  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
					       -1,
					       "Second column",
					       renderer,
					       "text", 1, NULL);

  ro = create_and_fill_model();
  model = GTK_TREE_MODEL (ro.store);
  gtk_tree_view_set_model (GTK_TREE_VIEW (view), model);

  g_object_unref (model);
  ro.wid = view;
  return ro;
}

void addrow(struct retObj abc) {
	GtkTreeIter iter;
	gtk_list_store_append (abc.store, &iter);
    gtk_list_store_set (abc.store, &iter, 
			  0, -1,
			  1, -2,
			  2, 3, 
			  -1);
}

int main (int argc, char **argv) {
  GtkWidget *window;
  GtkWidget *view;
  GtkWidget *vbox;
  GtkWidget *sw;
  GtkListStore *st;

  gtk_init (&argc, &argv);
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);


  gtk_container_set_border_width (GTK_CONTAINER (window), 15);

  g_signal_connect (window, "delete_event", gtk_main_quit, NULL);	
  struct retObj rroo;
  rroo = create_view_and_model ();

  view = rroo.wid;
  st = rroo.store;

  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 15);
  gtk_container_add (GTK_CONTAINER (window), vbox);

  gtk_box_pack_start (GTK_BOX (vbox),
		      gtk_label_new ("Practice"),
		      FALSE, FALSE, 0);


  sw = gtk_scrolled_window_new (NULL, NULL);

  gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);

  gtk_container_add (GTK_CONTAINER (sw), view);

  gtk_window_set_default_size (GTK_WINDOW (window), 480, 620);

  gtk_widget_show_all (window);

  int cont = 1;
  while(cont != 0) {
  	printf("Enter 1 to add row\nEnter 0 to stop\n");
  	scanf("%d", &cont);
    addrow(rroo);
  }
  gtk_main ();
  return 0;
}


Here the function "create_and_fill_model()" creates an intial GtkTreeView window with 4 rows, of 3 columns each, whereas the function "addRow()" adds more rows to the original GtkTreeView. In the main() I am running a loop and taking user input, and while the input is 1, I am calling addRow() function. Now the addRow function is called as many times as a positive input is given, but the problem is that GUI only pops up in the end.

What I want is the GUI to pop up as soon as the program is executed, and on every positive input, when the addRow() function is called, the GUI should keep on updating. I have been told to use "g_idle_add()" for it, but I am really confused to do it exactly in this program.
Posted
Updated 29-Dec-23 4:39am
v2
Comments
Richard MacCutchan 29-Dec-23 10:50am    
I assume you need to use GTK's own thread library: GLib – 2.0: Threads[^].

1 solution

The reason the GUI appears is because gtk_main is called. That means you need to save all data necessary to add a row and make it accessible to the updating thread. It seems your retObj structure can be used for that purpose. When you create the thread(s) pass a pointer or reference to an instance of that structure and then when the thread obtains data it can update the view. Another option, and what I usually do, is to make all of the data globally accessible and when the thread receives data it saves it and notifies the view via a message or event and the view updates itself. If events and messages are not available then you could probably implement a polling loop that continually looks for new data to be available and updates the view when it is. That should be the tactic of last resort though because event-driven designs are more efficient.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900