IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

GTK+ Discussion :

Envoi d'une adresse de structure à une fonction callback


Sujet :

GTK+

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juillet 2013
    Messages
    74
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juillet 2013
    Messages : 74
    Points : 53
    Points
    53
    Par défaut Envoi d'une adresse de structure à une fonction callback
    Bonjour tout le monde :
    J'ai besoin d'envoyer plusieurs argument à travers la fonction callback, c'est ainsi que j'ai pensé de faire un test pour vérifier cette manipulation.
    J'ai fait ce programme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #include <stdio.h>
    #include <gtk/gtk.h>
    typedef struct dat dat;
    struct dat 
    {
    		int i;
    		int j;
    };
    void func_callback (dat *number)
    {
    		printf ("%d %d\n", number->i, number->j);
    }
    void func_normal (dat *number)
    {
    		printf ("%d %d\n", number->i, number->j);
    }
    int main (int argc, char **argv)
    {
    		GtkWidget *window;
    		GtkWidget *button;
    		dat data;
    		gtk_init (&argc, &argv);
    		window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    		gtk_window_set_title (GTK_WINDOW(window), "struct_test");
    		gtk_window_set_default_size (GTK_WINDOW(window), 700, 700);
    		button = gtk_button_new_with_label ("button");
    		data.i = 10;
    		data.j = 20;
    		func_normal (&data);
    		g_signal_connect (G_OBJECT(button), "clicked", G_CALLBACK(func_callback), &data);
    		gtk_container_add (GTK_CONTAINER(window), button);
    		gtk_widget_show_all (window);
    		gtk_main();
    		return 0;
    }
    dans le terminal je vois des résultats différents, la fonction callback reçoit le pointeur de structure d'une manière différente qu'une autre fonction normale !
    la fonction normale donne le résultat attendu, 10 et 20, alors que la première fonction donne des nombres aléatoires.
    Pourquoi ?
    Quelle est la solution pour envoyer plusieurs argument à une fonction callback ?
    Merci pour votre réponse.
    Merci pour votre temps que vous avez accordé à mon sujet.

  2. #2
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2009
    Messages
    1 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 395
    Points : 2 002
    Points
    2 002
    Par défaut
    Bonjour,

    le problème vient du fait que tu ne respectes pas la signature de la callback.
    Regarde la documentation: chaque signal a une signature bien particulière. La signature d'une fonction, ce sont les paramètres d'entrée et de sortie. Pour le signal GtkButton::clicked, la signature est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void user_function (GtkButton *button, gpointer user_data)
    Or, tu as défini ta callback ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void func_callback (dat *number)
    Ce que tu reçois dans number est donc en fait le pointeur vers le widget boutton sur lequel tu as cliqué. Le pointeur vers ta structure de donnée est lui dans le gpointer user_data. Un gpointeur est juste un void *, c'est à dire un pointeur vers un objet dont on ne connaît pas le type.

    Respecte donc cette règle de base: lis la documentation du signal auquel tu te connectes pour savoir comment GTK+ va appeler ta fonction. Vous devez respecter les mêmes conventions, c'est à dire les mêmes nombres et type de paramètres d'entrée et de sortie.

    Il te faut donc écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void func_callback (GtkButton *button, gpointer user_data)
    {
       dat *number = user_data;
       printf ("%d %d\n", number->i, number->j);
    }
    Pour ce qui est de passer plusieurs arguments, tu as effectivement trouvé la solution tout seul, il suffit de les regrouper dans une structure.
    Documentation officielle GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels par l'exemple (platform-demos):
    GTK (tous langages)

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 5
    Points : 6
    Points
    6
    Par défaut Même genre de problème.
    Bonjour,
    Je me permets de remonter ce post car je suis confronté un peu au même genre de problème.
    J'ai fait un petit programme pour tester l'ouverture d'une gtk_dialog_with_buttons à partir du menu.

    J'ai donc un petit programme qui commence comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <gtk/gtk.h>
    #include <libpq-fe.h>
     
    #include "startup.h"
    #include "vuebase.h"
    #include "bdadm.h"
     
    int main (int argc, char *argv[])
    {
        GtkApplication *appli;
        int statut;
        PGconn *conn = NULL;
     
        appli = gtk_application_new("prog.BD.Test", G_APPLICATION_FLAGS_NONE);
        g_signal_connect(appli, "startup", G_CALLBACK(startup), &conn);
        g_signal_connect(appli, "activate", G_CALLBACK(cb_vuebase), &conn);
        /*g_signal_connect(appli, "shutdown", G_CALLBACK(deconnexiondb), &conn);*/
        statut = g_application_run(G_APPLICATION(appli), argc, argv);
        g_object_unref(appli);
     
        return statut;
    }
    Ma fonction cb_vuebase est standard et ne fait pas grand chose si ce n'est mettre en place les Widget.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
     
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <gtk/gtk.h>
     
    #include "vuebase.h"
    #include "MenuTool.h"
    #include "BDadm.h"
     
    void cb_vuebase(GtkApplication *appli, gpointer *data)
    {
        GtkWidget *fenetrebase = NULL;
    	GtkWidget *conteneur = NULL;
    	GtkWidget *etiquette = NULL;
     
    	printf("Connexion vuebase : %p\n", *data);
     
        /* Création de la fenetre avec un conteneur vertical */
        fenetrebase = gtk_application_window_new(appli);
        gtk_window_set_title(GTK_WINDOW(fenetrebase), "Test signal");
        gtk_window_set_position(GTK_WINDOW(fenetrebase), GTK_WIN_POS_CENTER_ALWAYS);
        gtk_window_maximize(GTK_WINDOW(fenetrebase));
        conteneur = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
        gtk_container_add(GTK_CONTAINER(fenetrebase), conteneur);
     
    	/* Mise en place de la headerbar */
    	gtk_box_pack_start(GTK_BOX(conteneur), GTK_WIDGET(titre()), FALSE, FALSE, 0);
    	printf("Header bar ok.\n");
     
    	/* Mise en place du menu */
    	gtk_box_pack_start(GTK_BOX(conteneur), GTK_WIDGET(menu(fenetrebase, *data)), FALSE, FALSE, 0);
    	printf("Menu ok.\n");
     
    	/* Un label dans la fenêtre */
    	etiquette = gtk_label_new("Coucou");
        gtk_box_pack_start(GTK_BOX(conteneur), etiquette, TRUE, TRUE, 5);
     
        gtk_widget_show_all(fenetrebase);
        (void)data;
    }
     
    GtkHeaderBar *titre(void)
    {
    	GtkWidget *titreappli = NULL;
     
    	titreappli = gtk_header_bar_new();
    	gtk_header_bar_set_title(GTK_HEADER_BAR(titreappli), "Test signal");
    	gtk_header_bar_set_subtitle(GTK_HEADER_BAR(titreappli), "Petit programme pour explorer g_signal");
    	gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(titreappli), TRUE);
    	return GTK_HEADER_BAR(titreappli);
    }
     
    void activate_quitter(GSimpleAction *simple, GVariant *parametre, gpointer data)
    {
      GApplication *application = data;
     
      g_application_quit(application);
      (void)simple;
      (void)parametre;
    }
    Ma fonction menu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    #include <gtk/gtk.h>
    #include "vuebase.h"
    #include "MenuTool.h"
    #include "bdadm.h"
     
    GtkMenuBar *menu(GtkWidget *fenetre, const PGconn *data)
    {
    	GtkWidget *menuappli = NULL;
    	GMenu *menumodel = NULL;
    	GMenu *menufichier = NULL;
    	GMenu *menutest = NULL;
    	GSimpleAction *actiontest = NULL;
    	struct lien l;
     
    	printf("Debut du module Menu.\n");
    	printf("Initialisation de la structure lien.\n");
    	initlien(&l);
    	l.fenetreparent = fenetre;
    	l.connexion = data;
     
    	menumodel = g_menu_new();
    	/* Menu Fichier */
    	menufichier = g_menu_new();
    	g_menu_append(menufichier, "Quitter", "app.quitter");
    	g_menu_append_submenu(menumodel, "Fichier", G_MENU_MODEL(menufichier));
    	/* Menu test */
        /* Action : test */
        actiontest = g_simple_action_new("test", NULL);
        g_signal_connect(actiontest, "activate", G_CALLBACK(cb_test), (gpointer)&l);
        g_action_map_add_action(G_ACTION_MAP(fenetre), G_ACTION(actiontest));
    	menutest = g_menu_new();
    	g_menu_append(menutest, "un test", "win.test");
    	g_menu_append_submenu(menumodel, "Test", G_MENU_MODEL(menutest));
     
    	menuappli = gtk_menu_bar_new_from_model(G_MENU_MODEL(menumodel));
     
    	return GTK_MENU_BAR(menuappli);
    }
     
    void initlien (struct lien *l)
    {
    	l->fenetreparent = NULL;
    	l->connexion = NULL;
    	l->i = 2;
    }
    et enfin la fonction qui m'affiche la gtk_dialog :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
    void cb_test(GtkWidget *pwidget, gpointer data)
    {
    	GtkWidget *fenetresaisie = NULL;
    	GtkWidget *contenu = NULL;
    	GtkWidget *etiquette = NULL;
    	int resultat;
    	GtkDialogFlags flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT;
    	struct lien *lientest = NULL;
    	struct saisieessai *saisiee = (struct saisieessai*)malloc(sizeof(struct saisieessai));
     
    	lientest = malloc(sizeof(struct lien));
    	lientest = (struct lien *)data;
     
    	printf("fonction cb_test.\n");
    	printf("i = %d\n", lientest->i);
    	printf("ok pour lecture de lientest.\n");
     
    	/* Initialisation de la structure saisieessai */
    	initsaisieessai(saisiee);
     
    	/* Mise en place de la fenetre de saisie */
    	fenetresaisie = gtk_dialog_new_with_buttons ("Fenetre de saisie", GTK_WINDOW(lientest->fenetreparent), flags, "_Valider", 1, "_Annuler", 2, NULL);
    	gtk_window_set_transient_for(GTK_WINDOW(fenetresaisie), GTK_WINDOW(lientest->fenetreparent));
    	contenu = gtk_dialog_get_content_area(GTK_DIALOG(fenetresaisie));
    	gtk_container_add(GTK_CONTAINER(contenu), etiquette);
     
        gtk_widget_show_all(fenetresaisie);
     
        resultat = gtk_dialog_run(GTK_DIALOG(fenetresaisie));
    	switch (resultat)
    	{
    		case 1:
    			printf("Ok\n");
    			valider(saisiee);
    		break;
    		case 2:
    		break;
    		default:
    			printf("Defaut\n");
    		break;
    	}
    	free(saisiee);
    	gtk_widget_destroy(fenetresaisie);
     
    	(void)pwidget;
    }
    J'ai une erreur de segmentation (core dump) dès que je veux lire ce que contient lientest.
    J'ai lu un peu le forum qui est très dense. J'ai regardé sur internet. Je n'arrive à rien.
    En premier lieu j'avais un warning dereferencing 'void *' pointer. J'ai corrigé (enfin je crois avoir compris que le gpointer est en fait un void *).
    Mais à chaque fois que je tente d’accéder à lientest, j'ai cette erreur de segmentation.
    J'ai besoin de cette structure lien pour transmettre la fenêtre parent au gtk_dialog mais aussi je voudrais passer un pointeur de connexion à une base de donnée (je voudrais que le gtk_dialog me donne les infos sur la base de données : propriétaire, etc ...
    Quelqu'un a t-il une idée ?
    Merci du temps que vous voudrez bien me consacrer.

  4. #4
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2009
    Messages
    1 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 395
    Points : 2 002
    Points
    2 002
    Par défaut
    Bonjour,

    en cas d'erreur de segmentation, le premier réflexe c'est de prendre un débogueur et voir ce que tu as dans tes variables.
    Ensuite, mettre un gros paté de code pour qu'on se débrouille avec, c'est pas super. Je te conseille de prendre l'habitude de simplifier tes exemples en retirant tout ce qui n'a pas de rapport. C'est plus facile à lire et si d'un coup ça se met à fonctionner c'est que tu es passé à côté de quelque chose.

    Là en l'occurence tu mets plein de choses, mais pas l'appel à g_signal_connect où tu connectes la callbcack cb_test à un signal (lequel ?). Dans ces conditions, impossible de savoir ce que contient la variable data. Si elle contient n'importe quoi, alors effectivement tu auras une erreur de segmentation.
    Documentation officielle GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels par l'exemple (platform-demos):
    GTK (tous langages)

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 5
    Points : 6
    Points
    6
    Par défaut
    Bonjour,
    Merci pour cette réponse. Je vais faire comme tu dis.
    Bonne journée.

Discussions similaires

  1. Port fowarding depuis une adresse publique vers une adresse privée
    Par MrPchoun dans le forum Shell et commandes POSIX
    Réponses: 4
    Dernier message: 04/03/2017, 15h19
  2. Accéder à une adresse contenu dans une adresse
    Par Qooort dans le forum x86 32-bits / 64-bits
    Réponses: 4
    Dernier message: 22/06/2013, 00h33
  3. Réponses: 7
    Dernier message: 06/05/2009, 12h05
  4. Réponses: 18
    Dernier message: 26/06/2008, 10h10
  5. copie d'une table Y d'une base A vers une table X d'une base
    Par moneyboss dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 30/08/2005, 21h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo