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 :

Affichage dynamique -type animation


Sujet :

GTK+ avec C & C++

  1. #1
    Membre confirmé
    Homme Profil pro
    chercheur
    Inscrit en
    Décembre 2012
    Messages
    195
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : Décembre 2012
    Messages : 195
    Par défaut Affichage dynamique -type animation
    Bonjour,

    Je commence - je crois - à bien comprendre GTK (même si je ne maitrise pas encore tout évidement). Plus trop de problème pour afficher et gérer des choses en statique.

    Ce que je voudrais faire à présent, est d'avoir un affichage dynamique (par exemple du type chronomètre que affiche les secondes qui défilent, pour rester simple). J'ai beau chercher partout, je ne trouve pas. Notamment, pour l'application que je dois développer, je suis mal à l'aise avec l'idée d'utiliser des timeouts car il se passe potentiellement des choses tout le temps - en continu - et l'affichage doit suivre ceci de manière fluide. Si je prends comme exemple l'affichage des nombres entiers, 1, 2, 3 etc., je pensais naïvement definir une fonction callback qui met à jour un label, et qui est appelée chaque fois que le signal "expose-event" est capté, avec un code comme ca:

    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
    #include <stdlib.h>
    #include <gtk/gtk.h>
    int i=1;
    int main(int argc, char **argv)
    {
        /* déclaration des widgets */
        GtkWidget *pWindow; /*fenetre */
        GtkWidget *pLabel; /* un label */
     
        void OnDestroy(GtkWidget *pWidget, gpointer pData); /* fonction call back destroy */
        void OnExpose(GtkWidget *pWidget, gpointer pData); /* fonction call back mise à jour affichage */
     
        /* Initialisation de GTK+ */
        gtk_init(&argc, &argv);
        /* création de la fenetre */
        pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        /* définition des paramètres de la fenetre */
        gtk_window_set_position(GTK_WINDOW(pWindow), GTK_WIN_POS_CENTER);
        gtk_window_set_default_size(GTK_WINDOW(pWindow), 500, 500);
        gtk_window_set_title(GTK_WINDOW(pWindow), "fenetre");
        /* création du label */
        pLabel=gtk_label_new("1");
     
        /* ajout du label à la fenetre */
         gtk_container_add(GTK_CONTAINER(pWindow), pLabel);
        /*affichage de la fenetre */
        gtk_widget_show_all(pWindow);
        /* Connexion des signaux */
         g_signal_connect(G_OBJECT(pWindow), "expose-event", G_CALLBACK(OnExpose), GTK_LABEL(pLabel));
        g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(OnDestroy), NULL);
        /* Demarrage de la boucle evenementielle */
        gtk_main();
        return EXIT_SUCCESS;
    }
    void OnDestroy(GtkWidget *pWidget, gpointer pData){
        /* Arret de la boucle evenementielle */
         gtk_main_quit();
    }
    void OnExpose(GtkWidget *pWidget, gpointer pData){
        /* Mise a jour du label */
        char tempo[10];
        (void)sprintf(tempo, "%d", i);
        i++;
        gtk_label_set_text(GTK_LABEL(pData), tempo);
    }
    Ca ne marche pas. Ai-je donc loupé quelque chose? Le signal "expose-event" n'est-il pas le bon signal à gérer? D'autres solutions existent?

    D'avance merci pour toute aide sur ce point.

    Eric.

  2. #2
    Membre actif Avatar de poincare
    Homme Profil pro
    Architecte technique
    Inscrit en
    Mai 2007
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 48
    Par défaut Cycle de vie des widgets gtk
    Il faudrait peut-être mettre la commande show en dernier, après la connexion des signaux.
    Le signal expose-event est appellé dans show.
    Un conseil : aller voir des exemples Gtk soit dans rosetta-code.org, soit dans un tutoriel.de ce site.

  3. #3
    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 eric1708 Voir le message
    Ca ne marche pas.
    "Cela entraîne une erreur de segmentation" aurait été une meilleure description. Je ne vois pas trop comment tu peux tester le fonctionnel si ton programme ne se lance même pas.

    Première erreur: tu ne respecte pas les prototypes des signaux. Ceux-ci ne s'inventent pas: il faut consulter la documentation officielle pour connaître le prototype à utiliser. En l'occurence, pour le signal expose-event:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    gboolean user_function (GtkWidget *widget, GdkEvent *event, gpointer user_data)
    On se rend alors compte que ton prototype retourne void au lieu de gboolean, et que tu as oublié le paramètre de type GdkEvent *. C'est celui là que tu as essayé de manipuler comme un GtkLabel, d'où le crash.

    Tu dois en plus faire retourner FALSE à ta callback, pour que l'événement soit propagé et la nouvelle valeur de ton GtkLabel affichée. Ta callback devient:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    gboolean OnExpose(GtkWidget *pWidget, GdkEvent *event, gpointer pData)
    {
    	/* Mise a jour du label */
    	char tempo[10];
    	(void)sprintf(tempo, "%d", i);
    	i++;
    	gtk_label_set_text(GTK_LABEL(pData), tempo);
    	return FALSE;
    }
    Ce code modifié gère l'affichage d'un label qui s'auto-incrémente. Cependant, pour un chronomètre, cela ne fonctionnera pas, la méthode n'est pas la bonne. Le signal expose-event est appelé à chaque fois que le contenu d'un widget doit être redessiné. Or là, tu le fais non-stop, et tu modifies le contenu continuellement. Tu ne gères pas l'aspect temporel.

    La bonne méthode, c'est d'utiliser un timeout avec g_timeout_add_seconds pour se déclencher approximativement toutes les secondes, et dans la callback correspondante, mettre à jour la valeur à afficher (comme tu l'as fait avec gtk_label_set_text) à partir d'un GTimer. Ton GTimer t'offre la précision nécessaire pour la gestion temporelle, et tu ne fais que raffraîchir à l'écran la valeur du GTimer, approximativement une fois par seconde.

    Tu n'auras donc même pas besoin d'utiliser le signal expose-event, qui n'est réellement nécessaire que quand tu dessines toi même le contenu d'une fenêtre (dans le cas d'un GtkDrawingArea par exemple). Or, ce que tu veux faire, c'est juste changer le contenu d'un widget, mais déléguer au widget la manière de dessiner ce contenu.

  4. #4
    Membre confirmé
    Homme Profil pro
    chercheur
    Inscrit en
    Décembre 2012
    Messages
    195
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : Décembre 2012
    Messages : 195
    Par défaut
    Citation Envoyé par liberforce Voir le message
    "Cela entraîne une erreur de segmentation" aurait été une meilleure description. Je ne vois pas trop comment tu peux tester le fonctionnel si ton programme ne se lance même pas.
    Oui, en fait, j'ai oublié de dire que j'étais un super-gourou et que j'étais capable de savoir qu'un code fonctionne ou pas sans le lancer ...

    Citation Envoyé par liberforce Voir le message
    Première erreur: tu ne respecte pas les prototypes des signaux. Ceux-ci ne s'inventent pas: il faut consulter la documentation officielle pour connaître le prototype à utiliser. En l'occurence, pour le signal expose-event:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    gboolean user_function (GtkWidget *widget, GdkEvent *event, gpointer user_data)
    On se rend alors compte que ton prototype retourne void au lieu de gboolean, et que tu as oublié le paramètre de type GdkEvent *. C'est celui là que tu as essayé de manipuler comme un GtkLabel, d'où le crash.
    Excellente réponse. Merci. Le problème est que je n'avais pas trouvé la "documentation officielle" pour les signaux et les prototypes des fonctions callback. Merci!

    Citation Envoyé par liberforce Voir le message
    [...]
    Ce code modifié gère l'affichage d'un label qui s'auto-incrémente. Cependant, pour un chronomètre, cela ne fonctionnera pas, la méthode n'est pas la bonne. Le signal expose-event est appelé à chaque fois que le contenu d'un widget doit être redessiné. Or là, tu le fais non-stop, et tu modifies le contenu continuellement. Tu ne gères pas l'aspect temporel.

    La bonne méthode, c'est d'utiliser un timeout avec g_timeout_add_seconds pour se déclencher approximativement toutes les secondes, et dans la callback correspondante, mettre à jour la valeur à afficher (comme tu l'as fait avec gtk_label_set_text) à partir d'un GTimer. Ton GTimer t'offre la précision nécessaire pour la gestion temporelle, et tu ne fais que raffraîchir à l'écran la valeur du GTimer, approximativement une fois par seconde.
    A mon tour: Mais comment peux-tu répondre à ma question sans même l'avoir lu (nan, je rigole, c'est de l'humour): Je dis clairement dans ma question initiale que je dois gérer en continue des evenements, pas au pas de la seconde (ou moins). Je dois modifier en continu, et - au besoin - je peux gérer ca en fonction d'une base de temps, si nécessaire.

    Merci en tout cas pour la réponse. Ce me sauve.

    Cordialement,

  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
    Le problème c'est que "en continu", ça peut être interprété de multiples façons. Mais je vois l'esprit. Pour de l'animation, tu vas viser un certain nombre d'images par seconde, donc en général tu te rapportes à des FPS (frame per second), et donc une période temporelle entre chaque image. Si tu veux en revanche rafraîchir ton interface à chaque fois que c'est possible mais sans imposer de contrainte temporelle, tu peux faire du polling avec g_idle_add. Cela te permet d'enregistrer une callback qui sera appelée quand GTK n'aura plus d'événements à traiter. Attention aussi à la valeur de retour de la callback, c'est un booléen qui indique si elle devra à nouveau être appelée ou pas.

  6. #6
    Membre confirmé
    Homme Profil pro
    chercheur
    Inscrit en
    Décembre 2012
    Messages
    195
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : Décembre 2012
    Messages : 195
    Par défaut
    Merci pour cette réponse. Très utile. Je n'ai jamais utilisé g_idle_add(). Je suis preneur d'un exemple de code. Ceci dit, pour rentrer dans le détail, voici ce que j'essaye de coder:

    J'ai un dispositif de prise de mesure qui discute sur un port série, et qui envoie des signaux. Le code doit écouter ce port (dans une boucle while() sans fin) et doit à la fois enregistrer la coordonnée temporelle de chaque signal émis (d'où le "en continu" dont je parle) et modifier l'affichage sur l'écran en direct (d'où l'utilisation du signal "expose-event"). Il y a peu de signaux qui sont émis (moins d'un par seconde, en moyenne) donc pas de risque "d'engorgement" de la pile d’événements à gérer par GTK. Je ne suis pas sûr, donc, de devoir utilser un g_idle_add(). Il me reste cependant à gérer la boucle while() sans fin d"écoute du port série, et son interaction avec la bouche évenementielle de GTK. Voilà!

    Encore merci pour toute aide.

    Cordialement,

    Eric.

Discussions similaires

  1. Problème d'affichage dynamique d'une liste
    Par bor1s dans le forum ASP
    Réponses: 2
    Dernier message: 18/11/2005, 16h18
  2. Réponses: 1
    Dernier message: 08/07/2005, 02h46
  3. [VB.NET] - affichage dynamique dans un tableau
    Par karibouxe dans le forum ASP.NET
    Réponses: 8
    Dernier message: 20/06/2005, 15h07
  4. affichage dynamique en fonction des données en base
    Par jengo dans le forum Bases de données
    Réponses: 1
    Dernier message: 28/10/2004, 10h22
  5. Réponses: 4
    Dernier message: 18/04/2004, 13h36

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