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 :

ProgressBar et Fonction


Sujet :

GTK+ avec C & C++

  1. #1
    Membre averti
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2011
    Messages : 34
    Par défaut ProgressBar et Fonction
    Bonjour après 2 jours de recherche infructueuse je me décide à demander de l'aide....

    Voici mon problème :

    Je désire suivre l'évolution d'une fonction par le biais d'une ProgressBar, la fonction en question est complètement externe à GTK, elle fait partie d'une de mes bibliothèque et peut être modifiée à ma guise.

    Pour lancer cette fonction j'utilise un bouton (dans ma fenetre principale), sont callback me permet de lancer une nouvelle fenêtre qui affiche la barre de progression et la fonction.

    Ma question est comment faire en sorte que ma fonction retourne régulièrement une valeur pour que la progressbar évolue ?

    J'ajoute un peu de code, en espérant que sa pourra aider à comprendre se que je veux faire.

    <CModule.h>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    ///  declarations ....
    class CModule {
    protected:
    public:
          int m_iAvancement; 
          bool Fonction(data) ;
          bool ComputeAff(data);
          bool Compute(data);
    }
    <CModule.cpp>
    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
     
    ///  declarations ....
    bool ComputeAff(gpointer data)
    {
       ///// data une structure contenant  des pointeurs sur différents parametres et des Widget
       // La Fenetre
       data->pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
       gtk_window_set_title(GTK_WINDOW(data->pWindow), "GtkProgressBar");
       gtk_window_set_default_size(GTK_WINDOW(pWindow), 320, 100);
       gtk_container_set_border_width(GTK_CONTAINER(data->pWindow), 4);
       // Le decoupage vertical
       GtkWidget * pMainVBox = gtk_vbox_new(TRUE, 0);
       gtk_container_add(GTK_CONTAINER(pWindow), pMainVBox);
       /* Creation de la barre de progression Principale*/
       data->pProgressP = gtk_progress_bar_new();
       gtk_box_pack_start(GTK_BOX(pMainVBox), data->pProgressP, TRUE, FALSE, 0);
       g_signal_connect(G_OBJECT(data->pWindow), "show",  G_CALLBACK(Compute), (gpointer*)data);
      gtk_widget_show_all(data->pWindow);
      gtk_main();
      return TRUE;
     }
     
    bool Compute (gpointer data)
    {
    ///// data une structure contenant  des pointeurs sur différents parametres et des Widget
     
    //// Initialisation de la progressbar (pas de pb)
     
    // Je veux lancer ma fonction
    CModule  core_module;
    core_module.m_iAvancement=0;  //fixe avancement à zéro et au cours de la fonction Avancement évolue.
     
    core_module. bool Fonction(data); // lancement de la function
     
    //// Comment faire évoluer la progressbar ?????
     
    }


    <Main.cpp>
    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
     
    ///  declarations ....
     
    void Callback_Lancement (GtkWidget* widget, gpointer data)
    {
         // Relayage vers FONCTION
         CModule().Compute(data);
    }
     
    void main()
    {
        /*********************
        * Initialisation GTK *
        *********************/
         //Init du multithreading
         if(!g_thread_supported())
             g_thread_init(NULL);
     
         //Init le multithreading pour GDK
         gdk_threads_init();
     
         //Zone critique du thread pour le programme principal
         gdk_threads_enter();
     
         /***************************
        * L'application principale *
        ***************************/
         //Taille de la fenetre principale
         int m_nSizeX = 200; int m_nSizeY = 100;
         //Cree la fenêtre
         GtkWidget* m_pWindowSecondaire = gtk_window_new(GTK_WINDOW_TOPLEVEL);
         p_struc_gtkpointer->p_Widget1 = m_pWindowSecondaire;
         //Fixe la taille de la fenêtre
         gtk_window_set_default_size(GTK_WINDOW(m_pWindowSecondaire),m_nSizeX,m_nSizeY);
         //Fixe l'affichage de la fenêtre au centre
         gtk_window_set_position(GTK_WINDOW(m_pWindowSecondaire),GTK_WIN_POS_CENTER);
         // Contenaire et ajout a la fenetre
         GtkWidget* m_pV = gtk_vbox_new(FALSE,0);
         gtk_container_add(GTK_CONTAINER(m_pWindowSecondaire),m_pV);
     
        ///// DIVERS WIDGET de RéGLAGES
     
         /// Boutton APPLIQUER
         GtkWidget* pApply=gtk_button_new_from_stock(GTK_STOCK_EXECUTE);
         gtk_box_pack_start(GTK_BOX(m_pV),pApply,FALSE,FALSE,0);
         /// Lance calcul 
         g_signal_connect(G_OBJECT(pApply),"clicked",G_CALLBACK(Callback_Lancement),(gpointer*)data);
     
         //Affichage principal
         gtk_widget_show_all(m_pWindowSecondaire);
         //Entre dans la boucle infinie
         gtk_main();
         //Fin de la zone critique du thread du programme principal
         gdk_threads_leave();
    }

  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
    Fonction (data); doit obligatoirement être capable de donner une information en temps réel sur sa progression si tu tiens à avoir une valeur de la barre de progression précise.

    Si Fonction (data); ne peut pas le faire tu peux simplement utiliser la barre de progression en mode automatique. La barre se déplace de gauche à droite indéfiniment tant que tu ne la détruit pas.

    Quelque soit la solution choisie le principe est d'utiliser g_timeout_add(); (ou dérivée) pour ajouter une fonction annexe à la boucle principale Gtk. Cette fonction annexe gère exclusivement la barre de progression. Avec cette méthode ton interface n'est pas figée. Tu pourras donc interrompre l'exécution de Fonction (data); à tout moment (ou autre chose...).

  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 gerald3d Voir le message

    Quelque soit la solution choisie le principe est d'utiliser g_timeout_add(); (ou dérivée) pour ajouter une fonction annexe à la boucle principale Gtk. Cette fonction annexe gère exclusivement la barre de progression. Avec cette méthode ton interface n'est pas figée. Tu pourras donc interrompre l'exécution de Fonction (data); à tout moment (ou autre chose...).
    Hop hop hop, tu vas un peu vite. Si sa fonction est une fonction qui a un temps d'exécution non négligeable, alors g_timeout_add ou ses dérivés ne fonctionnera tout bonnement pas, il sera obligé de passer par un thread. Tout traitement effectué dans des callbacks bloque la pompe à événements de GTK. Pour s'en rendre compte, il suffit de faire un appel à sleep(5) par exemple, pour simuler une fonction qui met 5 secondes à s'exécuter et rendre la main. Le thread principal gère l'interface graphique, donc si tu le bloques pendant 5 secondes, ton application est figée. S'il n'y a pas de variante asynchrone à sa fonction, il est obligé d'utiliser un thread.

  4. #4
    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 liberforce Voir le message
    Hop hop hop, tu vas un peu vite. Si sa fonction est une fonction qui a un temps d'exécution non négligeable, alors g_timeout_add ou ses dérivés ne fonctionnera tout bonnement pas, il sera obligé de passer par un thread. Tout traitement effectué dans des callbacks bloque la pompe à événements de GTK. Pour s'en rendre compte, il suffit de faire un appel à sleep(5) par exemple, pour simuler une fonction qui met 5 secondes à s'exécuter et rendre la main. Le thread principal gère l'interface graphique, donc si tu le bloques pendant 5 secondes, ton application est figée. S'il n'y a pas de variante asynchrone à sa fonction, il est obligé d'utiliser un thread.
    Oui tout à fat d'accord Liberforce . Je ne cherchais qu'à apporter une première solution généraliste. Maintenant si son process est gourmand en temps, un passage par les threads sera nécessaire.

  5. #5
    Membre averti
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2011
    Messages : 34
    Par défaut
    Merci de vous intéresser à mon problème. Effectivement le passage par les threads me parait obligatoire car la fonction peut durer plusieurs minutes. Par contre je ne vois pas comment m'y prendre les tutos ne sont pas nombreux ....

    J'ai essayé cette méthode :

    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
     
    bool Compute (gpointer data)
    {
    ///// data une structure contenant  des pointeurs sur différents parametres et des Widget
     
    //// Initialisation de la progressbar (pas de pb)
     
    // Je veux lancer ma fonction dans un thread
     
    g_thread_init (NULL);
    GThread          *Thread1;
    char *message1 = "Thread 1";
    GError           *err1 = NULL ;
     
    if( !g_thread_supported() )
    {
        g_thread_init(NULL);
        gdk_threads_init();                
        printf("g_thread supported\n");
    }
    else
    {
        printf("g_thread NOT supported\n");
    }
     
     
    CModule  core_module;
    core_module.m_iAvancement=0;  //fixe avancement à zéro et au cours de la fonction Avancement évolue.
     
    if( (Thread1 = g_thread_create((GThreadFunc) core_module.Fonction(data),  (void *)message1, TRUE, &err1)) == NULL)
    {
        printf("Thread create failed: %s!!\n", err1->message );
        g_error_free ( err1 ) ;
    }
     
    g_thread_join(Thread1);
     
     
    //// Comment faire évoluer la progressbar ?????
     
    }
    Le premier problème, à l'exécution j'ai systématiquement "g_thread NOT supported" ??

    Ensuite, malgré tout la fonction est lancé mais plante au bout d'une petit moment. (Lors de l’exécution de : g_thread_join(Thread1)

    De plus je ne sait toujours pas comment récupérer en même temps la variable Avancement n'i mettre à jours m'a progressbar.

  6. #6
    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
    Tout d'abord g_thread_init(); n'est plus nécessaire :
    The GLib threading system used to be initialized with g_thread_init(). This is no longer necessary. Since version 2.32, the GLib threading system is automatically initialized at the start of your program, and all thread-creation functions and synchronization primitives are available right away.
    Ensuite il faut bien faire attention lorsqu'on manipule des threads. Les variables globales sont automatiquement boquées lors de leur accession à contrario des variables locales. message1 par exemple peut poser problème. L'utilisation des GMUTEX devient alors obligatoire.

    En utilisant un debogueur (gdb par exemple) tu pourrais avoir une information plus fine sur le lieu où le crash se produit.

  7. #7
    Membre averti
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2011
    Messages : 34
    Par défaut
    Voici le rapport de debug obtenu avec CodeBlock : Call Stack

    #0 00000000 0x00000077 in ??() (?? : ??)
    #1 65C42050 g_thread_proxy@4() (C:\CodeBlocks\MinGW\bin\libgthread-2.0-0.dll : ??)
    #2 75EA1287 msvcrt!_itow_s() (C:\Windows\system32\msvcrt.dll : ??)
    #3 75EA1328 msvcrt!_endthreadex() (C:\Windows\system32\msvcrt.dll : ??)
    #4 760BED6C KERNEL32!AcquireSRWLockExclusive() (C:\Windows\system32\kernel32.dll : ??)
    #5 7739377B ntdll!RtlInsertElementGenericTableAvl() (C:\Windows\system32\ntdll.dll : ??)
    #6 7739374E ntdll!RtlInsertElementGenericTableAvl() (C:\Windows\system32\ntdll.dll : ??)
    #7 00000000 0x00000000 in ??() (?? : ??)

    Je sais pas trop a quoi sa correspond c'est la première fois que j'utilise le debugage.....

    De plus j'ai supprimé message1 (remplacé par NULL dans g_thread_create) mais aucun changement.

  8. #8
    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
    hum...pas très explicite en effet.

    Lorsque tu crées le thread l'affichage "Thread create failed:..." apparaît-il en console? Si oui ton code risque d'avoir un comportement hasardeux. Une fois l'affichage de l'erreur fait ton code poursuit et passe à la fonction g_thread_join (Thread1);.

    Pour continuer sur ton problème tu pourrais commencer par threader une fonction vide, histoire de t'assurer que le problème vient bien de la gestion des threads et non de la fonction threadée.

  9. #9
    Membre averti
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2011
    Messages : 34
    Par défaut
    Non, le message "Thread create failed: " n'apparait pas dans la console, la fonction ne pose aucun problème d'exécution sans thread, pour vérifié j'ai testé avec une fonction vide et toujours le même problème :

    - plantage lors de l'instruction : g_thread_join(Thread1);

    De plus je ne comprend pas bien à quoi sert cette instruction ?

  10. #10
    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
    Lorsque tu lances un thread tu as deux manières de le gérer:
    1. le thread s'éxécute pendant que ton application continue son propre processus,
    2. ton application attend que le thread se termine pour poursuivre sa propre exécution.

    g_thread_join(); te permet d'attendre la fin du thread. C'est donc la deuxième solution que tu as choisi.

    En écrivant ces lignes j'ai repris la documentation officielle. g_thread_create(); est obsolète. il faut utiliser g_thread_new(); (ou g_thread_try_new();) à la place.
    Pendant qu'on y est le prototype du thread à respecter est de la forme : gpointer (*GThreadFunc) (gpointer data);

    Lorsque le thread se termine il renvoie une valeur quelconque que tu peux réceptionner grâce à la fonction gpointer g_thread_join();.

  11. #11
    Membre averti
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2011
    Messages : 34
    Par défaut
    Merci pour votre aide, je n'utilisais pas correctement le prototype du thread maintenant le tout fonctionne correctement.
    Pour ceux qui serai un peu perdu comme je l'était il suffit de penser que l'appelle des threads est quasi identique à des appels de CallBacks (arretez moi si je dit des anneries), pour mon cas j'appel le thread et je fait un relais vers ma propre fonction.


    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
     
    gpointer GThreadFunc_Compute(gpointer data)
    {
       std::cout<<"Lancement du Thread : GThreadFunc_Compute"<<std::endl;
       // Gestion du pointeur data;
       MaFonction(data);
    }
     
    void main()
    {
     
           //////// AUTRE
     
            //Creation d'un thread de calcul
            GThread *Thread1;
            //Lancement du thread de calcul
            if( (Thread1 = g_thread_create_full(GThreadFunc_Compute,(gpointer) data,0,TRUE,TRUE,G_THREAD_PRIORITY_NORMAL,NULL))==NULL)
               std::cout<<"Error : Thread (Compute) create failed : !!" <<std::endl;
            else
               std::cout<<"Thread (Compute) create success" <<std::endl;
     
                //boucle tant que le calcul n'est pas fini
            while(Avancement de la fonction < Total de la fonction){
               /* Getion d'une progress bar */
              Mise à jour de la progressBar;
               CCallBackWindowsFonction().StrucProgressBarMaJS(p_struc_progressbar);}
     
            //Attente du thread
    	    g_thread_join(Thread1);
     
           //////// AUTRE
     
    }

    Pour ce qui est de la ProgressBar "MaFonction" met à jours au cours de sont exécution 1 variable "Avancement" et lors de sont lancement "Total" il suffit d'observer ces variables et de mettre à jour la progressBar parallèlement à l’exécution de"MaFonction".


    Je ne sais pas si mes explications sont très clair ... mais j'espère que sa pourra peut être servir à quelqu'un.

  12. #12
    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
    Content qu'enfin tu es résolu ton problème.

    Histoire d'ajouter un point de précision temps qu'on ne fait que lire des données partagées, ici Avancement et Total, on peut se passer des mutex. Si par contre deux threads écrivent sur les mêmes variables il faudra alors en bloquer l'usage lors de cette opération par le thread concerné.

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

Discussions similaires

  1. afficher une ProgressBar pour une fonction
    Par bullrot dans le forum C#
    Réponses: 6
    Dernier message: 06/06/2012, 11h15
  2. Réponses: 1
    Dernier message: 19/01/2010, 14h48
  3. Réponses: 1
    Dernier message: 14/04/2008, 11h23
  4. Réponses: 1
    Dernier message: 13/04/2008, 14h53
  5. [MFC] fonction Create d'une ProgressBar
    Par lastcheper dans le forum MFC
    Réponses: 10
    Dernier message: 20/05/2005, 15h20

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