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 :

Création d'un monitor


Sujet :

GTK+ avec C & C++

  1. #1
    Membre confirmé Avatar de Mayhem555
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 89
    Par défaut Création d'un monitor
    Salut à tous.

    Je cherche à programmer un petit utilitaire sous GNome qui serait du style "System Monitor", qui permettrais donc de controller de manière graphique (avec GTK+ si possible) un autre programme que j'ai déjà fait (genre avoir un bouton graphique pour le démarrer, l'arrêter, etc.)

    Ce programme que je dois "surveiller" tourne en tâche de fond et génère des fichiers log. J'aimerai que mon monitor puisse récupérer ces fichiers log afin de tracer un graphique d'activité (un peu comme sous Win ou Linux quand on voit l'occupation de la mémoire vive, sauf que je n'ai pas besoin du temps réel).

    Voilà, le truc c'est que je n'y connais que dalle en GTK+, et que je ne sais pas trop quels outils peuvent me servir pour me lancer dans ce truc là. (le langage C m'est imposé). Quels outils me conseillez vous pour par exemple, tracer un graphique, récupérer l'état d'un process, etc..??

    Je sais que ma question est quelque peu vague, mais je suis dans le flou moi-même...

    Merci les amis

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    M'est avis il y a deux manières d'aborder le problème.
    • Soit tu lances ton application depuis une autre application.
    • Soit tu lances une application qui lit à intervalle régulier le fichier log pour en extraire les données utiles.

    Dans le premier cas la Glib met à ta disposition les fonctions suivantes.
    Dans le deuxième cas c'est de la programmation pure. Lecture d'un fichier et traitement des données. La Glib met aussi des fonctions à ta disposition pour le traitement des chaines de caractère.

    Enfin graphiquement GTK+ peut répondre sans problème à ton cahier des charges. Dessiner des graphiques ne pose pas vraiment de gros problèmes, lire à intervalle régulier, c'est aussi possible en toute simplicité.

  3. #3
    Membre confirmé Avatar de Mayhem555
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 89
    Par défaut
    Merci beaucoup gerald3d pour cette réponse très intéressante. Je vais regarder de près cette librairie Glib.

  4. #4
    Membre confirmé Avatar de Mayhem555
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 89
    Par défaut
    Bonjour !

    Me revoilà pour une seconde question, toujours sur le même projet.

    Dans mon application de monitoring, je souhaite être au courant des démons qui sont lancés (il y en a 4).
    J'ai déjà créé une fonction permettant de savoir si un processus est démarré selon son nom, mais maintenant je voudrais qu'il y ait 4 petites LED (des fichiers gif) qui soient chacune rouges ou vertes selon l'état du processus correspondant.

    Par conséquent, je voudrais appeler ma fonction qui vérifie chacun des 4 états le plus souvent possible.
    Après avoir lu quelques trucs dans les FAQ, je pensait qu'il serait bien de rajouter cette fonction dans la boucle principale de GTK, mais je n'arrive pas à grand chose.

    Le prototype de ma fonction est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int isStarted (const char *process_name) ;
    Elle renvoie 1 si le process est démarré, 0 sinon.

    Est-ce que quelqu'un pourrait m'expliquer comment implémenter cette fonctionnalité ?? Merci beaucoup !

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Pour insérer une fonction dans la boucle GTK+ il suffit d'utiliser la fonction suivante :
    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
    guint               g_timeout_add                       (guint interval,
                                                             GSourceFunc function,
                                                             gpointer data);
     
    Sets a function to be called at regular intervals, with the default priority, G_PRIORITY_DEFAULT. The function is called repeatedly until it returns FALSE, at which point the timeout is automatically destroyed and the function will not be called again. The first call to the function will be at the end of the first interval.
     
    Note that timeout functions may be delayed, due to the processing of other event sources. Thus they should not be relied on for precise timing. After each call to the timeout function, the time of the next timeout is recalculated based on the current time and the given interval (it does not try to 'catch up' time lost in delays).
     
    If you want to have a timer in the "seconds" range and do not care about the exact time of the first call of the timer, use the g_timeout_add_seconds() function; this function allows for more optimizations and more efficient system power usage.
     
    interval :
    	the time between calls to the function, in milliseconds (1/1000ths of a second)
     
    function :
    	function to call
     
    data :
    	data to pass to function
     
    Returns :
    	the ID (greater than 0) of the event source.
    Avec cette fonction on indique l'intervalle de temps entre chaque appel, la fonction à appeler et on peut en plus envoyer à la fonction appelée une donnée utilisateur.
    Le prototype de la fonction appelée est le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    gboolean            (*GSourceFunc)                      (gpointer data);
     
    Specifies the type of function passed to g_timeout_add(), g_timeout_add_full(), g_idle_add(), and g_idle_add_full().
     
    data :
    	data passed to the function, set when the source was created with one of the above functions.
     
    Returns :
    	it should return FALSE if the source should be removed.
    Comme tu peux le voir ca ne correspond pas bien avec ta fonction. Mais ce n'est pas un problème. Crées une fonction avec le bon prototype. A l'intérieur tu appelles ta propre fonction. Le tour est joué.

    Remarque :
    Il existe des LEDs toutes faites : GTK_STOCK_YES et GTK_STOCK_NO. Bien sûr tu peux toujours utiliser les tiennes pour apporter une touche personnelle à ton application.

  6. #6
    Membre confirmé Avatar de Mayhem555
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 89
    Par défaut
    Merci gerald.

    J'ai bien réussi à faire appeler ma fonction en passant via une callback et en l'ajoutant à la boucle principale de GTK+.

    Ma callback renvoie le status de mon process par le gpointer userdata (qui est passé en paranetre), est-ce une bonne pratique ? Je ne vois pas comment comment récupérer les valeurs de retour dans mon programme autrement.

    Mon autre probleme est de changer la led de couleur une fois que j'ai la valeur de retour de ma fonction...

    Pour le moment, il s'agit juste d'une image qui ne réagit à rien :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    imageled =  gtk_image_new_from_file("icons/green_led.gif");
    J'aimerai pouvoir changer dynamiquement cette image, en la remplaçant par red_led.gif lorsque le process est détecté comme non lancé.

    J'ai du mal à conceptualiser comment faire. Faut-il que ma callback qui renvoie le status du process renvoie plutôt un signal ? Dans ce cas comment faire pour que mon image réagisse à ce signal en changeant l'URL du fichier image ??

    Merci pour votre aide.

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Pour commencer tu utilises une fonction pour charger depuis le disque dur une image. Au vu de ce que tu veux faire il me semble que le chargement risque d'être répétitif au fur et à mesure de l'arrêt/démarrage de tes différents processus. Pour ma part je charger en global les deux images à utiliser. Ainsi plus d'accès disque par la suite.

    Ensuite l'image que tu as chargé il faut bien l'intégrer dans ton interface. Apparemment pour le moment ce n'est pas le cas. Une fois que tu auras décidé de son emplacement, comment la changer selon les besoins?

    Le plus simple et de détruire l'actuelle avec un simple gtk_widget_destroy(); et d'insérer sa remplaçante au même endroit. Le problème est que lors du premier gtk_widget_destroy(); ton pointeur global sur ton image n'est plus utilisable.

    La solution est simple. Plutôt que de charger ton image directement dans un GtkWidget, charges-la dans un GdkPixbuf. Ensuite pour l'afficher tu as la fonction GtkWidget* gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf);. Tu récupères un GtkWidget que tu peux insérer dans ton interface. Ainsi tu ne touches pas aux deux pointeurs globaux qui contiennent les images et tu peux utiliser la méthode pré-citée pour changer les images de ton interface à la volée.

  8. #8
    Membre confirmé Avatar de Mayhem555
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 89
    Par défaut
    Salut, je reviens dans ce post avec une autre étape de mon projet de type"system monitor"

    Je rapelle ce que je veux faire : j'ai un démon qui observe des paquets d'un certain type passer sur le réseau. Pour chaque paquet qui passe, le programme rempli un des fichiers log.

    Je veux donc tracer un graphe comparable aux system monitor permettant de voir combien de paquets ont été espionnés, en lisant pour cela le nombre de ligne des fichiers log. Le graphe doit donc évoluer en temps réel, en se déplaçant vers la gauche d'un pixel à chaque intervalle de temps (préalablement fixé), alors que la colonne de pixels la plus à gauche est supprimée, je trace la nouvelle valeur sur la colonne la plus à droite...et ainsi de suite.

    Je souhaite donc utiliser GDK pour le dessin...j'aimerai par ailleurs dessiner à l'intérieur d'une GtkDrawingArea, mais je ne sais pas comment faire par la suite, pour gérer mon mécanisme d'affichage...
    Faut-il utiliser un gdkpixmap, pixbuf ?

    Aussi, comment faire pour gérer ce mécanisme de déplacement vers la gauche de mon graphe, sans que ça "déborde" sur la gauche, etc...

    Comment éviter de devoir garder tout ça en mémoire pour le retracer avec un pixel de décalage ?

    Merci pour votre aide !

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Comme tu l'as écrit un GtkDrawingArea demande une sauvegarde des données affichées pour permettre un rafraichissement ou un changement du dessin.

    L'idéal est d'utiliser les GdkPixbuf. Tu peux en créer un vierge de dimension (x,y). Tu peux ensuite mettre le pixel que tu veux à la couleur que tu veux. Ce GdkPixbuf peut être affiché ensuite dans un GtkDrawingArea.

    Mais tu te demandes quel est l'intérêt? C'est simple. Image une image de (10,10). Cette image représente le graphe. Une nouvelle barre doit être dessinée à droite.
    Tu peux créer un nouveau GdkPixbuf en copiant celui contenant le graphe mais en ne prenant que les 9 dernières "colonnes". Ensuite tu dessines dans ce GdkPixbuf la nouvelle donnée. Enfin tu l'affiches. CQFD.
    Lors d'un rafraichissement le serveur X affichera le GdkPixbuf actuel. Avec cette méthode il n'y a en plus aucune perte de temps en calcul quelconque pour reconstruire le graphe.

  10. #10
    Membre confirmé Avatar de Mayhem555
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 89
    Par défaut
    Salut a vous.

    gerald3d, merci pour ta réponse.

    Désolé de ne pas avoir répondu avant j'avais des soucis sur ma machine qui m'ont d'ailleurs retardé dans mon projet.

    Toujours est-il que j'ai un peu de mal à*implémenter ta solution. Je veux que mon graphe se rafraichisse toutes les secondes, j'ai donc ajouté une callback à la GTK Main Loop qui fait ceci (elle trace juste une ligne pour le test) :

    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
     
    gboolean
    cb_graph (gpointer data)
    {
    	GdkPixbuf *pixbuf1 ;
    	GdkDrawable *drawable1 ;
    	drawable1 = drawingArea->window ; //drawingArea is a  global GtkWidget
    	/*draw */
    	gdk_draw_line (drawable1, drawingArea->style->fg_gc[GTK_WIDGET_STATE (drawingArea)], 0,0, drawingArea->allocation.width,  drawingArea->allocation.height) ;
     
    	/* we copy the drawable into pixbuf but with width -1 pixel*/
    	gdk_pixbuf_get_from_drawable (pixbuf1, drawable1,  gdk_drawable_get_colormap (drawable1),
    	                                                         0, 0,
    	                                                         0, 0,
    	                                                         drawingArea->allocation.width -1,
    	                                                         drawingArea->allocation.height );
    	(void) data ;
      return TRUE ;
    }
    Comme on l'a vu, étant donné que je dois respecter le prototype de ma callback pour la faire passer dans un g_timeout_add, je ne peux faire passer mon GtkDrawingArea que de manière globale (ou bien pourrais-je le tenter via le gpointer ?).

    Et voilà donc le contenu de interface.c (qui dessine toute l'interface), le pointer GtkWidget *drawingArea est déclaré de manière globale dans interface.h.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    /* Second Tab  */
    	drawingArea = gtk_drawing_area_new ();
    	gtk_container_add (GTK_CONTAINER (tabs), drawingArea);
    	gtk_widget_set_size_request (drawingArea, 50, 100);
    	label_tab_2 = gtk_label_new ("Activity");
    	gtk_notebook_set_tab_label (GTK_NOTEBOOK (tabs), gtk_notebook_get_nth_page (GTK_NOTEBOOK (tabs), 1), label_tab_2);
     
    g_timeout_add (1000, cb_graph, NULL) ;
    Comme on peut le voir, le graphe se situe sur le deuxieme onglet d'un notebook. Lors du lancement de l'application, il n'est donc pas visible.
    J'ai donc ces deux trucs qui m'apparaissent en console :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    (projet:9790): Gdk-CRITICAL **: gdk_drawable_get_colormap: assertion `GDK_IS_DRAWABLE (drawable)' failed
     
    (projet:9790): Gdk-CRITICAL **: gdk_pixbuf_get_from_drawable: assertion `src != NULL' failed
    Lorsque je clique sur le deuxieme onglet (ou se trouve le graphe), rien. Il redessine tranquillement la ligne chaque seconde.

    Mais dès que je rechange d'onglet, c'est reparti :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (projet:9850): Gdk-CRITICAL **: gdk_pixbuf_get_from_drawable: assertion `gdk_window_is_viewable (src)' failed
    Alors il y a plein de choses que je n'ai pas du comprendre

    Pouvez-vous m'aider ?

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Tu dessines directement sur le GtkDRawingArea qui n'est pas affiché. Donc tu reçois gentiment un warning. Pour le warning n°2 tu peux toujours utiliser une condition avec ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #define GTK_WIDGET_VISIBLE(wid)		  ((GTK_WIDGET_FLAGS (wid) & GTK_VISIBLE) != 0)
     
    Evaluates to TRUE if the widget is visible.
     
    wid :
    	a GtkWidget.
    Tu dis être obligé de mettre le GtkDRawingArea en global. Pourquoi n'utilises-tu pas le gpointer data mis à ta dispostion dans cb_graph();? Dans interface.c tu écris simplement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    g_timeout_add (1000, cb_graph, drawingArea) ;
    Et dans cb_graph(); tu commences par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GtkWidget *drawingArea = (GtkWidget*) data;
    Enfin les premiers warnings apparaissent parce que ton pointeur drawingArea n'est pas encore initialisé et que tu commences déjà à vouloir le travailler. En règle générale il faut que le widget soit affiché avant. Pour palier à ce petit inconvénient on peut utiliser un CallBack associé au signal "realize" du GtkDrawingArea dans lequel on effectue le premier dessin.
    Une autre méthode et d'utiliser dans cb_graph(); une condition :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    GTK_WIDGET_DRAWABLE()
     
    #define GTK_WIDGET_DRAWABLE(wid)	  (GTK_WIDGET_VISIBLE (wid) && GTK_WIDGET_MAPPED (wid))
     
    Evaluates to TRUE if the widget is mapped and visible.
     
    wid :
    	a GtkWidget.

  12. #12
    Membre confirmé Avatar de Mayhem555
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 89
    Par défaut
    Salut ! Merci beaucoup pour ta réponse, tu es ma lumière ces jours-ci.

    La deuxieme solution en utilisant la macro GTK_DRAWABLE() a bien marché. Ainsi que le passage du GtkDrawingArea dans le gpointer.

    Je poursuis donc mon projet, et j'ai fait évoluer ma callback cb_graph, voilà ce que ça donne :
    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
    cb_graph (gpointer data)
    {
     
    	static gboolean firstFrame = TRUE ;
    	static GdkPixbuf *pixbuf1 ;
    	int plottingValue = 25 ; //TODO
    	GtkWidget *drawingArea = (GtkWidget*) data ;
    	GdkDrawable *drawable1 ;
    	drawable1 = drawingArea->window ;
     
    	if(GTK_WIDGET_DRAWABLE(drawingArea))
    	{
    		if (!firstFrame) //if not the first frame, draw the previous pixbuf in the drawable
    			gdk_draw_pixbuf (	drawable1,
    								drawingArea->style->fg_gc[GTK_WIDGET_STATE (drawingArea)],
    								pixbuf1,
    								0,0,
    								0,0,
    								-1,-1,
    								GDK_RGB_DITHER_NORMAL,
    								0,0) ;
     
    		/*draw the value*/
     
     
    		gdk_draw_line (drawable1, drawingArea->style->fg_gc[GTK_WIDGET_STATE (drawingArea)],
    				drawingArea->allocation.width, drawingArea->allocation.height,
    				drawingArea->allocation.width, drawingArea->allocation.height - plottingValue) ;
     
    		/* we copy the drawable into pixbuf but with width -1 pixel*/
    		gdk_pixbuf_get_from_drawable (pixbuf1, drawable1,  gdk_drawable_get_colormap (drawable1),
    																 1, 0,
    																 0, 0,
    																 drawingArea->allocation.width -1,
    																 drawingArea->allocation.height );
    		firstFrame = FALSE ;
    	}
    	else
    		firstFrame = TRUE ;
     
    	return TRUE ;
    }

    Maintenant, les anciens warning n'apparaissent plus, mais quand je suis sur l'onglet de graphique (le second), le graphe n'est pas tracé (rien n'est tracé d'ailleurs) et un warning apparaît (chaque seconde donc) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (projet:11868): Gdk-CRITICAL **: gdk_draw_pixbuf: assertion `GDK_IS_PIXBUF (pixbuf)' failed
    Heu oui, mais bon. Le pixbuf n'est pas bon ? Pourtant il devrait être correctement créé par la fonction gdk_pixbuf_get_from_drawable(), qui sera de toute façon appelée avant gdk_draw_pixbuf ().


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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par Mayhem555 Voir le message
    Heu oui, mais bon. Le pixbuf n'est pas bon ? Pourtant il devrait être correctement créé par la fonction gdk_pixbuf_get_from_drawable(), qui sera de toute façon appelée avant gdk_draw_pixbuf ().
    Heu oui mais non . pixbuf1 n'est pas forcément initialisé.

    Un pixbuf n'est pas forcément initialisé à tous les coups. Surtout si le drawable n'est pas encore affiché. Tu retrouves donc un peu les problèmes précédents. Il exite deux solutions à ca:
    1. Tu initialises la première fois pixbuf1 avec gdk_pixbuf_new();.
    2. Tu vérifies à chaque fois que tu veux l'afficher qu'il ne vaut pas NULL.Si l'initialisation ou la copie dans un pixbuf échoue les fonctions associées renvoient NULL.

  14. #14
    Membre confirmé Avatar de Mayhem555
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 89
    Par défaut
    Aha ! Autant pour moi !

    Alorsssssse, j'ai un peu avancé, maintenant le graphe se trace (valeur constante pour le moment), mais lors du traçage de la deuxieme valeur, il trace un espece de ligne qui n'a rien a faire là.

    Ensuite, lorsque je laisse tourner un peu, le graphe avance vers la gauche, toujours avec cette ligne bizarre, puis hop, j'ai un autre phénomène encore plus bizarre. Voila ce que j'ai (ce sera plus simple avec un screenshot) :


    OK, pour le moment c'est moche je sais , mais je ne comprends pas d'où vient l'erreur. Probablement de la façon dont je sauvegarde mon pixbuf, mais où ??

    Mon code actuel pour le traçage du graphe :

    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
    gboolean
    cb_graph (gpointer data)
    {
    	GtkWidget *drawingArea = (GtkWidget*) data ;
    	GdkDrawable *drawable1 ;
    	GdkColormap *colormap ;
    	GdkColor graph_color ;
    	static gboolean firstFrame = TRUE ;
    	static GdkPixbuf *pixbuf1 ;
    	static int plottingValue = 25 ; //TODO
    	int width ;
    	int height ;
     
    	width = drawingArea->allocation.width ;
    	height = drawingArea->allocation.height ;
    	drawable1 = drawingArea->window ;
     
    	//color  around blue //TO BE ADDED TO THE COLORMAP
    	graph_color.red = 15872 ;
    	graph_color.green = 40056 ;
    	graph_color.blue = 49152 ;
     
     
    	if(GTK_WIDGET_DRAWABLE(drawingArea))
    	{
    		if (!firstFrame) //if not the first frame, draw the previous pixbuf in the drawable
    		{
    			gdk_draw_pixbuf (	drawable1,
    					drawingArea->style->fg_gc[GTK_WIDGET_STATE (drawingArea)],
    					pixbuf1,
    					0,0,
    					0,0,
    					-1,-1,
    					GDK_RGB_DITHER_NORMAL,
    					0,0) ;
    			g_object_unref (pixbuf1);
    		}
     
    		gdk_draw_rectangle (drawingArea->window,
    					drawingArea->style->fg_gc[GTK_WIDGET_STATE (drawingArea)],
    					TRUE,
    					width - KAMON_GRAPH_THICKNESS -1,
    					height -KAMON_GRAPH_THICKNESS -1 - plottingValue,
    					2*KAMON_GRAPH_THICKNESS+1,
    					2*KAMON_GRAPH_THICKNESS+1);
     
    		/* we copy the drawable into pixbuf but with width -1 pixel*/
     
    		pixbuf1 = gdk_pixbuf_get_from_drawable(NULL, drawable1, gdk_drawable_get_colormap (drawable1),
    												KAMON_GRAPH_THICKNESS,0,
    												0,0,
    												width,
    												height );
     
    		firstFrame = FALSE ;
    	}
    	else
    	{
    		firstFrame = TRUE ;
    	}
    	return TRUE ;
    }
    La macro KAMON_GRAPH_THICKNESS vaut 1.
    Ah oui aussi le dessin devient tout crade lorsque une autre fenêtre passe par dessus, mais là je suppose qu'il faut que je gère un expose_event pour ça non ?

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Je pense que tu as trouvé la solution tout seul. Gère le signal "expose-event".

    Une petite remarque toutefois. Je te conseille de ne pas dessiner directement dans le GtkDrawingArea. Dans cb_graph(); construis seulement un GdkPixbuf représentant ton graph. Ensuite dans le CALLBACK de "expose-event" tu affiches simplement ce GdkPixbuf.

    Cette méthode donne une vélocité à ton application sans commune mesure avec ta méthode actuelle.

  16. #16
    Membre confirmé Avatar de Mayhem555
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 89
    Par défaut
    La gestion de l'expose_event va enlever les bugs d'affichage ? (les lignes bizarres sur le screenshot de mon précédent post ?)

    Pour ta solution, comment faire pour dessiner directement dans un pixbuf ? je suis nécessairement obligé de passer par un drawable, non ? Un gdk_pixmap peut-être ? que je retransforme ensuite en pixbuf ?

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    J'avais ecris un papier sur le sujet qui n'a pas encore été mis en place. Je te le livre ici en copie :

    Question :
    Principe des GdkPixbufs.

    Réponse:
    Le GdkPixbuf est une structure dans laquelle on va pouvoir trouver différentes informations sur l'image ainsi que les données brutes de l'image.
    Il existe plusieures manières de créer une image dans un GdkPixbuf:
    - Soit en déclarant une image vierge.
    - Soit en copiant toute ou partie d'une image existante.
    - Soit en chargeant une image depuis un support (DD, CD, DVD ...).

    Une fois créée, les données brutes sont accessibles avec la fonction guchar *gdk_pixbuf_get_pixels(const GdkPixbuf *pixbuf);.

    Comment sont ordonnées les données?
    -----------------------------------
    Il est important de savoir qu'une image n'est pas forcément codée avec 3 octets par pixels. On peut aussi en utiliser 4! Donc avant de vouloir "triturer" ces données il faut connaître l'encodage. Pour cela on dispose de la fonction int gdk_pixbuf_get_n_channels(const GdkPixbuf *pixbuf); qui nous renverra le nombre d'octet par pixel.

    A quoi peut bien servir ce quatrième octet?
    -------------------------------------------
    Cet octet permet de gérer la transparence de l'image. Vous pouvez l'ignorer si cette information ne vous sert à rien. La gestion de la transparence est un autre sujet que ne sera traîté ici.

    Comment accéder aux données?
    ----------------------------
    Pour accéder aux données, rien de plus simple si on peut dire. Le pixel en haut à gauche se trouve aux adresses suivantes :

    // Récupération du pointeur sur les données brutes.
    guchar *pixel=gdk_pixbuf_get_pixels(pixbuf);

    // Récupération des composantes du pixel de coordonnées (0,0)
    guchar red, green, blue;
    red=pixel[0];
    green=pixel[1];
    blue=pixel[2];

    Tout ceci c'est bien joli, mais comment faire si la couleur est codée sur 4 octets? pixel[3] correspond alors à l'information de transparence. Ignorez-le.

    Automatisation d'accés.
    -----------------------
    Admettons que nous disposions d'une image de 100x50. Comment accéder rapidement à tout pixel de cette image? Je vous donne ici le code d'une fonction simple qui vous renvoie les composantes des coordonnées d'un pixel transmises.
    Cette fonction renvoie FALSE si vous donnez une coordonnée hors image ou lorsque l'image vaut NULL.

    gboolean gdkpixbuf_get_colors_by_coordinates(GdkPixbuf *pixbuf, gint x, gint y, guchar *red, guchar *green, guchar *blue)
    {
    guchar *pixel=NULL;
    gint channel=0;
    gint width=0;

    if (!pixbuf) return FALSE;
    if (x<0 || y<0) return FALSE;
    if (x>gdk_pixbuf_get_width(pixbuf)) return FALSE;
    if (y>gdk_pixbuf_get_height(pixbuf)) return FALSE;

    pixel=gdk_pixbuf_get_pixels(pixbuf);
    channel=gdk_pixbuf_get_n_channels(pixbuf);
    width=gdk_pixbuf_get_width(pixbuf);

    *red = pixel[(x*channel)+(y*width*channel)];
    *green = pixel[(x*channel)+(y*width*channel)+1];
    *blue = pixel[(x*channel)+(y*width*channel)+2];

    return TRUE;
    }

    Dans le même ordre d'idée on peut "inverser" cette fonction pour afficher un pixel. Voila une autre fonction qui à le même déroulement mais qui cette fois affecte une couleur à un pixel.

    gboolean gdkpixbuf_set_colors_by_coordinates(GdkPixbuf *pixbuf, gint x, gint y, guchar red, guchar green, guchar blue)
    {
    guchar *pixel=NULL;
    gint channel=0;
    gint width=0;

    if (!pixbuf) return FALSE;
    if (x<0 || y<0) return FALSE;
    if (x>gdk_pixbuf_get_width(pixbuf)) return FALSE;
    if (y>gdk_pixbuf_get_height(pixbuf)) return FALSE;

    pixel=gdk_pixbuf_get_pixels(pixbuf);
    channel=gdk_pixbuf_get_n_channels(pixbuf);
    width=gdk_pixbuf_get_width(pixbuf);

    pixel[(x*channel)+(y*width*channel)] = red;
    pixel[(x*channel)+(y*width*channel)+1] = green;
    pixel[(x*channel)+(y*width*channel)+2] = blue;

    return TRUE;
    }

    Conclusion.
    -----------
    Le GdkPixbuf est la base de tout traîtement d'image sérieux avec GTK+. The Gimp en est le répresentant. Plutôt que d'essayer de "monter une usine à gaz" en empilant des GtkImage dans des GtkTable et autres GtkBox, je vous enclins à vous pencher un peu sur cette manière de "dessiner". De nombreuses fonctions sont à votre disposition pour manipuler des GdkPixbuf. Leur affichage final ne pose aucun problème puisque vous pouvez les intégrer directement dans un GtkDrawingArea ou bien les "convertir" en GtkImage.

  18. #18
    Rédacteur

    Avatar de gege2061
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2004
    Messages
    5 840
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Juin 2004
    Messages : 5 840
    Par défaut
    Citation Envoyé par gerald3d Voir le message
    J'avais ecris un papier sur le sujet qui n'a pas encore été mis en place. Je te le livre ici en copie :
    Bien évidement que si : http://gtk.developpez.com/faq/?page=gdkpixbuf

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Au temps pour moi gege2061.

  20. #20
    Membre confirmé Avatar de Mayhem555
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 89
    Par défaut
    Alors si je comprends bien, on peut écrire dans un pixbuf, mais pixel par pixel.

    Bien que ce ne soit pas vraiment mon cas, qu'en est-il s'y on doit par exemple tracer une ligne ? Faut-il implémenter soit même des algorithmes d'allumage de pixels (Bresenham) ? Qu'en est-il pour des formes plus complexes ?

Discussions similaires

  1. Classe pour la création d'un graphe xy
    Par Bob dans le forum MFC
    Réponses: 24
    Dernier message: 03/12/2009, 17h20
  2. création d'un scanserveur (monitoring)
    Par lylou dans le forum Programmation et administration système
    Réponses: 1
    Dernier message: 03/05/2006, 22h08
  3. [Kylix] Création d'un fichier lien
    Par DrQ dans le forum EDI
    Réponses: 2
    Dernier message: 14/05/2002, 21h30
  4. Création image BMP
    Par Anonymous dans le forum C
    Réponses: 2
    Dernier message: 25/04/2002, 16h04

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