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

Qt Discussion :

Faire une pause dans mon programme sans geler toute la fenêtre


Sujet :

Qt

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mai 2015
    Messages : 13
    Points : 13
    Points
    13
    Par défaut Faire une pause dans mon programme sans geler toute la fenêtre
    Bonjour à tous et bonne année !

    J'ai fais un petit projet en C++ permettant de contrôler deux trains électriques.
    J'ai entièrement codé mon programme avec QT Creator et je suis sous Linux.
    J'aimerai mettre un sleep dans mon code afin que la vitesse du train diminue progressivement mais même en mettant sleep(1); cela bloque le programme.
    De plus je voudrais qu'il soit possible de pouvoir utiliser les autres fonctions du programme pendant que la boucle tourne.
    Pour faire ça dois-je passer par le multi-threading ?...

    J'espère avoir été assez clair et vous remercie d'avance

    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
     
    connect(Arret2, SIGNAL(clicked()), this, SLOT(ActionArret2()));
     
    void FenPrincipale::ActionArret2()
    {
          Arret2->setPalette(QPalette(QColor(0, 255, 0, 255)));
          Marche2->setPalette(QPalette(QColor(255, 255, 255, 255)));//Blanc
          if (ADauto2->isChecked()==true)
          {
              int vitesse2 = slider2->value();
              for(vitesse2 ; vitesse2>=0 ; vitesse2--)
              {
                  sleep(1);
                  slider2->setSliderPosition(vitesse2);
              }
          }
    }

  2. #2
    Membre émérite
    Avatar de ymoreau
    Homme Profil pro
    Ingénieur étude et développement
    Inscrit en
    Septembre 2005
    Messages
    1 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur étude et développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 154
    Points : 2 834
    Points
    2 834
    Par défaut
    Plutôt que faire une boucle avec un sleep pour espacer les pas de boucle, tu peux utiliser QTimer. Le principe est d'activer un slot au bout d'un temps donné, et tu peux également faire ça en boucle, cad appeler ton slot tous les 500ms (comme une boucle avec un sleep de 500ms). De cette façon pendant que ton slot "attend" d'être appelé par le QTimer le programme continue de s'exécuter et n'est pas gelé. De manière générale il vaut mieux éviter les sleep, et d'autant plus dans le thread principal de Qt (qui gère la boucle d'évènements).

    Tu auras besoin de faire du multithread si le code que tu exécutes est long, cad assez long pour que l'utilisateur veuille faire une action alors que l'exécution de ta fonction n'est pas terminée (vu que la fenêtre est gelée pendant ce temps là).

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mai 2015
    Messages : 13
    Points : 13
    Points
    13
    Par défaut
    Merci de ta réponse
    Si je comprends bien en passant par QTimer ainsi que ta méthode l'utilisateur aura en quelques sortes 500 ms pour effectuer une action avant que le programme ne le blogue pour effectuer son action et ainsi de suite.... ?

    En texte cela voudrais dire:



    tout le programme
    tant que vitesse !=0 et slotactif->Au bout de 500ms va au slot baisse vitesse de 1.
    slot: slotactif;
    si vitesse!=0 baisse vitesse de 1->vitesse--
    si vitesse==0 et slotactif->slotnonactif
    return vitesse slotactif;

    Tu auras besoin de faire du multithread si le code que tu exécutes est long, cad assez long pour que l'utilisateur veuille faire une action alors que l'exécution de ta fonction n'est pas terminée
    La fonction correspond à mon slot ?


    C' est un peu flou tout ça...
    Je pense qu'il serait plus judicieux d'utiliser le multi thread en espérant que ça soit à ma porté...de plus ça me permettrait de faire plein d'autre choses !
    Dans mon thread je pourrai alors utiliser mon sleep sans geler le programme

  4. #4
    Membre émérite
    Avatar de ymoreau
    Homme Profil pro
    Ingénieur étude et développement
    Inscrit en
    Septembre 2005
    Messages
    1 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur étude et développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 154
    Points : 2 834
    Points
    2 834
    Par défaut
    A partir du moment où tu exécutes du code dans le thread principal, ce code gèle ta fenêtre. Mais quand il s'agit de temps très court l'utilisateur ne le voit même pas. Quand tu cliques sur un bouton par exemple, le signal est émis, un slot peut être exécuté qui changera un texte ou ouvrira une boîte de dialogue. Tout ce code là est tellement rapide que l'utilisateur n'est pas gêné. A moins que tu aies un gros calcul à faire tu n'as pas besoin du multithread, et dans tous les cas tu n'as pas besoin du sleep. D'autant plus que les widgets ne doivent pas être modifiés depuis un autre thread, dans ton cas tu mets à jour un slider par exemple.

    Un slot est une fonction C++ oui (méthode pour être précis), qui peut en plus être invoqué par Qt par le système signal/slot.

    Avec un fonctionnement évènementiel tu n'as plus de "tant que" dans ton algo. C'est moins facile à comprendre et décrire car ton code ne se déroule pas en un fil linéaire mais une succession d'évènements.
    En résumé quand tu veux commencer à ralentir ton train tu démarres le QTimer, il se chargera ensuite d'appeler ton slot à intervalle régulier mais entre les deux il peut arriver d'autres évènements (clic souris etc), ton slot lui se contente de mettre à jour ce qu'il faut (décrémenter la vitesse, mettre à jour les widgets concernés). Une fois que tu as atteint la vitesse 0 tu stoppe le QTimer.

    constructeur de FenPrincipale :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    m_timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(ralentirTrain()));
    fonctions de FenPrincipale :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void FenPrincipale::ActionArret2()
    {
        ...
        m_timer->start(1000); // Chaque seconde
    }
     
    void FenPrincipale::ralentirTrain()
    {
        int vitesse2 = slider2->value() - 1;
        if (vitesse2 > 0)
            slider2->setValue(vitesse2);
        else
            m_timer->stop();
    }

  5. #5
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mai 2015
    Messages : 13
    Points : 13
    Points
    13
    Par défaut
    Alors là !
    Tes explications sont claires et j'ai tout compris !
    En plus le code que tu m'as donné me permet de voir comment je vais pouvoir adapter ça à mon programme
    Effectivement dans mon cas je n'ai pas besoin de passer par du multi-thread.

    Cependant j'aurai une dernière question histoire d'être sur que je fais bien les choses. Du moins un peu près

    Dans ma FenPrincipal j'ai le menu programmation qui ouvre une nouvelle fenêtre.
    Dans cette fenêtre l'utilisateur pourra programmer les actions d'un train sur une durée T.
    Cette méthode va t'elle geler ma FenPrincipale ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    connect(actionProgrammation, SIGNAL(triggered()), this, SLOT(Programmation()));
    void FenPrincipale::Programmation()     //ouvrir fenetre programmation
    {
            FenProgrammation * fenetreprogrammation = new FenProgrammation;
            fenetreprogrammation->show();
    }
    Et FenProgrammation:
    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
    m_timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(Faire2Tours()));
    void FenPrincipale::ActionArret2()
    {
        ...
        m_timer->start(Durée); // Valeur définie par l'utilisateur
     
    void FenPrincipale::Faire2Tours()
    {
        int minuteur = minuteur- 1;
        if (minuteur > 0)
            minuteur--;
        else
            m_timer->stop();
    }

  6. #6
    Membre émérite
    Avatar de ymoreau
    Homme Profil pro
    Ingénieur étude et développement
    Inscrit en
    Septembre 2005
    Messages
    1 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur étude et développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 154
    Points : 2 834
    Points
    2 834
    Par défaut
    Comme je le disais ton interface sera gelée quand du code s'exécute, que ça soit la fenêtre principale ou une boite de dialogue, tout se passe dans le même thread.

    Pour les boites de dialogue, il faut distinguer les boites modales (bloquant l'accès à la fenêtre principale tant qu'elles sont ouvertes) et les non modales. En utilisant show tu es par défaut en mode non-modal, l'utilisateur peut faire des actions sur les deux fenêtres en même temps. Pour lancer en mode modal on utilise exec au lieu de show, le code devient bloquant (tu ne passes pas à l'instruction suivante tant que la boite de dialogue n'est pas fermée).
    Au passage, tu crées FenProgrammation sans lui donner de parent, ce qui est recommandé pour qu'elle s'affiche au centre de ton application. Et j'ai l'impression que tu oublies de faire un delete, tu auras donc une fuite mémoire à chaque fois que tu crées-puis-ferme ta boite de dialogue.

  7. #7
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mai 2015
    Messages : 13
    Points : 13
    Points
    13
    Par défaut
    En effet je n'ai pas mis de delete. Je vais en mettre un ainsi que mettre FenPrincipale en parent.

    Merci pour toutes ces explications.

  8. #8
    Membre éclairé Avatar de Matthieu76
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Mars 2013
    Messages
    568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2013
    Messages : 568
    Points : 890
    Points
    890
    Par défaut re
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void MainWindow::sleep(int time)
    {
        dieTime = QTime::currentTime().addMSecs(time);
        while (QTime::currentTime() < dieTime)
            QCoreApplication::processEvents(); // (QEventLoop::AllEvents, 100)
    }
    De mon côté, j'utilise cette fonction sleep qui redonne la main à l'interface de mon appliquation pendant son appel.

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

Discussions similaires

  1. Réponses: 9
    Dernier message: 18/12/2009, 00h36
  2. Faire une pause dans un programme
    Par jorg1n dans le forum C
    Réponses: 1
    Dernier message: 12/11/2007, 12h02
  3. Réponses: 18
    Dernier message: 07/06/2007, 18h43
  4. Faire une pause dans le programme
    Par shinobi dans le forum Access
    Réponses: 6
    Dernier message: 13/06/2005, 16h37
  5. [] Utiliser AVI d'une DLL dans mon programme
    Par seb.49 dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 02/05/2003, 14h52

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