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 :

Recharger une image


Sujet :

GTK+ avec C & C++

  1. #1
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2003
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2003
    Messages : 75
    Points : 76
    Points
    76
    Par défaut Recharger une image
    Bonjour,

    Je souhaite charger une image à partir d'un menu, il y aura donc plusieurs appels à gtk_image_new_from_file(nom_fichier);

    Que faut-il faire pour réafficher le GtkImage utilisé?

    J'ai essayé avec gtk_widget_show(image); ou ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        GdkWindow *f = gtk_widget_get_window(fenetre); 
        gdk_window_invalidate_rect(f, NULL, TRUE);
        gdk_window_process_updates(f, TRUE);
    où fenetre est ma fenêtre toplevel, ca ne marche pas(il laisse la première image chargée).

  2. #2
    Membre du Club Avatar de diesel83
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2014
    Messages
    57
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Décembre 2014
    Messages : 57
    Points : 51
    Points
    51
    Par défaut
    Bonsoir,

    Est-ce qu'un gtk_widget_queue_draw (ton_widget); ne résoudrait pas ton problème ?

    Jean-Marie
    Je déteste qu'on cherche à me faire passer pour un con, j'y arrive déjà très bien tout seul.

  3. #3
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2003
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2003
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Non ça ne change rien...


    Ca y est, j'ai trouvé la solution:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        gtk_image_clear(GTK_IMAGE(image));
        image=gtk_image_new_from_file(nom_fichier);
        gtk_layout_put(GTK_LAYOUT(conteneur), image, 50, 50);    
        gtk_widget_show_all(fenetre);

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

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

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

    Une petite remarque un peu décalée par rapport à ta problématique. Charger les images depuis le disque à chaque fois que tu veux en changer peut devenir vite pénible pour l'utilisateur final. À chaque fois il y a un appel au disque dur. Si les changements sont fréquents il vaut mieux charger une seule fois toutes les images dans des GDkPixbuf. Par la suite il te suffit de les affecter au GtkImage selon les besoins.

  5. #5
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2003
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2003
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Aïe je m’aperçois qu'il reste un problème: si je colorie des pixels dans l'image et que je charge ensuite une image plus petite, celle-ci se superpose à l'image précédente.

    Et même: si je charge une troisième image plus petite que la seconde, la première est redessinée sur la partie commune à la 2ème...

    Quelqu'un a une idée du pourquoi de ce fonctionnement?

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

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

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

    Le problème vient sûrement de l'utilisation de gtk_layout_put();.

    Je ferais de deux manières différentes :
    1. tu disposes des images au format GdkPixbuf. Tu utilises alors la fonction gtk_image_set_from_pixbuf();,
    2. les images sur ton disque dur ont toutes une taille compatible avec ton interface. J'utiliserai alors gtk_image_set_from_file();

    L'utilisation de l'une ou l'autre solution permet la mise à jour en temps réel de l'affichage. Ta solution actuelle est un "bidouillage", sans aucun sous-entendu péjoratif, pour obtenir le résultat escompté.

    Voila un petit exemple fonctionnel pour appuyer mes propos. Il suffit d'indiquer les chemins de deux images IMAGE1 et IMAGE2 sur ton disque dur pour l'essayer.

    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
    #include <stdlib.h>
    #include <gtk/gtk.h>
     
    #define IMAGE1 "./image1.jpg"
    #define IMAGE2 "./image2.jpg"
     
    void
    gc_button_change (GtkButton *button, GtkWidget *image)
    {
      static gboolean bascule = FALSE;
     
      if (bascule)
        gtk_image_set_from_file (GTK_IMAGE(image), IMAGE1);
      else
        gtk_image_set_from_file (GTK_IMAGE(image), IMAGE2);
     
      bascule = !bascule;
    }
     
    int
    main(int argc, char** argv)
    {
      GtkWidget *window = NULL;
      GtkWidget *image=NULL;
      GtkWidget *box = NULL;
      GtkWidget *button=NULL;
     
      // Initialisation gtk
      gtk_init(&argc, &argv);
     
      // Création fenetre
      window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      gtk_window_set_title(GTK_WINDOW(window), "Test changement d'image");
      gtk_window_set_default_size(GTK_WINDOW(window), 400, 200);
      gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
     
      // Insertion d'une box dans la fenêtre principale
      box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
      gtk_container_add(GTK_CONTAINER(window), box);
     
      // Connexion du signal "delete-event" pour fermer l'application
      g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(gtk_main_quit), NULL);
     
      // Insertion d'une première image
      image = gtk_image_new_from_file (IMAGE1);
      gtk_box_pack_end (GTK_BOX(box), image, FALSE, FALSE, 0);
     
      // Insertion d'un bouton pour basculer d'une image à l'autre
      button = gtk_button_new_with_label ("basculer image");
      gtk_box_pack_start (GTK_BOX(box), button, FALSE, FALSE, 0);
      g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(gc_button_change), image);
     
      // Affichage du tout
      gtk_widget_show_all(window);
     
      gtk_main();
     
      return EXIT_SUCCESS;
    }

  7. #7
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2003
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2003
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Alors voila ce que j'obtiens avec gtk_image_set_from_file seul:

    *si je ne touche pas à l'image, la nouvelle image est bien chargée et affichée.
    *si je colorie l'image, la nouvelle image est chargée en mémoire mais l'affichage n'est pas actualisé.

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    Billets dans le blog
    5
    Par défaut
    Tu colories l'image de quelle manière ? En passant par Cairo ? Si tel est le cas il va te falloir sauvegarder le résultat dans un GdkPixbuf que tu utiliseras comme source à insérer dans le GtkImage.

  9. #9
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2003
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2003
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Pour colorier j'utilise un GdkPixbuf

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    Billets dans le blog
    5
    Par défaut
    À ce stade, pour pouvoir te répondre plus précisément il me faut voir ton code source. Peux-tu le poster ?

  11. #11
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2003
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2003
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Et voila le code:
    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
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
     
    #include <gtk/gtk.h>
    #include <string.h>
    #include <stdlib.h>
    #include "colorie2.h"
     
     
    #define X 50
    #define Y 50
     
     
    GtkWidget *fenetre; 
    GtkWidget *conteneur;
    GtkWidget *label;
    GtkWidget *image;
    GdkPixbuf *pixels;
    gchar texte[100], nom_fichier[100];
    guint ligne, pixel, larg, haut;
     
     
    // callback pour le menu Ouvrir image
    void ouvrir(GtkWidget *p_widget, gpointer user_data);
     
     
    // création d'un item de menu
    void menu_item_new(GtkMenu *p_menu, const gchar *titre, GCallback callback, gpointer user_data)
    {
      GtkWidget *p_menu_item = NULL;
     
      p_menu_item = gtk_menu_item_new_with_mnemonic(titre);
      gtk_menu_shell_append(GTK_MENU_SHELL(p_menu), p_menu_item);
      g_signal_connect(G_OBJECT(p_menu_item), "activate", callback, user_data);
    }
     
     
    // création du menu
    GtkMenuBar *cree_menu()
    { 
      GtkWidget *p_menu_bar = NULL;  
      GtkWidget *p_menu1 = NULL;
      GtkWidget *p_menu_item = NULL;
     
      p_menu_bar = gtk_menu_bar_new();
     
      p_menu1 = gtk_menu_new();
      p_menu_item = gtk_menu_item_new_with_mnemonic("Fichier");   
      menu_item_new(GTK_MENU(p_menu1), "Ouvrir image", G_CALLBACK(ouvrir), NULL);
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(p_menu_item), p_menu1);
      gtk_menu_shell_append(GTK_MENU_SHELL(p_menu_bar), p_menu_item);
     
     
      return GTK_MENU_BAR(p_menu_bar);
    }
     
     
    // colorier complètement l'image avec 2 couleurs blanc et noir
    void bicolore(GdkPixbuf *gpix)
    { guchar *debut = gdk_pixbuf_get_pixels(gpix);
      guchar *p = debut;
      guchar *fin;
     
      ligne = gdk_pixbuf_get_rowstride(gpix);
      pixel = gdk_pixbuf_get_n_channels(gpix);
      larg = gdk_pixbuf_get_width(gpix); 
      haut = gdk_pixbuf_get_height(gpix);
      fin = debut + haut*ligne;
     
      sprintf(texte, "larg=%d haut=%d", larg, haut);
      gtk_label_set_text(GTK_LABEL(label), texte);
     
       while(p<fin)
         { if (p[0]>200 && p[1]>200 && p[2]>200)
    	 { p[0]=p[1]=p[2]=255;
    	 }
           else
    	 { p[0]=p[1]=p[2]=0;
    	 }
           p+=pixel;
         }
    }
     
     
    // blanchis l'image en 2 couleurs
    void blanchis(void)
    { 
      pixels = gtk_image_get_pixbuf(GTK_IMAGE(image));
      if (pixels != NULL) bicolore(pixels);
      else gtk_label_set_text(GTK_LABEL(label), "pixbuf NULL");//*/
    }
     
     
    // Fichier Ouvrir -> ouvrir un fichier image
    void ouvrir(GtkWidget *p_widget, gpointer user_data)
    {
      GtkWidget *p_dialog = NULL;
      p_dialog = gtk_file_chooser_dialog_new("Ouvrir un fichier", NULL,
                                              GTK_FILE_CHOOSER_ACTION_OPEN,
                                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                              GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
                                              NULL);
      if (gtk_dialog_run(GTK_DIALOG(p_dialog)) == GTK_RESPONSE_ACCEPT)
      {    
        strcpy(nom_fichier, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(p_dialog)));
        gtk_label_set_text(GTK_LABEL(label), nom_fichier);
     
        gtk_image_set_from_file(GTK_IMAGE(image), nom_fichier);					 
        blanchis(); 
      }
      gtk_widget_destroy (p_dialog);
    }
     
     
    void OnDestroy(GtkWidget *pWidget, gpointer pData)
    {
        gtk_main_quit();
    }
     
     
    gboolean OnClic(GtkWidget *widget, GdkEventButton *event, gpointer data)
    { guchar *p;
      guint x, y;
      couleur col;
      GdkWindow *f;
     
      col=bleu;
      if (event->button == GDK_BUTTON_PRIMARY) // clic gauche
        { x = event->x - X;
          y = event->y - Y;            
     
          if (x>=0 && x<larg && y>=0 && y<haut) // colorier la région en bleu
    	colorie_region(pixels, x, y, col, blanc);
     
          image=gtk_image_new_from_pixbuf(pixels);      
          f = gtk_widget_get_window(widget); 
          gdk_window_invalidate_rect(f, NULL, TRUE);
          gdk_window_process_updates(f, FALSE);
        }
      else if (event->button == GDK_BUTTON_SECONDARY) // clic droit
        { x = event->x - X;
          y = event->y - Y;
          if (x>=0 && x<larg && y>=0 && y<haut) // repeindre la région en blanc
    	{
    	  p = gdk_pixbuf_get_pixels(pixels) + y*ligne + x*pixel;
    	  if (compare(p, col))	  	  
    	    colorie_region(pixels, x, y, blanc, col);      
    	  image=gtk_image_new_from_pixbuf(pixels); 
    	  f = gtk_widget_get_window(widget);
    	  gdk_window_invalidate_rect(f, NULL, TRUE);
    	  gdk_window_process_updates(f, TRUE);      	  
    	}
        }
     
      return TRUE;
    }
     
     
    int main( int argc, char *argv[])
    {
      gtk_init(&argc, &argv);
     
      fenetre=gtk_window_new(GTK_WINDOW_TOPLEVEL);
      gtk_window_set_default_size(GTK_WINDOW(fenetre), 1100, 1000);
      gtk_window_set_title(GTK_WINDOW(fenetre), "Cartes");
      g_signal_connect(G_OBJECT(fenetre), "destroy", G_CALLBACK(OnDestroy), NULL);
      gtk_widget_set_events(fenetre, GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK);
      g_signal_connect(G_OBJECT(fenetre), "button-release-event", G_CALLBACK(OnClic), NULL);
     
      conteneur=gtk_layout_new(NULL, NULL); 
      gtk_container_add(GTK_CONTAINER(fenetre), conteneur);
     
      gtk_layout_put(GTK_LAYOUT(conteneur), GTK_WIDGET(cree_menu()), 0, 0);
     
      strcpy(texte, "");
      label=gtk_label_new(texte);
      gtk_layout_put(GTK_LAYOUT(conteneur), label, 100, 25);
     
      strcpy(nom_fichier, "France_regions.jpg"); 
      image=gtk_image_new_from_file(nom_fichier);
      gtk_layout_put(GTK_LAYOUT(conteneur), image, X, Y);
     
      init_couleurs();
      blanchis();
     
      gtk_widget_show_all(fenetre);
      gtk_main();
     
      return 0;
    }
    et voila colorie2.h:
    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
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
     
     
    typedef struct _point
    {
      gushort x;
      gushort y;
    } point;
     
     
    typedef struct _couleur
    {
      guchar R;
      guchar V;
      guchar B;
    } couleur;
     
    extern guint ligne, pixel, larg, haut;
     
    couleur bleu, blanc, rouge;
    static GdkPixbuf *pixbuf;
     
     
    // création d'un point x,y
    point *new_point(guint x, guint y)
    { point *pt=(point *)malloc(sizeof(point));
     
      if (pt!=NULL) 
        { pt->x=x;
          pt->y=y;
        }
      return pt;
    }
     
     
    // création d'une couleur RVB
    couleur cree_couleur(guchar R, guchar V, guchar B)
    { couleur c;
     
      c.R=R;
      c.V=V;
      c.B=B;
     
      return c;
    }
     
     
    // crée les couleurs
    void init_couleurs()
    {
      bleu=cree_couleur(0, 0, 255);
      blanc=cree_couleur(255, 255, 255);
      rouge=cree_couleur(255, 0, 0);
    }
     
     
    // 1 si le pixel p est de la couleur c 
    gboolean compare(guchar *p, couleur c)
    {
      if (p[0]==c.R && p[1]==c.V && p[2]==c.B) return 1;
     
      return 0;
    }
     
     
    // colorie le point(x,y) dans la couleur c si il est ds la couleur c2
    // suppose x et y >=0, x<larg et y<haut
    static gboolean colorie_point(gint x, gint y, couleur c, couleur c2)
    { 
      guchar *p = gdk_pixbuf_get_pixels(pixbuf) + y*ligne + x*pixel;
     
      if (p[0]==c2.R && p[1]==c2.V && p[2]==c2.B)
        { p[0] = c.R;
          p[1] = c.V;
          p[2] = c.B;
     
          return 1;
        }     
     
      return 0;
    }
     
     
    // colorie une region dans la couleur c si elle est dans la couleur c2
    // version tronquée colorie une seule ligne
    void colorie_region(GdkPixbuf *pix, gint x, gint y, couleur c, couleur c2)
    { 
      gboolean vrai;
      gint xmin, xmax, xpre;
     
          pixbuf=pix;
          vrai=colorie_point(x, y, c, c2);
          xpre=x+1;
          if (x>0)
    	do
    	  { vrai = colorie_point(--x, y, c, c2);	    
    	  }
    	while (vrai && x > 0);
          xmin=x+1;
          if (vrai) xmin=x;
          x=xpre;
          if (x<larg)
    	do
    	  { vrai = colorie_point(x++, y, c, c2); 		 	    
    	  }
    	while (vrai && x < larg);
          xmax=x-1;
    }
    Pour simplifier je n'ai mis que le coloriage d'une ligne dans la fonction colorie_region.

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

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

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

    Il y a beaucoup de choses à dire sur ton code. Je vais essayer de reprendre tous les points qui pourraient être améliorer ou modifier.

    Tout d'abord le principe général. Si tu lis un peu mes quelques réponses sur ce forum tu auras compris que j'ai en horreur les déclarations de variables en globale. Ce n'est pas interdit bien sûr mais, de mon point de vue, ca rend le code illisible. De plus, on finit par ne plus trop savoir si la variable que l'on manipule est encore valide (peut être qu'une autre fonction s'est fait un plaisir de changer sa valeur) !

    Tu extrais le GdkPixbuf de ton GtkImage pour manipuler ses pixels. Bonne démarche. Mais comme tu balades une variable globale initialisée avec ce pointeur on n'est pas sûr à la fin que tu travailles toujours dessus. Pour simplifier tout ca il te faut supprimer la variable pixels, qui soit dit en passant n'est pas très explicite. pixels est en fait un pointeur sur un GdkPixbuf !

    Comment faire pour éviter les variables globales avec Gtk ?

    Il ne faut pas oublier que la majeure partie des fonctions callback peuvent recevoir une donnée utilisateur : le fameux gpointer data. Donc il faut l'utiliser pour récupérer dans la fonction gboolean OnClic(GtkWidget *widget, GdkEventButton *event, gpointer data) le pointeur sur le GtkImage.
    Pour ce faire, il faut revoir un peu la disposition des appels dans la fonction main(); :
    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
      gtk_init(&argc, &argv);
     
      fenetre=gtk_window_new(GTK_WINDOW_TOPLEVEL);
      gtk_window_set_default_size(GTK_WINDOW(fenetre), 1100, 1000);
      gtk_window_set_title(GTK_WINDOW(fenetre), "Cartes");
      g_signal_connect(G_OBJECT(fenetre), "destroy", G_CALLBACK(OnDestroy), NULL);
      gtk_widget_set_events(fenetre, GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK);
      g_signal_connect(G_OBJECT(fenetre), "button-release-event", G_CALLBACK(OnClic), NULL);
     
      conteneur=gtk_layout_new(NULL, NULL); 
      gtk_container_add(GTK_CONTAINER(fenetre), conteneur);
     
      gtk_layout_put(GTK_LAYOUT(conteneur), GTK_WIDGET(cree_menu()), 0, 0);
     
      strcpy(texte, "");
      label=gtk_label_new(texte);
      gtk_layout_put(GTK_LAYOUT(conteneur), label, 100, 25);
     
      strcpy(nom_fichier, "mon_image.jpg"); 
      image=gtk_image_new_from_file(nom_fichier);
      gtk_layout_put(GTK_LAYOUT(conteneur), image, X, Y);
    La déclaration de image doit être effectuée avant la connexion du signal "button-release-event" à la fonction Onclic();. Ainsi on pourra transmettre le pointeur image lors de la connexion. Il ne manquera plus qu'à déclarer une variable locale image dans le main(); :
    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
      GtkWidget *image=NULL;
      
      gtk_init(&argc, &argv);
     
      fenetre=gtk_window_new(GTK_WINDOW_TOPLEVEL);
      gtk_window_set_default_size(GTK_WINDOW(fenetre), 1100, 1000);
      gtk_window_set_title(GTK_WINDOW(fenetre), "Cartes");
      g_signal_connect(G_OBJECT(fenetre), "destroy", G_CALLBACK(OnDestroy), NULL);
      gtk_widget_set_events(fenetre, GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK);
    
      strcpy(nom_fichier, "mon_image.jpg"); 
      image=gtk_image_new_from_file(nom_fichier);
      
      g_signal_connect(G_OBJECT(fenetre), "button-release-event", G_CALLBACK(OnClic), image);
     
      conteneur=gtk_layout_new(NULL, NULL); 
      gtk_container_add(GTK_CONTAINER(fenetre), conteneur);
     
      gtk_layout_put(GTK_LAYOUT(conteneur), GTK_WIDGET(cree_menu()), 0, 0);
     
      strcpy(texte, "");
      label=gtk_label_new(texte);
      gtk_layout_put(GTK_LAYOUT(conteneur), label, 100, 25);
    
      // Insertion de image dans le layout
      gtk_layout_put(GTK_LAYOUT(conteneur), image, X, Y);
    Ligne 14 on transmet le pointeur image à la fonction callback "OnClic". Dans ce callback voila comment on le récupère :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    gboolean OnClic(GtkWidget *widget, GdkEventButton *event, GtkWidget *image)
    Il m'a suffit de déclarer directement le type du pointeur recu. Les avantages du C...

    Après cette manipulation on peut supprimer la variable globale image. Une fois fait le compilateur va hurler, ce qui est normal puisque tu utilises cette variable à tout bout de champ dans ton code. Il faut alors se débrouiller pour transmettre la variable locale à ces fonctions.



    Continuons dans nos remarques préliminaires. Gtk+ s'appuie pour fonctionner sur la Glib. C'est une boite à outils très complète qui te permet, entre autre, de manipuler des chaînes de caractères. Tu utilises de ton côté strcpy();. Je dirais Beurk ! Ca reste un point de vue. Cependant si tu utilises quelques fonctions mises à ta disposition par la Glib tu verrais que ton code ne s'en porterait pas plus mal. Prenons un exemple pour éclaircir tout ca.
    Dans ton code tu as
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      strcpy(nom_fichier, "mon_image.jpg"); 
      image=gtk_image_new_from_file(nom_fichier);
    Il y a deux inconvénients majeurs à cette pratique :
    1. déclarer un espace mémoire suffisant pour recevoir la copie,
    2. la déclaration en globale de la variable nom_fichier.


    Tu peux utiliser la fonction g_strdup(); de la Glib. Elle va s'occuper de l'allocation nécessaire à la chaîne transmise. Il faut, en contre partie, ne pas oublier que l'espace mémoire est alloué dans le tas. Ce qui signifie qu'une fois son utilisation terminée il faut libérer cet espace avec un g_free();.
    Ton code pourrait alors devenir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    gchar *nom_fichier = NULL;
     
    nom_fichier = g_strdup ("mon_image.jpg"); 
    image=gtk_image_new_from_file(nom_fichier);
    g_free (nom_fichier);
    Le tableau nom_fichier[] en globale peut alors être supprimé. Pour enfoncer le clou je dirais qu'ici cette allocation ne sert absolument à rien . Tu peux directement écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    image=gtk_image_new_from_file("mon_image.jpg");
    En partant de ce principe tu peux commencer à supprimer tous les appels à strcpy(); pour les remplacer par les fonctions de la glib, plus sûres.

    J'arrête là pour le moment. Je vais de mon côté modifier tout ton code dans cet esprit pour que j'y retrouve mes petits et ensuite m'attaquer à ton problème principal.

  13. #13
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2003
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2003
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Merci pour toutes ces remarques

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    Billets dans le blog
    5
    Par défaut
    Après avoir modifié tout ton code pour supprimer toutes les variables globales (je sais j'ai la tête dure ) je me suis penché sur ton problème. Pour le résoudre il suffit de faire une copie du pixbuf que tu as modifé et tu l'insères dans le GtkImage. La mise à jour est automatique .

    Voila ce que ca peut donner :
    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
    gboolean OnClic(GtkWidget *widget, GdkEventButton *event, GtkWidget *image)
    {
      guchar *p;
      guint x, y;
      couleur col;
      GdkWindow *f;
      GdkPixbuf *pixbuf = gtk_image_get_pixbuf (GTK_IMAGE(image));
      guint ligne = gdk_pixbuf_get_rowstride(pixbuf);
      guint pixel = gdk_pixbuf_get_n_channels(pixbuf);
      guint larg = gdk_pixbuf_get_width(pixbuf); 
      guint haut = gdk_pixbuf_get_height(pixbuf);
     
      col=bleu;
      if (event->button == GDK_BUTTON_PRIMARY) // clic gauche
        { x = event->x - X;
          y = event->y - Y;            
     
          if (x>=0 && x<larg && y>=0 && y<haut) // colorier la région en bleu
    	colorie_region(pixbuf, x, y, col, blanc);
     
          // Création d'une copie du pixbuf modifié
          GdkPixbuf *pixcopy = gdk_pixbuf_copy (pixbuf);
          // Insertion de ce pixbuf dans le GtkImage
          gtk_image_set_from_pixbuf (GTK_IMAGE(image), pixcopy);
          // Suppression de la copie devenue inutile
          g_object_unref(pixcopy);
     
          /*      image=gtk_image_new_from_pixbuf(pixbuf);      
    	      f = gtk_widget_get_window(widget); 
    	      gdk_window_invalidate_rect(f, NULL, TRUE);
    	      gdk_window_process_updates(f, FALSE);
          */
        }
      else if (event->button == GDK_BUTTON_SECONDARY) // clic droit
        { x = event->x - X;
          y = event->y - Y;
          if (x>=0 && x<larg && y>=0 && y<haut) // repeindre la région en blanc
    	{
    	  p = gdk_pixbuf_get_pixels(pixbuf) + y*ligne + x*pixel;
    	  if (compare(p, col))	  	  
    	    colorie_region(pixbuf, x, y, blanc, col);
     
    	  // Création d'une copie du pixbuf modifié
    	  GdkPixbuf *pixcopy = gdk_pixbuf_copy (pixbuf);
    	  // Insertion de ce pixbuf dans le GtkImage
    	  gtk_image_set_from_pixbuf (GTK_IMAGE(image), pixcopy);
    	  // Suppression de la copie devenue inutile
    	  g_object_unref(pixcopy);
     
    	  /*	  image=gtk_image_new_from_pixbuf(pixbuf); 
    		  f = gtk_widget_get_window(widget);
    		  gdk_window_invalidate_rect(f, NULL, TRUE);
    		  gdk_window_process_updates(f, TRUE);
    	  */
    	}
        }
     
      return TRUE;
    }
    Une petite question pour finir. Tu retournes TRUE pour le callback OnClic();. Est-ce vraiment le comportement que tu recherches ?

  15. #15
    Membre confirmé
    Profil pro
    Retraité
    Inscrit en
    Novembre 2009
    Messages
    329
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Novembre 2009
    Messages : 329
    Points : 606
    Points
    606
    Par défaut
    Histoire d'agiter un chiffon rouge devant Gérald, voici mon point de vue.

    Je pense que les variables globales sont agréables quand on crée des singletons (c'est à dire des objets qui ont une seule instance) volumineux et persistants.
    Quand l'objet à créer est suffisamment volumineux pour mériter un fichier distinct du fichier principal, si on déclare la variable static, sa portée est limitée au fichier considéré (donc elle n'est pas globale pour tout le programme) et cela évite la lourdeur de déclarer une structure, l'instancier et traîner tout au long du fichier des indirections inutiles.
    Évidemment, il faut être sûr de ne pas avoir à utiliser deux instances différentes de l'objet...

    Ceci dit, je suis toujours émerveillé par l'énergie que Gérald met à aider ses semblables.
    GraceGTK: a plotting tool at https://sourceforge.net/projects/gracegtk

  16. #16
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2003
    Messages
    75
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2003
    Messages : 75
    Points : 76
    Points
    76
    Par défaut
    Merci Gérald pour ton analyse. Ta méthode fonctionne bien.

    Concernant le booléen de la fonction callback, je ne fais pas trop la différence entre retourner true ou false.

  17. #17
    Membre du Club Avatar de diesel83
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2014
    Messages
    57
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Décembre 2014
    Messages : 57
    Points : 51
    Points
    51
    Par défaut
    Citation Envoyé par pierrot106 Voir le message
    Merci Gérald pour ton analyse. Ta méthode fonctionne bien.

    Concernant le booléen de la fonction callback, je ne fais pas trop la différence entre retourner true ou false.
    Quand tu réponds avec FALSE, tu laisses le signal continuer à se propager. Toutes les autres fonctions de callback liées à ce signal vont le traiter.

    Quand tu réponds TRUE, le signal est effacé par le framework GTK une fois que ta fonction de callback a fini de le traiter. En général, c'est la bonne chose à faire.

    Jean-Marie
    Je déteste qu'on cherche à me faire passer pour un con, j'y arrive déjà très bien tout seul.

  18. #18
    Membre confirmé
    Profil pro
    Retraité
    Inscrit en
    Novembre 2009
    Messages
    329
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Novembre 2009
    Messages : 329
    Points : 606
    Points
    606
    Par défaut
    Citation Envoyé par diesel83 Voir le message
    Quand tu réponds TRUE, [...]. En général, c'est la bonne chose à faire.
    Attention, si le callback modifie la taille ou l'arrangement des widgets, il faut laisser GTK faire son travail de "packing" derrière.
    GraceGTK: a plotting tool at https://sourceforge.net/projects/gracegtk

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par pvincent Voir le message
    Histoire d'agiter un chiffon rouge devant Gérald, voici mon point de vue.

    Je pense que les variables globales sont agréables quand on crée des singletons (c'est à dire des objets qui ont une seule instance) volumineux et persistants.
    Quand l'objet à créer est suffisamment volumineux pour mériter un fichier distinct du fichier principal, si on déclare la variable static, sa portée est limitée au fichier considéré (donc elle n'est pas globale pour tout le programme) et cela évite la lourdeur de déclarer une structure, l'instancier et traîner tout au long du fichier des indirections inutiles.
    Évidemment, il faut être sûr de ne pas avoir à utiliser deux instances différentes de l'objet...

    Ceci dit, je suis toujours émerveillé par l'énergie que Gérald met à aider ses semblables.
    Oui je suis d'accord. La déclaration de variables "en dehors" de toute fonction n'est pas interdite et peut se justifier selon les cas.

    Et merci pour le compliment. C'est toujours un plaisir de pouvoir aider dans la limite de ses capacités.

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

Discussions similaires

  1. [Prototype] Recharger une image
    Par estampille dans le forum Bibliothèques & Frameworks
    Réponses: 4
    Dernier message: 05/01/2009, 14h54
  2. Réponses: 6
    Dernier message: 09/10/2008, 19h43
  3. [PHP-JS] Recharger une image
    Par L8O8L dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 14/05/2008, 16h27
  4. Sauver/ReCharger une image, donne
    Par Happy dans le forum C++
    Réponses: 3
    Dernier message: 18/05/2007, 13h06
  5. Recharger une image dans la cache
    Par Prophetis dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 13/07/2006, 13h24

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