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 :

Zone de Dessin dans une fenêtre [GTK 3 & Cairo]


Sujet :

GTK+ avec C & C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2011
    Messages : 38
    Par défaut Zone de Dessin dans une fenêtre [GTK 3 & Cairo]
    Bonjour à tous.

    J'ai déjà souffert un peu avec les Drawing Area notamment parce que
    je travail sur la version 3 de GTK et que sur cette version on ne peut
    plus faire de : Widget->window, Widget->style et que même si je
    commence à peine à utiliser GTK la plupart des tutoriels sont faits
    sur la version 2 de GTK et n'utilise donc pas Cairo.


    Bref... Après recherche j'ai vu qu'il fallait utiliser cairo pour faire des
    DrawingArea. Plusieurs tutoriels sur le net expliquent bien comment
    procéder mais aucun d'entres eux ne dit comment créer un zone de
    dessin dans une fenêtre et pas faire de la fenêtre une zone de dessin
    entière...


    Par exemple je sais que je peux dessiner une zone de dessin (couleur
    jaune ici) à l'aide du code suivant, seulement toute la fenêtre sera une
    DrawingArea ce que je ne veux pas :

    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
    #include <gtk/gtk.h>
    #include <cairo.h>
     
    typedef struct Info {
      GtkWidget * win;
      cairo_t * cairo;
    } Info;
     
    gboolean on_expose_color (GtkWidget * widget, GdkEvent * e, gpointer data) {
      Info * info= data;
      cairo_pattern_t * yellow;
      double red, green, blue, alpha;
     
      info->cairo= gdk_cairo_create (gtk_widget_get_window(widget));
      red= 1.0; green= 1.0; blue= 0.0; alpha= 1.00;
      yellow= cairo_pattern_create_rgba (red, green, blue, alpha);
      cairo_set_source (info->cairo, yellow);
      cairo_paint (info->cairo);
     
      cairo_pattern_destroy (yellow);
      cairo_destroy (info->cairo);  info->cairo= NULL;
      return TRUE;
    }
     
     
    void info_init (Info * info, GtkWidget * win)  {
      info->win  = win;
      info->cairo= NULL;
    }
     
    int main (int argc, char * argv [])
    {
      Info info;
      GtkWidget * win;
      gtk_init (& argc, & argv);
      win= gtk_window_new (GTK_WINDOW_TOPLEVEL);
      gtk_widget_set_size_request (win, 200, 200);
      info_init (& info, win);
      g_signal_connect (win, "draw", G_CALLBACK (on_expose_color), & info);
     
      gtk_widget_show_all (win);  
      gtk_main ();
      return 0;
    }
    Je voulais remplacer la ligne info->cairo... par :
    info->cairo= gdk_cairo_create (gtk_widget_queue_draw_area(widget, 2, 5, 50, 20));

    mais gtk_widget_queue_draw_area renvoie pas une GtkWindow mais rien (void) donc
    cela fait une erreur... je vois pas du tout comment faire.

    Note :
    Widget->window est remplacé par gtk_widget_get_window(widget) dans GTK 3.


    Dans l'absolu ce qui serait encore mieux c'est que quand je clique sur l'icône "Nouveau"
    de ma barre d'outils une zone de dessin sur fond noire apparaissent sur une partie
    de ma fenêtre principale...

    Merci par avance
    Bonne soirée

  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
    Par défaut
    Citation Envoyé par Twice22 Voir le message
    même si je
    commence à peine à utiliser GTK la plupart des tutoriels sont faits
    sur la version 2 de GTK et n'utilise donc pas Cairo.
    Cairo est utilisé depuis GTK 2.8, soit depuis 2005... Il y a des tutoriels GTK et cairo, mais ceux sur développez.net ne sont pas forcément les plus à jour.

    Citation Envoyé par Twice22 Voir le message
    Bref... Après recherche j'ai vu qu'il fallait utiliser cairo pour faire des
    DrawingArea. Plusieurs tutoriels sur le net expliquent bien comment
    procéder mais aucun d'entres eux ne dit comment créer un zone de
    dessin dans une fenêtre et pas faire de la fenêtre une zone de dessin
    entière...
    Je ne sais pas si j'ai tout bien compris, mais a priori tu n'as qu'à ajouter une GtkDrawingArea dans ton interface, te connecter à son événement "draw", et dessiner dans la callback associée. Si dans ton exemple tu dessines dans toute la GtkWindow, c'est parce que tu es connecté à son événement draw.

    Pour ce qui est de dessiner un sous ensemble du widget auquel tu as connecté l'événement draw, gtk_widget_queue_draw te permet d'indiquer que le widget entier doit être redessiné (parce que les données qu'il affiche ont changé par exemple). En retour, cette fonction va émettre le signal "draw" pour ton widget, et ta callback va l'intercepter, te permettant de redessiner le widget entier.

    Si une modification des données à afficher ne doit provoquer la modification que d'une partie de ton widget, alors tu peux appeler gtk_widget_queue_draw_area en spécifiant les coordonnées de cette zone. Cette fonction va émettre le signal "draw" pour ton widget, ta callback va l'intercepter, et dans les paramètres d'entrée, tu peux récupérer les coordonnées de la zone à redessiner (et utiliser les fonctions de clipping de cairo, qui accélèreront l'affichage en ne dessinant que le strict nécessaire).

    J'ai écrit il y a quelques temps un exemple simple de dessin avec GTK et cairo. C'est pour GTK 2, mais la seule différence c'est que le signal "expose-event" de GTK 2 est devenu "draw" dans GTK 3. D'ailleurs, je te conseille de renommer ta callback en on_draw plutôt que on_expose_color...

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2011
    Messages : 38
    Par défaut
    Ce que je veux faire c'est créer une drawingArea dans ma fenêtre principale qui ne prenne pas toute la place de la fenêtre. Ainsi j'aurais par exemple des boutons situé sur la gauche de ma fenêtre et sur la droite un rectangle (noir) qui est ma drawing area dans laquelle je pourrais dessiner des choses quand j'appuyerai sur mes boutons...


    Je cherchais une fonction du côté de Cairo pour créer une drawingArea d'une certaine dimension dans ma fenêtre mais en fait il faut plutôt que je créé mes boutons et ma drawing area séparement et que je les attache à une table (Grid en GTK 3) ?

    En effet si je dis par exemple : "Je veux créer une une zone de dessin rectangulaire de 200 par 500 pixels dans ma fenêtre principale dont le coin supérieur de ma zone de dessin est situé aux coordonnées (20,20) de ma fenêtre principale" ben quand je redimensionnerai la fenêtre... le programme ne
    captera pas... c'est pour ça qu'il ont créé des tables je pense d'ailleurs ?

    J'ai tenté de faire un petit quelque chose mais... cela ne fonctionne pas.
    Comme mis en commentaire du code je pense qu'il faut passer area dans
    le g_signal_connect mais si je passe area rien ne se colorie...

    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
    #include <stdlib.h>
    #include <stdio.h>
    #include <gtk/gtk.h>
    #include <cairo.h>
     
     
     
    gboolean on_draw (GtkWidget *widget, GdkEventExpose *event, gpointer data) 
    {
     
      cairo_t *cr = gdk_cairo_create (gtk_widget_get_window(widget));
      GdkRectangle da;           //Dimensions de la GtkDrawingArea */
     
      /* bizarrement il n'y a pas le paramètre depth comme marqué dans le manuel officiel... */
      gdk_window_get_geometry (gtk_widget_get_window(widget), &da.x, &da.y, &da.width, &da.height);
     
      /* affiche dans la console les dimension de ma GTK_GRID */
      printf("x = %d, y = %d, width = %d, height = %d\n", da.x, da.y, da.width, da.height);
     
      cairo_set_source_rgb (cr, 0.0 , 0.0 , 0.0); //fond noir
      cairo_paint (cr);
     
      cairo_destroy (cr);
      return FALSE;
    }
     
     
    int main (int argc, char * argv [])
    {
      GtkWidget * win;
      GtkWidget * area;
      GtkWidget * table;
     
      gtk_init (& argc, & argv);
     
     
      /* description de la fenetre */
      win= gtk_window_new (GTK_WINDOW_TOPLEVEL);
      gtk_widget_set_size_request (win, 800, 600);
      g_signal_connect (G_OBJECT(win), "destroy", G_CALLBACK(gtk_main_quit), NULL);
     
      /* Créatione st insertion de zone de dessin dans la table */
      table = gtk_grid_new();
      gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(table));
     
      /* Création de la table */
      area = gtk_drawing_area_new ();
      gtk_grid_attach(GTK_GRID (table), area, 0, 0, 1, 1);
      // gtk_container_add (GTK_CONTAINER (win), area);  
     
      /* j'avais mis area au lieu de table comme premier paramètre mais 
      dans ce cas la fenetre ce colorie pas... */
      g_signal_connect (G_OBJECT (table), "draw", G_CALLBACK (on_draw), NULL);
     
      gtk_widget_show_all (win);  
      gtk_main ();
      return 0;
    }

  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
    Par défaut
    Un conseil, ne t'enferme pas dans des tailles fixes, c'est le meilleur moyen d'avoir une interface ultra-rigide. Ce qui te conviendrait le mieux, c'est une interface avec tes boutons, tes actions, et une GtkDrawingArea qui prend toute la place disponible restante. Pour cela tu dois jouer avec le paramètre expand de gtk_box_pack_start, qui dit au widget de prendre la place supplémentaire disponible, ou bien fais la même chose avec GtkGrid. Si tous les modèles de dimensionnement sont dynamiques dans GTK, c'est pour éviter les fenêtres où tout était placé au pixel près, et qui ne s'adaptaient plus dès que tu agrandissais ou rétrécissais la fenêtre (et j'ai pas mal souffert sous Windows en MFC avec ça).

    Et pour garder le dessin à la bonne échelle dans ta GtkDrawingArea, utilise les matrices de transformation cairo, comme je l'ai fait dans l'exemple de graphique en cairo dont je t'ai filé le lien.

  5. #5
    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
    Par défaut
    Je viens de regarder ton code, tu fais aussi une erreur: le prototype de la callback on_draw est erroné. Tu utilises le prototype de la callback associée au signal expose-event, mais celui ci n'existe plus. Tu dois regarder la doc GTK 3 pour connaître le prototype à utiliser. Par exemple pour GtkWidget::draw:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    gboolean user_function (GtkWidget *widget, CairoContext *cr, gpointer user_data)
    C'est d'ailleurs une des raisons de la rupture de compatibilité de GTK 3: tu travailles nativement avec cairo, plus besoin de faire des conversions de contexte graphique GDK en contexte cairo avec gdk_cairo_create, ni d'appeler cairo_destroy. C'est plus propre et plus efficace.

    Pour un exemple concret, regarde la doc de GtkDrawingArea dans GTK 3.

    Perso j'ai une erreur avec CairoContext, mais en remplaçant par le type normal d'un contexte cairo (cairo_t) ça fonctionne chez moi. Peut être un bug de la doc à ce niveau là.

    Autre remarque: utilise gtk_window_set_default_size plutôt que gtk_widget_set_size_request, sinon tu empêches le redimensionnement à une taille plus petite...

    Si tu n'arrivais pas à dessiner directement dans le GtkDrawingArea, c'est parce qu'il a une taille de 1x1 pixel. C'est parce que la manière de définir la place occupée par un widget (s'il s'étend ou pas, horizontalement, verticalement) a changé avec GtkGrid pour la rendre plus homogène. Tu as un tutoriel de la doc GTK qui t'explique les différences entre GtkBox et GtkGrid.

    Ce qui donne au final:
    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
    #include <stdlib.h>
    #include <stdio.h>
    #include <gtk/gtk.h>
    #include <cairo.h>
     
     
    gboolean on_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data) 
    {
      /* affiche dans la console les dimensions du widget */
      printf("width = %d, height = %d\n",
    		  gtk_widget_get_allocated_width(widget),
    		  gtk_widget_get_allocated_height(widget));
     
      cairo_set_source_rgb (cr, 0.0 , 0.0 , 0.0); //fond noir
      cairo_paint (cr);
     
      return FALSE;
    }
     
     
    int main (int argc, char * argv [])
    {
      GtkWidget * win;
      GtkWidget * area;
      GtkWidget * table;
     
      gtk_init (&argc, &argv);
     
     
      /* description de la fenetre */
      win= gtk_window_new (GTK_WINDOW_TOPLEVEL);
      gtk_window_set_default_size (GTK_WINDOW (win), 800, 600);
      g_signal_connect (G_OBJECT(win), "destroy", G_CALLBACK(gtk_main_quit), NULL);
     
      /* Création et insertion de zone de dessin dans la table */
      table = gtk_grid_new();
      gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(table));
     
      /* Création de la table */
      area = gtk_drawing_area_new ();
      gtk_grid_attach(GTK_GRID (table), area, 0, 0, 1, 1);
     
      /* On indique que la drawing area prend le maximum de place disponible */
      gtk_widget_set_hexpand (area, TRUE);
      gtk_widget_set_vexpand (area, TRUE);
      g_signal_connect (G_OBJECT (area), "draw", G_CALLBACK (on_draw), NULL);
     
      gtk_widget_show_all (win);  
      gtk_main ();
      return 0;
    }
    Pour éviter ces problèmes de placement de widget, je t'assure, teste Glade

  6. #6
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2011
    Messages : 38
    Par défaut
    Bonjour. Je viens de compiler votre code. Il fonctionne mais il ne fait pas ce que je souhaite.
    Je m'explique peut-être mal mais je souhaite que ma DrawingArea ne prenne pas toute la place de ma fenêtre principale mais seulement une partie. Quand je compile votre code modifié j'ai toute la fenêtre qui est colorié en noir (donc ma GtkDrawingArea remplie toute la fenêtre ?).

    Je pensais qu'en mettant ma drawingArea dans une Grille à l'aide de la fonction
    gtk_grid_attach Je pouvais avoir ce que je voulais...


    J'ai compris que les paramètres qu'il faut rentrer dans la
    gtk_grid_attach étaient les nombres de colonnes et de lignes qui séparent
    mon Widget des bordures... seulement si on a pas dit en combien de colonnes
    je subdivise ma fenêtre principale comment le programme peut effectivement placer
    ma fenêtre...

    Edit : J'arrive à faire presque ce que je veux.
    Le problème c'est qu'avec GTK 3 ben quand je redimensionne ma fenêtre la zone
    allouée pour ma drawingArea ne se redimensionne pas en prenant le même pourcentage
    d'espace vu que je suis apparemment obligé de donner la taille en pixels séparant les
    colonnes et que je peux pas plutôt subdiviser mon espace en colonne dont l'espacement
    s'adapte avec le redimensionnement de la fenêtre...

    En outre j'ai encore un problème.. Je veux mettre ma DrawingArea au milieu à droite et
    pas en haut à gauche mais quand je change les paramètre left et top de gtk_grid_attach
    ma drawingArea reste en haut à gauche... Voilà 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
    #include <stdlib.h>
    #include <stdio.h>
    #include <gtk/gtk.h>
    #include <cairo.h>
     
     
     
    gboolean on_draw (GtkWidget *widget, cairo_t *cr, gpointer data) 
    {
     
      /* affiche dans la console les dimensions du widget */
      printf("width = %d, height = %d\n",
    		  gtk_widget_get_allocated_width(widget),
    		  gtk_widget_get_allocated_height(widget));
     
     
      cairo_set_source_rgb (cr, 0.0 , 0.0 , 0.0); //fond noir
      cairo_paint (cr);
     
      //cairo_destroy (cr);
      return FALSE;
    }
     
     
    int main (int argc, char * argv [])
    {
      GtkWidget * win;
      GtkWidget * area;
      GtkWidget * table;
     
      gtk_init (& argc, & argv);
     
     
      /* description de la fenetre */
      win= gtk_window_new (GTK_WINDOW_TOPLEVEL);
      gtk_widget_set_size_request (win, 800, 600);
      g_signal_connect (G_OBJECT(win), "destroy", G_CALLBACK(gtk_main_quit), NULL);
     
      /* Créatione st insertion de zone de dessin dans la table */
      table = gtk_grid_new();
      gtk_grid_set_row_spacing (GTK_GRID (table), 10);
      gtk_grid_set_column_spacing (GTK_GRID(table), 10);
      gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(table));
     
      /* Création de la table */
      area = gtk_drawing_area_new ();
      gtk_grid_attach(GTK_GRID (table), area, 300, 200, 6, 40);
      // gtk_container_add (GTK_CONTAINER (win), area);  
     
      /* j'avais mis area au lieu de table comme premier paramètre mais 
      dans ce cas la fenetre ce colorie pas... */
      //gtk_widget_set_hexpand (area, TRUE);
      //gtk_widget_set_vexpand (area, TRUE);
      // gtk_grid_insert_column (GTK_GRID(table), 200);
      g_signal_connect (G_OBJECT (area), "draw", G_CALLBACK (on_draw), NULL);
     
      gtk_widget_show_all (win);  
      gtk_main ();
      return 0;
    }

    Merci.
    Merci

  7. #7
    Membre éclairé
    Profil pro
    Retraité
    Inscrit en
    Novembre 2009
    Messages
    331
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Novembre 2009
    Messages : 331
    Par défaut
    Il me semble que ce que tu veux faire, c'est diviser ta fenêtre principale en deux, par exemple en créant deux GtkBox, l'une qui contiendra tes boutons et l'autre ta DrawingArea.
    Avec GTK il ne faut pas hésiter à créer autant de boites que nécessaire pour obtenir la mise en page désirée.

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

Discussions similaires

  1. [Virtual Pascal] Dessiner dans une fenêtre avec la librairie OWL
    Par Roland Chastain dans le forum Autres IDE
    Réponses: 15
    Dernier message: 31/08/2012, 19h15
  2. Dessin dans une autre fenêtre
    Par Harmo dans le forum AWT/Swing
    Réponses: 5
    Dernier message: 10/05/2010, 16h00
  3. Dessiner dans une fenêtre externe à mon application
    Par fatdarron dans le forum Langage
    Réponses: 6
    Dernier message: 15/03/2010, 15h13
  4. Réponses: 2
    Dernier message: 09/02/2008, 01h23
  5. problème de dessin dans une fenêtre
    Par Mat 74 dans le forum Windows
    Réponses: 8
    Dernier message: 12/04/2007, 11h44

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