0

I'm creating a small program with C++ and GTK 3 (just learning it), and i have had trouble with this. So, i isolated the problematic part.

It is suposed to get the entry and print it when the button is clicked.

This is the code:

#include <iostream>
#include <gtk/gtk.h>

using namespace std;

GtkWidget *wventana;
GtkWidget *wgrid;

//FUNCS

void ventana(string titulo, int margen)
{
    const char * tituloc = titulo.c_str();

    wventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position (GTK_WINDOW (wventana), GTK_WIN_POS_CENTER);
    gtk_window_set_title (GTK_WINDOW (wventana), tituloc);
    gtk_container_set_border_width(GTK_CONTAINER(wventana), margen);
}

void grid()
{
    wgrid = gtk_grid_new();
    gtk_container_add(GTK_CONTAINER(wventana), wgrid);
    gtk_grid_set_row_spacing (GTK_GRID (wgrid), 10);
    gtk_grid_set_column_spacing (GTK_GRID (wgrid), 25);
}

void boton_clic (GtkEntry *wentrada, gpointer user_data)
{
    const char *nombre;
    nombre = gtk_entry_get_text(wentrada);
    cout << nombre << endl;
}

void entrada(int x, int y, int lx, int ly)
{
    GtkWidget *wentrada;
    wentrada = gtk_entry_new();
    gtk_grid_attach (GTK_GRID (wgrid), wentrada, x, y, lx, ly);
}

void boton(string texto, int x, int y, int lx, int ly)
{
    const char * wtexto = texto.c_str();

    GtkWidget *wboton;
    wboton = gtk_button_new_with_label (wtexto);
    gtk_grid_attach (GTK_GRID (wgrid), wboton, x, y, lx, ly);

    g_signal_connect (GTK_BUTTON (wboton), "clicked", G_CALLBACK (boton_clic), G_OBJECT     (wventana));
}

//MAIN

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

    ventana("ventana",10);
    grid();
    entrada(1, 1, 1, 1);
    boton("Aprietame", 1, 2, 1, 1);

    gtk_widget_show_all (wventana);
    gtk_main ();

    return 0;
}

It doesnt get the entry and shows the following error message:

(boton:6669): Gtk-CRITICAL **: gtk_entry_get_text: assertion 'GTK_IS_ENTRY (entry)' failed

Could anyone please tell what the problem is? and, how can I make it work? Or in any case, what is a good alternative to do this? (it has to be with separated functions)

Thanks in advance.


Thanks for your answer @ptomato, I tried replacing with the changes you proposed, been the new code:

#include <iostream>
#include <gtk/gtk.h>

using namespace std;

GtkWidget *wventana;
GtkWidget *wgrid;

//FUNCS

void ventana(string titulo, int margen)
{
    const char * tituloc = titulo.c_str();

    wventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position (GTK_WINDOW (wventana), GTK_WIN_POS_CENTER);
    gtk_window_set_title (GTK_WINDOW (wventana), tituloc);
    gtk_container_set_border_width(GTK_CONTAINER(wventana), margen);
}

void grid()
{
    wgrid = gtk_grid_new();
    gtk_container_add(GTK_CONTAINER(wventana), wgrid);
    gtk_grid_set_row_spacing (GTK_GRID (wgrid), 10);
    gtk_grid_set_column_spacing (GTK_GRID (wgrid), 25);
}

void boton_clic (GtkButton *wboton, GtkEntry *wentrada)
{
    const char *nombre;
    nombre = gtk_entry_get_text (wentrada);
    cout << nombre << endl;
}

void entrada(int x, int y, int lx, int ly)
{
    GtkWidget *wentrada;
    wentrada = gtk_entry_new();
    gtk_grid_attach (GTK_GRID (wgrid), wentrada, x, y, lx, ly);
}

void boton(string texto, int x, int y, int lx, int ly)
{
    const char * wtexto = texto.c_str();

    GtkWidget *wboton;
    wboton = gtk_button_new_with_label (wtexto);
    gtk_grid_attach (GTK_GRID (wgrid), wboton, x, y, lx, ly);

    g_signal_connect (wboton, "clicked", G_CALLBACK (boton_clic), wentrada);
}

//MAIN

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

    ventana("ventana",10);
    grid();
    entrada(1, 1, 1, 1);
    boton("Aprietame", 1, 2, 1, 1);

    gtk_widget_show_all (wventana);
    gtk_main ();

    return 0;
}

but when i try to compile it, it shows:

In file included from /usr/include/glib-2.0/gobject/gobject.h:28:0,
                 from /usr/include/glib-2.0/gobject/gbinding.h:29,
                 from /usr/include/glib-2.0/glib-object.h:23,
                 from /usr/include/glib-2.0/gio/gioenums.h:28,
                 from /usr/include/glib-2.0/gio/giotypes.h:28,
                 from /usr/include/glib-2.0/gio/gio.h:26,
                 from /usr/include/gtk-3.0/gdk/gdkapplaunchcontext.h:28,
                 from /usr/include/gtk-3.0/gdk/gdk.h:32,
                 from /usr/include/gtk-3.0/gtk/gtk.h:30,
                 from boton.cpp:2:
boton.cpp: In function ‘void boton(std::string, int, int, int, int)’:
boton.cpp:51:64: error: ‘wentrada’ was not declared in this scope
  g_signal_connect (wboton, "clicked", G_CALLBACK (boton_clic), wentrada);
                                                                ^
/usr/include/glib-2.0/gobject/gsignal.h:472:73: note: in definition of macro     ‘g_signal_connect’
     g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL,     (GConnectFlags) 0)
                                                                             ^
 Compilation failed.

What is wrong? What should I do???

Could you please explain again about the second argument? (english is not my mother language and this part was a little confusing for me :P )

Thanks again.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Ffff
  • 73
  • 1
  • 3
  • 14
  • 1
    You should declare it global, like you did with `wventada` and `wgrid`, in the begin of the code: `GtkWidget *wentrada;`. Actually, this is not the best solution. Better if you create classes, and not use global variables. But for this example, that is the solution that fits the rest of the code. – DrBeco Jun 18 '18 at 16:27

1 Answers1

2

The boton_clic signal handler has two arguments: a GtkWidget * and a pointer to some user data that you specify. The first argument is always the object that sent the signal, so that is wboton; but you labeled the argument wentrada and are treating it as a GtkEntry *, hence the error message.

The second argument is the user data that you specify when connecting the signal. In your g_signal_connect() call, you pass wventana here. But if you want to access the entry in your signal handler, you should pass wentrada instead.

So, it should look like this:

void boton_clic (GtkButton *wboton, GtkEntry *wentrada)
{
    const char *nombre;
    nombre = gtk_entry_get_text (wentrada);
    cout << nombre << endl;
}

...

g_signal_connect (wboton, "clicked", G_CALLBACK (boton_clic), wentrada);
ptomato
  • 56,175
  • 13
  • 112
  • 165