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+ avec C & C++ Discussion :

Changer la couleur d'une image via un appui sur un bouton


Sujet :

GTK+ avec C & C++

  1. #1
    Candidat au Club
    Homme Profil pro
    Etudiant
    Inscrit en
    Août 2019
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Etudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2019
    Messages : 5
    Points : 3
    Points
    3
    Par défaut Changer la couleur d'une image via un appui sur un bouton
    Bonjour,

    Je débute avec glade et gtk+, je dois écrire un programme en langage C qui passe une image en rouge après un clic sur un bouton.
    Dans mon projet glade, j'ai associé le signal cliked de mon bouton "rouge" avec la fonction "on_click_button_red"
    Mon image originale s'affiche correctement, un clic sur le bouton m'aiguille bien sur la fonction se trouvant dans le callback.c mais l'image ne passe jamais en rouge.

    D'où mon impression que le problème vient du non rafraichissement de l'image.

    Mon code "main.c" est :

    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
     
    int main(int argc, char *argv[]) {
    	GtkWidget *window1 = NULL;
    	GtkBuilder *builder = NULL;
    	GtkImage *image1;
    	GdkPixbuf *gdk_pixbuf = NULL;
     
    	gtk_init(&argc, &argv);
     
    	builder = gtk_builder_new();
    	if (gtk_builder_add_from_file(builder, "projet.glade", NULL) == 0) {
    		fprintf(stderr, "Erreur ouverture fichier GLADE\n");
    		exit(EXIT_FAILURE);
    	}
     
    	window1 = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
    	gtk_window_set_default_size(GTK_WINDOW(window1), 1920, 1080);
     
    	image1 = GTK_IMAGE(gtk_builder_get_object(builder, "image1"));
    	gdk_pixbuf = gdk_pixbuf_new_from_file("image.png", NULL);
     
    	gtk_builder_connect_signals(builder, NULL);
     
    	gtk_image_set_from_pixbuf(image1, gdk_pixbuf);
    	gtk_widget_queue_draw(GTK_WIDGET(image1));
     
    	gtk_widget_show_all(window1);
     
    	gtk_main();
     
    	g_object_unref(G_OBJECT(builder));
     
    	return 0;
    	}
    Dans mon programme "callbacks.c" j'ai les fonctions:

    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
     
    void on_click_button_red(GtkButton *button, gpointer user_data){
    	GtkBuilder *builder = NULL;
    	GdkPixbuf *gdk_pixbuf = NULL;
    	GtkImage *image1=NULL;
    	GtkWidget *window1 = NULL;
     
    	int w,h,x,y = 0;
    	guchar *r = 0;
    	guchar *g = 0;
    	guchar *b = 0;
     
    	if (gtk_builder_add_from_file(builder, "projet.glade", NULL) == 0) {};
     
    	window1 = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
    	image1 = GTK_IMAGE(gtk_builder_get_object(builder, "image1"));
     
    	gdk_pixbuf = gdk_pixbuf_new_from_file("image.png", NULL);
    	w = gdk_pixbuf_get_width(gdk_pixbuf);
    	h = gdk_pixbuf_get_height(gdk_pixbuf);
     
    	for (x = 0; x <= w; x++) {
    		for (y=0; y <= h; y++) {
    			/* passage en rouge*/
    			gdkpixbuf_set_pixel_color(gdk_pixbuf, x, y, 255, 0, 0);
    		}
    	}
     
    	image1 = GTK_IMAGE(gtk_image_new_from_pixbuf(gdk_pixbuf));
    	gtk_image_set_from_pixbuf(image1, gdk_pixbuf);
     
    	gtk_widget_queue_draw(GTK_WIDGET(image1));
    	gtk_widget_show_all(window1);
     
    }
     
     
    gboolean gdkpixbuf_set_pixel_color(GdkPixbuf *pixbuf, gint x, gint y, guchar red, guchar green, guchar blue) {
    	...........
    }
    Merci d'avance pour vos retours.

  2. #2
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 296
    Points : 4 949
    Points
    4 949
    Billets dans le blog
    5
    Par défaut
    Bonsoir.

    Première petite remarque. Libère gdk_pixbuf dans le main (); une fois affecté dans image1.

    Ensuite pour ta question ton souci vient du GtkBuilder que tu initialises dans on_click_button_red ();. Tu ne dois pas faire comme ça. Le builder va pointer sur de nouveaux widgets et non ceux utilisés dans la fenêtre affichée.

    Tu dois passer en paramètre le GtkBuilder initialisé dans le main (); à ton callback.

  3. #3
    Candidat au Club
    Homme Profil pro
    Etudiant
    Inscrit en
    Août 2019
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Etudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2019
    Messages : 5
    Points : 3
    Points
    3
    Par défaut
    Merci pour ta réponse,

    J'ai modifié le main.c :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    gtk_image_set_from_pixbuf(image1, gdk_pixbuf);
    gdk_pixbuf = NULL;
    Et j'ai modifié ma fonction on_click_button_red comme ça mais l'image ne veut toujours pas passer en rouge : le queue_draw et show_all à la fin sont ils corrects selon-toi ? :

    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
     
    void on_click_button_red(GtkButton *button, GtkBuilder *builder){
    	GdkPixbuf *gdk_pixbuf = NULL;
    	GtkImage *image1 = NULL;
    	GtkWidget *window1 = NULL;
     
    	int w,h,x,y = 0;
    	guchar *r = 0;
    	guchar *g = 0;
    	guchar *b = 0;
     
    	if (gtk_builder_add_from_file(builder, "projet.glade", NULL) == 0) {};
     
    	window1 = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
    	image1 = GTK_IMAGE(gtk_builder_get_object(builder, "image1"));
     
    	gdk_pixbuf = gdk_pixbuf_new_from_file("image.png", NULL);
    	w = gdk_pixbuf_get_width(gdk_pixbuf);
    	h = gdk_pixbuf_get_height(gdk_pixbuf);
     
    	for (x = 0; x <= w; x++) {
    		for (y=0; y <= h; y++) {
    			/* passage en rouge*/
    			gdkpixbuf_set_pixel_color(gdk_pixbuf, x, y, 255, 0, 0);
    		}
    	}
     
    	image1 = GTK_IMAGE(gtk_image_new_from_pixbuf(gdk_pixbuf));
    	gtk_image_set_from_pixbuf(image1, gdk_pixbuf);
     
    	gtk_widget_queue_draw(GTK_WIDGET(image1));
    	gtk_widget_show_all(window1);
     
    }
     
     
    gboolean gdkpixbuf_set_pixel_color(GdkPixbuf *pixbuf, gint x, gint y, guchar red, guchar green, guchar blue) {
    	...........
    }
    Merci !

  4. #4
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 296
    Points : 4 949
    Points
    4 949
    Billets dans le blog
    5
    Par défaut
    gdk_pixbuf = null; ne libère rien. Il faut utiliser g_object_unref (gdk_pixbuf);.

    Pour la transmission du GtkBuilder il te faut utiliser la fonction gtk_builder_connect_signal (); dans le main ();.

  5. #5
    Candidat au Club
    Homme Profil pro
    Etudiant
    Inscrit en
    Août 2019
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Etudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2019
    Messages : 5
    Points : 3
    Points
    3
    Par défaut Pb raffraichir image
    Bonsoir, désolé je reprends le sujet maintenant :
    Merci pour la réponse.
    oui, j'ai mis gtk_builder_connect_signals (builder, NULL); dans le main()

    Mais dès que je passe dans la fonction, je n'arrive pas à afficher l'image en rouge. Pourtant le code de "passage en rouge" de l'image est bon car quand je le mets en direct dans le main() : l'image s'affiche en rouge.

    Dans la fonction du bouton, pour rafraîchir j'ai mis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    gtk_widget_queue_draw(GTK_WIDGET(image1));
    gtk_widget_show_all(GTK_WIDGET(window1));
    qu'en pensez-vous ?

    Merci pour votre aide

  6. #6
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 296
    Points : 4 949
    Points
    4 949
    Billets dans le blog
    5
    Par défaut
    Bonjour.

    Il est important de consulter la documentation des fonctions que tu utilises. gtk_builder_connect_signals (); attend un paramètre à transmettre. Tu lui transmets la valeur NULL ! comment veux-tu alors récupérer le GtkBuilder tant désiré ?

    Petite aparté.
    Pour consulter la documentation tu peux bien entendu aller sur le site officiel de Gtk. Mais comme il semble que tu sois sous linux je te propose d'installer devhelp. Cette application va regrouper toutes les documentations compatibles installées sur ta machine. Bien plus pratique à mon goût .

    Revenons à nous moutons. Donc la documentation de la fonction gtk_builder_connect_signals (); dit ceci :
    This method is a simpler variation of gtk_builder_connect_signals_full(). It uses symbols explicitly added to builder with prior calls to gtk_builder_add_callback_symbol(). In the case that symbols are not explicitly added; it uses GModule’s introspective features (by opening the module NULL) to look at the application’s symbol table. From here it tries to match the signal handler names given in the interface description with symbols in the application and connects the signals. Note that this function can only be called once, subsequent calls will do nothing.
    Pour pouvoir l'utiliser correctement sous Windows et/ou linux il faut ajouter/modifier les instructions de compilation :
    When compiling applications for Windows, you must declare signal callbacks with G_MODULE_EXPORT, or they will not be put in the symbol table. On Linux and Unices, this is not necessary; applications should instead be compiled with the -Wl,--export-dynamic CFLAGS, and linked against gmodule-export-2.0.
    Pour ce qui est de ton code, tu trouveras juste en dessous certaines modifications en bleue et les suppressions en rouge.
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    #include <stdlib.h>
    #include <gtk/gtk.h>
    
    void on_click_button_red(GtkButton *button, gpointer user_data);
    gboolean gdkpixbuf_set_pixel_color(GdkPixbuf *pixbuf, gint x, gint y, guchar red, guchar green, guchar blue);
     
    void
    on_click_button_red(GtkButton *button, gpointer user_data){
      GtkBuilder *builder = NULL;
      GtkBuilder *builder = (GtkBuilder*)user_data;
      GdkPixbuf *gdk_pixbuf = NULL;
      GtkImage *image1=NULL;
      GtkWidget *window1 = NULL;
     
      int w,h,x,y = 0;
      guchar *r = 0;
      guchar *g = 0;
      guchar *b = 0;
     
      if (gtk_builder_add_from_file(builder, "projet.glade", NULL) == 0) {};
     
      window1 = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
      image1 = GTK_IMAGE(gtk_builder_get_object(builder, "image1"));
    
      gdk_pixbuf = gdk_pixbuf_new_from_file("image.png", NULL);
      w = gdk_pixbuf_get_width(gdk_pixbuf);
      h = gdk_pixbuf_get_height(gdk_pixbuf);
    
      for (x = 0; x <= w; x++) {
        for (y=0; y <= h; y++) {
          /* passage en rouge*/
          gdkpixbuf_set_pixel_color(gdk_pixbuf, x, y, 255, 0, 0);
        }
      }
    
      /* Ici tu écrases le pointeur image1 de ta fenêtre principale par un nouveau pointeur qui ne sera donc pas affiché. Ligne à supprimer. */
      image1 = GTK_IMAGE(gtk_image_new_from_pixbuf(gdk_pixbuf));
      gtk_image_set_from_pixbuf(image1, gdk_pixbuf);
      g_object_unref (gdk_pixbuf);
     
      gtk_widget_queue_draw(GTK_WIDGET(image1));
      gtk_widget_show_all(window1);
     
    }
     
     
    gboolean
    gdkpixbuf_set_pixel_color(GdkPixbuf *pixbuf, gint x, gint y, guchar red, guchar green, guchar blue) {
    
      return TRUE;
    }
    
    int
    main(int argc, char *argv[]) {
      GtkWidget *window1 = NULL;
      GtkBuilder *builder = NULL;
      GtkImage *image1;
      GdkPixbuf *gdk_pixbuf = NULL;
     
      gtk_init(&argc, &argv);
     
      builder = gtk_builder_new();
      if (gtk_builder_add_from_file(builder, "projet.glade", NULL) == 0) {
        fprintf(stderr, "Erreur ouverture fichier GLADE\n");
        exit(EXIT_FAILURE);
      }
     
      window1 = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
      gtk_window_set_default_size(GTK_WINDOW(window1), 1920, 1080);
     
      image1 = GTK_IMAGE(gtk_builder_get_object(builder, "image1"));
      gdk_pixbuf = gdk_pixbuf_new_from_file("image.png", NULL);
     
      gtk_builder_connect_signals(builder, builder);
     
      gtk_image_set_from_pixbuf(image1, gdk_pixbuf);
      gtk_widget_queue_draw(GTK_WIDGET(image1));
      g_object_unref (gdk_pixbuf);
     
      gtk_widget_show_all(window1);
     
      gtk_main();
     
      g_object_unref(G_OBJECT(builder));
     
      return 0;
    }
    Amélioration du code


    Comme tu charges à chaque fois ton image depuis le disque, il y a une perte de performance en terme de temps d’exécution. L'idéal serait de ne la charger qu'une seule fois. Pour se faire, on va utiliser une structure dans laquelle on va naturellement trouver ton GdkPixbuf mais aussi le GtkBuilder de ta fenêtre principale.

    Quel est l'intéret ?
    Comme nous devons transmettre à la fonction callback le GtkBuilder mais aussi cette fois-çi le GdkPixbuf utiliser cette nouvelle structure va nous le peux permettre.

    Je vais donc déclarer cette structure comme suit. Tu pourras bien entendu lui donner le nom que tu veux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    typedef struct {
      GtkBuilder *builder;
      GdkPixbuf *gdk_pixbuf;
    } SData;
    Dans le main (); je vais déclarer une variable du type SData que je vais initialiser comme il faut. J'utilise ensuite cette variable tout au long de la fonction main ();. J'ai nettoyé le code par rapport aux remarques précédentes pour plus de clarté.
    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
    int
    main(int argc, char *argv[]) {
      GtkWidget *window1 = NULL;
      GtkBuilder *builder = NULL;
      GtkImage *image1;
      GdkPixbuf *gdk_pixbuf = NULL;
      SData data;
      
      /* Initialisation de Gtk */
      gtk_init(&argc, &argv);
    
      /* Tentative de chargement de l'interface principale */
      data.builder = gtk_builder_new();
      if (gtk_builder_add_from_file(data.builder, "projet.glade", NULL) == 0) {
        fprintf(stderr, "Erreur ouverture fichier GLADE\n");
        exit(EXIT_FAILURE);
      }
    
      /* Tentative de chargement de l'image */
      data.gdk_pixbuf = gdk_pixbuf_new_from_file("image.png", NULL);
      if (!GDK_IS_PIXBUF (data.gdk_pixbuf)) {
        /* Libération mémoire du GtkBuilder précédement initialisé */
        g_object_unref(G_OBJECT(data.builder));
          
        fprintf(stderr, "Erreur chargement de image.png\n");
        exit(EXIT_FAILURE);
      }
      
      window1 = GTK_WIDGET(gtk_builder_get_object(data.builder, "window1"));
      /* Remarque :la définition de la taille peut être effectuée directement dans Glade */
      gtk_window_set_default_size(GTK_WINDOW(window1), 1920, 1080);
     
      image1 = GTK_IMAGE(gtk_builder_get_object(data.builder, "image1"));
      
      gtk_builder_connect_signals(data.builder, &data);
     
      gtk_image_set_from_pixbuf(image1, data.gdk_pixbuf);
      g_object_unref (gdk_pixbuf);
     
      gtk_widget_show_all(window1);
     
      gtk_main();
    
      /* Libération des données de la structure avant de quitter */
      g_object_unref(G_OBJECT(data.builder));
      g_object_unref (data.gdk_pixbuf);
     
      return 0;
    }
    Tu remarqueras tout d'abord que j'ai un peu modifié le code pour le chargement de l'image. Je vérifie aussi si elle est bien chargée. Ca peut aider...
    Ensuite, ligne 35 je transmets non plus builder comme paramètre à notre callback mais l'adresse de la variable data de type SData. Ainsi je vais pouvoir recuperer tout ce petit monde dans mon callback .

    Justement il nous reste à transformer ce fâmeux callback.
    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
    void
    on_click_button_red(GtkButton *button, gpointer user_data){
      GtkBuilder *builder = (GtkBuilder*)user_data;
      SData *data = (SData*)user_data;
      GdkPixbuf *gdk_pixbuf = NULL;
      GtkImage *image1=NULL;
      GtkWidget *window1 = NULL;
     
      int w,h,x,y = 0;
      guchar *r = 0;
      guchar *g = 0;
      guchar *b = 0;
     
      window1 = GTK_WIDGET(gtk_builder_get_object(data->builder, "window1"));
      image1 = GTK_IMAGE(gtk_builder_get_object(data->builder, "image1"));
    
      gdk_pixbuf = gdk_pixbuf_new_from_file("image.png", NULL);
      w = gdk_pixbuf_get_width(data->gdk_pixbuf);
      h = gdk_pixbuf_get_height(data->gdk_pixbuf);
    
      for (x = 0; x <= w; x++) {
        for (y=0; y <= h; y++) {
          /* passage en rouge*/
          gdkpixbuf_set_pixel_color(data->gdk_pixbuf, x, y, 255, 0, 0);
        }
      }
    
      gtk_image_set_from_pixbuf(image1, data->gdk_pixbuf);
      g_object_unref (gdk_pixbuf);
     
      gtk_widget_show_all(window1);
    }
    J'arrête ici mes élucubrations . J'espère t'avoir apporté des eclaircicements et ne pas t'avoir trop embrouillé avec "mes améliorations" .

  7. #7
    Candidat au Club
    Homme Profil pro
    Etudiant
    Inscrit en
    Août 2019
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Etudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2019
    Messages : 5
    Points : 3
    Points
    3
    Par défaut
    Merci beaucoup, ça fonctionne !

    Bonne soirée à toi

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Changer les couleurs d'une image
    Par Bouki dans le forum Multimédia
    Réponses: 0
    Dernier message: 04/03/2011, 09h51
  2. Réponses: 7
    Dernier message: 30/06/2010, 16h56
  3. Changer différentes couleurs dans une image
    Par cashmoney dans le forum Flex
    Réponses: 13
    Dernier message: 08/10/2009, 18h06
  4. [serieux] Changer les couleurs d'une image
    Par TabrisLeFol dans le forum La taverne du Club : Humour et divers
    Réponses: 5
    Dernier message: 14/12/2006, 13h27
  5. Réponses: 2
    Dernier message: 04/04/2006, 17h03

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