GTK Linux C Get Input from Entry Box via Button Widget - c

I have a table that is filled with entry boxes, labels, and buttons.
Currently, if I compile the code, I can get input from a text box but only if the users presses the enter key, and the text only comes from the box they are currently typing in.
I would like to be able to get input from both text boxes when the "Login" button is pushed. I've tried using the same callback function that's used for enter key on the entry box, but GTK gives me an error.
If anyone could show me some code that would allow for me to get text from my entry boxes that are within tables (I know the method for retrieving data from tables and v/boxes is different) it would be greatly appreciated, as I can't seem to find it in any tutorials.
Will update w/working code.
Error when trying to attach status bar to table:
(Entry:5526): Gtk-CRITICAL **: gtk_table_attach: assertion `child->parent == NULL' failed
(Entry:5526): GLib-GObject-WARNING **: invalid cast from GtkTable' toGtkStatusbar'

Your callback function (named callback) needs to access both GtkEntry widgets in order to obtain their values. There are several ways this can be accomplished. Many GTK C programs use global variables, or global variables with file scope (ie a variable declared as static outside of any function within a file).
Remove your entry1 and entry2 variables near the top of the file before any functions:
static GtkWidget *entry1 = 0;
static GtkWidget *entry2 = 0;
And then modify the callback like so:
/* Our callback.
* The data passed to this function is printed to stdout */
static void callback( GtkWidget *widget, gpointer data)
{
const gchar *entry_text1;
const gchar *entry_text2;
g_print ("Hello again - %s was pressed\n", (char *) data);
entry_text1 = gtk_entry_get_text (GTK_ENTRY (entry1));
entry_text2 = gtk_entry_get_text (GTK_ENTRY (entry2));
g_print ("Contents of entries:\n%s\n%s\n", entry_text1, entry_text2);
}
You should additionally make similar modifications to the enter_callback function, and don't forget to remove the GtkWidget pointers to both GtkEntry from main.
As an alternative to using (static) global variables, create a data structure to hold the entries:
typedef struct login_data
{
GtkWidget *entry1;
GtkWidget *entry2;
} login_data;
This then gets passed to the callback (rather than text string as before), and the callback changes like so:
static void callback( GtkWidget *widget, gpointer data)
{
login_data* ld = (login_data*)data;
const gchar *entry_text1;
const gchar *entry_text2;
entry_text1 = gtk_entry_get_text (GTK_ENTRY (ld->entry1));
entry_text2 = gtk_entry_get_text (GTK_ENTRY (ld->entry2));
g_print ("Contents of entries:\n%s\n%s\n", entry_text1, entry_text2);
}
The data structure is dynamically allocated to prevent it going out of scope (not strictly necessary in simple applications) and this is done before using g_signal_connect to connect the callback to the entries:
login_data* ld = g_malloc(sizeof(*ld));
// callback function to execute when login is clicked
g_signal_connect (LoginButton, "clicked", G_CALLBACK (callback), (gpointer) ld);
Using this method, you must change all references to entry1 and entry2 to ld->entry1 and ld->entry2. Lastly, before the program exits, you should call g_free on the dynamically allocated struct ie g_free(ld).
BTW, for this program you don't need two separate callbacks, remove enter_callback and just use callback for both.

Related

Invalid UTF-8 string

I trying to swap the window title with the label inside the window on
keypress.
Below is my code :
#include<gtk/gtk.h>
static gboolean key_press_event(GtkWidget*,GdkEvent*,gpointer);
int main(int argv, char* argc[])
{
GtkWidget *window,*label;
gtk_init(&argv,&argc);
window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Sajith");
gtk_widget_set_size_request(window,300,100);
label=gtk_label_new("Sam");
gtk_label_set_selectable(GTK_LABEL(label),TRUE);
gtk_container_add(GTK_CONTAINER(window),label);
g_signal_connect(G_OBJECT(window),"key_press_event",
G_CALLBACK(key_press_event),label);
gtk_widget_show_all(window);
gtk_main();
}
static gboolean key_press_event(GtkWidget* window, GdkEvent* event, gpointer label)
{
GtkWidget* newlabel;
newlabel=GTK_LABEL(label);
const gchar* wtitle=gtk_window_get_title(GTK_WINDOW(window));
gtk_window_set_title(GTK_WINDOW(window),gtk_label_get_text(GTK_LABEL(newlabel)));
gtk_label_set_text(GTK_LABEL(newlabel),wtitle);
/* I am not sure if I could pass wtitle here*/
return FALSE;
}
On execution the window title is successfully swapped but the label is not.
Also, I get the following warning at the terminal.
(2p1:12005): Pango-WARNING **: Invalid UTF-8 string passed to pango_layout_set_text()
Any help appreciated.
gtk_window_get_title() returns a static buffer owned by the window. This buffer will have been changed after the gtk_window_set_title() call.
To achieve what you want, you should, in your callback function, create a copy of the string. You can use strdup(), but it may not be available on all platforms. Since you are using GTK+ which depends on GLib, you can use g_strdup(). Example:
gchar* wtitle = g_strdup(gtk_window_get_title(GTK_WINDOW(window)));
Remember to free it before the callback function returns with g_free(wtitle).
As for the return value, since the callback function returns gboolean, you cannot return wtitle. For your case, I don't see any difference between returning TRUE or FALSE, as there aren't any default handlers anyway. If, instead of a label, you are using something like a GtkEntry, then you would return TRUE if you don't want the text in the entry to be replaced by your input key.

C/GTK+ GTK_IS_PROGESSBAR failed

I have a main.c file where a progress bar is created and then it will be updated by other.c file.
Inside the main.c file i have this:
static void
a_func ( GtkWidget *dialog,
struct widget_t *Widget,
gint mode)
{
....
....
Widget->pBar = gtk_progress_bar_new ();
....
....
}
which create and run a dialog. When OK is pushed my_func (Widget); will be called.
Inside the other.c file i have this:
static gboolean
fill (gpointer data)
{
GtkWidget *bar = data;
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (bar));
return TRUE;
}
gint my_func (struct mystruct_t *Widget){
....
....
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (Widget->pBar));
g_timeout_add (100, fill, GTK_PROGRESS_BAR (Widget->pBar));
while (gtk_events_pending ())
gtk_main_iteration ();
....
....
}
The problem is that i'm getting this error:
GLib-GObject-WARNING **: invalid unclassed pointer in cast to 'GtkProgressBar'
Gtk-CRITICAL **: gtk_progress_bar_pulse: assertion 'GTK_IS_PROGRESS_BAR (pbar)' failed
EDIT 1:
This is a compilable example: https://gist.github.com/polslinux/96e7b18176ac66e50ee1
EDIT 2:
This is a simple workflow graph: http://it.tinypic.com/r/316us0y/8
This can not work:
crypt_file (Widget);
gtk_widget_destroy (dialog);
You add a GSource to your mainloop which modifies Widget->pBar but you never remove it. On the other hand you destroy the dialog (and thus also pBar itself as it is part of the widget sub-tree) which in turn renders Widget->pBar useless/makes it a dangling pointer.
Things you did not ask for (excuse the direct approach)
Your variable names are crappy at best, upper lower case, calling things Widget which are no widgets but mere structs.
Make sure you do not split into callbacks and other C functions. That will end up totally messy as your project grows.
Try to go for object-orientation. Create a GObject derived klass which handles the mess internally instead of passing translucent structs around.

return filename from G_CALLBACK in GTK

Hey guys so I would like to return value of filename from function (or pointer) but Im to sure how to do it. My filename stores path to file name /home/username/file. So here is my main
gchar *filename = NULL;
button = GTK_WIDGET( gtk_builder_get_object( builder, "button1" ) );
g_signal_connect (button, "clicked", G_CALLBACK (show_dialog), &filename);
And show dialog look like this
static void
show_dialog ( GtkWidget *button,
gint response_id,
gpointer user_data )
/* Init filechoosedialog, builder etc */
{
gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechoosedialog));
}
Do I need to change static void show_dialog to gchar show_dialog and at end do I need to do return filename; and what else do I need to declare because Im getting compile error
warning: return makes integer from pointer without a cast
So I would like to add code like this to my main and to get value of filename
if filename != NULL
g_print ("Selected filename: %s\n", filename);
This sounds like a misunderstanding of event driven programming. You don't do things like this in main(), you do it in the event handler. In your example you would call g_print() from show_dialog().
If you want to do something more complex you'll need to know some application state: that's what the g_signal_connect() userdata pointer is for. As an example, if you want to set the filename as the text of a label, you would set a pointer to the label as the user data pointer and can then set the label text in the event handler.
More generically, the userdata pointer can be anything: e.g. a data structure that you can use to store the filename string. Typical usage is an application data struct that is allocated in main: The struct contains all "application global" variables (like filename) and a pointer to the struct is given to all GTK+ callbacks so all functions can access and modify the struct contents.
If the problem was using the userdata pointer, here's an example using just a pointer to the filename as userdata:
g_signal_connect (button, "clicked", G_CALLBACK (button_clicked_cb), &filename);
static void
button_clicked_cb (GtkWidget *button,
gint response_id,
gpointer user_data)
{
char **filename_ptr = (char**)user_data;
*filename_ptr = g_strdup ("newly allocated string that the filename pointer in main() stack will now point to");
}

gtktreeview works fine in the example but stops once copied into application

I have the following problem. I'm developing an application which uses gtktreeview for displaying data retrieved from MySQL database.
I've already done few examples of gtktreeview, I was able to add, clear, remove from the list. Now I wanted to adapt this example to my application and suddenly it doesn't work anymore.
Here is the example I used which works.
The enum:
static enum {
FIRST_NAME,
LAST_NAME,
N_COL
};
The variables:
static GtkWidget *list;
static GtkWidget *f_entry;
static GtkWidget *l_entry;
The setup of a list:
static GtkWidget *setup_list()
{
GtkWidget *sc_win;
GtkListStore *store;
GtkCellRenderer *cell;
GtkTreeViewColumn *column;
sc_win = gtk_scrolled_window_new(NULL, NULL);
gtk_widget_set_usize(sc_win, 250, 150);
store = gtk_list_store_new(N_COL, G_TYPE_STRING, G_TYPE_STRING);
list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
cell = gtk_cell_renderer_text_new();
// column of the names
column = gtk_tree_view_column_new_with_attributes("ImiÄ™", cell, "text", FIRST_NAME, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
// column of the surnames
column = gtk_tree_view_column_new_with_attributes("Nazwisko", cell, "text", LAST_NAME, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
// scrolls
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(sc_win), list);
// free the store variable and return the scrolled window pointer
g_object_unref(G_OBJECT(store));
return sc_win;
}
The function which adds an element:
static void list_add_cb(GtkWidget* widget, gpointer data)
{
GtkListStore *store;
GtkTreeIter iter;
const char *first;
const char *last;
first = gtk_entry_get_text(GTK_ENTRY(f_entry));
last = gtk_entry_get_text(GTK_ENTRY(l_entry));
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, FIRST_NAME, first, LAST_NAME, last, -1);
}
And here is the equivalent in my application.
The enum:
enum {
ID_ALIAS,
N_COL
};
The variables (only those significant for the example):
static GtkWidget *list_pas;
static GtkWidget *list_key;
The setup of a list (almost identycle, except of passing the column name in the parameter and usage of only one column):
static GtkWidget *setup_list(char *typ)
{
GtkWidget *sc_win;
GtkWidget *list;
GtkListStore *store;
GtkCellRenderer *cell;
GtkTreeViewColumn *column;
sc_win = gtk_scrolled_window_new(NULL, NULL);
gtk_widget_set_usize(sc_win, 250, 150);
store = gtk_list_store_new(N_COL, G_TYPE_STRING, G_TYPE_STRING);
list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
cell = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(typ, cell, "text", ID_ALIAS, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
// scrolls
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(sc_win), list);
// free the store variable and return the scrolled window pointer
g_object_unref(G_OBJECT(store));
return sc_win;
}
The function which adds an element (in data there is a string of the element to add to the list and in the widget there is scrolled window which contains proper list):
static void list_add_cb(GtkWidget* widget, gpointer data)
{
GtkListStore *store;
GtkTreeIter iter;
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(widget)));
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, ID_ALIAS, (char *) data*, -1);
}
It does not work because of following errors I get everytime MySQL function tryes to write the data in their fields:
(app_0:3642): GLib-GObject-WARNING **: invalid cast from `GtkScrolledWindow' to `GtkTreeView'
(app_0:3642): Gtk-CRITICAL **: IA__gtk_tree_view_get_model: assertion `GTK_IS_TREE_VIEW (tree_view)' failed
(app_0:3642): Gtk-CRITICAL **: IA__gtk_list_store_append: assertion `GTK_IS_LIST_STORE (list_store)' failed
(app_0:3642): Gtk-CRITICAL **: IA__gtk_list_store_set_valist: assertion `GTK_IS_LIST_STORE (list_store)' failed
Here is how the function of adding a row is called:
list_add_cb(list, row[i] ? row[i] : "NULL");
I will also say that when I printf the row[i] ? row[i] : "NULL" I get correct value.
The MySQL part of my application works more than fine. The only warning I get while compilation is useless class storage specifier in empty declaration which I researched and here on stackoverflow.com I have learned this has nothing to do with this problem.
The other difference is I'm creating mutliple lists in my application. To verify if this was the source of the problem I have deleted all the lists except one single list and this changed nothing.
I've been also trying to charge the list with input fields and a button trigger, but this hasn't change anything. I've also tryed reordering declarations of the variables with the enum this had none effect on the result neither.
I haven't found anything usefull, I'm out of ideas, please help. I've been trying to explain this as clearly as possible, please ask question and correct me and my post. Thanks.
I've found the solution. Unfortunately I don't know exactly why it solves the problem.
As user ntd said in the comment I used GtkScrolledWindow to append lists, I though it's ok because it was this way in the example, but in the example there were secondary variables, not global in the main function which I didn't noticed. So thank you ntd for your point.
Second thing came of using multiple lists. The function static GtkWidget *setup_list(char *typ) had to be doubled. The funny thing was that I couldn't pass the gtktreeview object in the argument of this function, but once I've created two functions setup_list(char *typ) and setup_list2(char *typ) where the only difference was a variable used for storing gtktreeview.
I don't really know why it does work this way, I'll be happy to learn if someone has an idea. I'm happy anyway because my project can go further now. Cheers people!

What's the GTK header I need to include so I can use lookup_widget?

As shown in the example below, this callback function is when the user clicks an OK button. I can get window (the top level widget) from button by using gtk_widget_get_toplevel, but I'm stuck trying to get a widget pointer for a GtkEntry widget with name ENTRY.
/* Called when OK button is clicked */
on_BT_OK_clicked(GtkButton *button, gpointer user_data)
{
//The line directly below is the one I get an error on
GtkWidget *entry = lookup_widget( GTK_WIDGET(button), "ENTRY" );
gchar *text1, *text2;
text1 = gtk_entry_get_text( GTK_ENTRY(entry));
text2 = g_strconcat("Hello, ", text1, NULL);
GtkWidget *window = gtk_widget_get_toplevel (GTK_WIDGET(button));
GtkWidget *dialog = gtk_message_dialog_new( window,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_CLOSE,
text2);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
But I get the error "undefined reference to lookup_widget." I can find a billion examples of snippets of code using lookup_widget, but not a single one full source code example showing the headers that enable the use of it. I'm using Anjuta3.2.0 and the latest Glade plugin.
As Basile Starynkevitch says, lookup_widget() was a function generated by Glade 2. However, code generation by Glade has been deprecated for quite a long time now, in favor of (first) libglade and (later) GtkBuilder. In fact, Glade 3 won't even do it.
The preferred solution is to pass a pointer to your ENTRY as the user data pointer when you connect the signal, or, if you're using gtk_builder_connect_signals(), store a pointer to ENTRY in your class and pass the class as the user data pointer.
However, if you must use lookup_widget(), here's the source that Glade 2 generated as of about 6 years ago:
GtkWidget*
lookup_widget (GtkWidget *widget,
const gchar *widget_name)
{
GtkWidget *parent, *found_widget;
for (;;)
{
if (GTK_IS_MENU (widget))
parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
else
parent = widget->parent;
if (!parent)
parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
if (parent == NULL)
break;
widget = parent;
}
found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
widget_name);
if (!found_widget)
g_warning ("Widget not found: %s", widget_name);
return found_widget;
}
For this to work, you have to do the following for every widget contained within a toplevel window:
g_object_set_data_full (G_OBJECT (toplevel), "name-of-widget", gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref);
and then the following once for each toplevel window:
g_object_set_data (G_OBJECT (toplevel), "name-of-toplevel", toplevel);
Seems to me to be more trouble than it's worth.
Glade-2 implements lookup_widget() in support.c and the header is support.h
Once the GLADE GUI is converted to C codes these files are generated automatically.

Resources