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

Windows Forms Discussion :

Comment interrompre une tâche ?


Sujet :

Windows Forms

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 20
    Par défaut Comment interrompre une tâche ?
    Bonjour

    J'ai une tache à effectuer avec tout plein de calculs longs et fastidieux.
    J'ai une "ProgressBar" que je mets à jour régulièrement et un bouton "Arrêter" qui pour l'instant ne sert à rien (et c'est bien là le problème).

    Comment puis-je interrompre ma tache avec ce bouton alors que le système et occupé à faire des tas de calculs et ne voit pas que j'ai appuyé sur le bouton ?

    Quelqu'un aurait une solution ?

    Merci d'avance

    kwAz

  2. #2
    Expert confirmé
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Par défaut
    cherche sur le net des cours sur le BackgroundWorker.
    D'ailleurs, il y a un cours sur dvp :
    http://glarde.developpez.com/dotnet/bgworker/

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 20
    Par défaut
    Pas sûr que ce lien m'aide beaucoup (A moins que quelque chose m'ais échappé) :
    Je ne veux pas paralléliser mes calculs, je veux pouvoir les interrompre avec un bouton.

    D'autres propositions ?

    Merci d'avance

    kwAz

  4. #4
    Expert confirmé
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Par défaut
    Mais oui mais oui, ça pourrai marcher
    Dans ton thread principal tu attend tranquillement le backgroundWorker et tu utilise une variable globale genre "isCancelled" que tu met à true lors de l'appui sur le boutton "Annuler". Dans ton code que tu utilises pour faire ton calcul, tu vérifie à chaque étape la valeur de isCancelled et tu arretes tout si isCancelled = true.

    L'autre méthode c'est de créer toi même le thread ( avec System.Threading.Thread ) et de faire un bon vieux Thread.Abort à l'appui du boutton "Annuler" ... mais c'est pas très élégant ...

  5. #5
    Membre très actif
    Avatar de Cyrilange
    Profil pro
    Inscrit en
    Février 2004
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 268
    Par défaut
    Apparament tu ne veux pas arrêter tes calculs, tu veux juste les mettre en pause c'est ça ?

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Par défaut
    Salut,

    si tu veux juste interrompre (pause) tes calculs pour pouvoir les continuer plus tard, un ManualResetEvent fera le job, en le placant dans ton code de facon à ce qu'il soit souvent controlé. Tu le reset quand tu veux pauser et tu le signales quand tu veux reprendre.

    Si tu veux interrompre totalement les calculs (terminer le thread), tu peux soit inspecter un booleen si les calculs sont iteratifs (cas le plus simple, si ton code ne l'est pas, tu devras trouver un moyen d'inspecter cette variable regulierement, pour donner de la "reactivité" au cancel), ou alors, en dernier recours, appeler un Thread.Abort() (ce qui exclut l'utilisation de BGW ou du pool), mais attention aux consequences !

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 20
    Par défaut
    Bonsoir

    J'ai lu attentivement le lien de smyley sur les BackgroundWorker. Je n'ai pas tout compris (désolé, encore débutant) et je ne vois pas comment l'adapter à mon code que je vais tenter d'expliciter :

    Tout se passe dans mon interface principale (et, si possible, je ne voudrais pas devoir ouvrir une autre fenêtre), dans laquelle j'ai une bar de progression "ProgressBar" et un bouton "QuitterBtn" (à double fonctions). La tache que je souhaite accomplir est déclenchée par un MenuItem dont voici le code (simplifié) :

    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
       Private Sub ElaguerToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ElaguerToolStripMenuItem.Click
            Dim m(8, 8) As Byte
            Dim n As Byte
     
            m=getmat() 'récupération de valeurs dans l'interface
            Me.QuitterBtn.Text = "Arrêter"
            Me.ProgressBar.Visible = True
            Me.ProgressBar.Value = 0
            Me.Refresh()
     
            'Traitements 1
     
            For n = 0 To 80
                Me.ProgressBar.Value = n
                Me.ProgressBar.Refresh()
     
                m=elaguer(m,n) 'gros traitement 2 qui prend jusqu'à 3 secondes
     
                Me.Refresh 'mise à jour de l'interface suite à traitement 2
                If Me.QuitterBtn.Text = "Quitter" Then
                    Exit For
                End if
            Next
     
            'Traitements 3
     
            Me.ProgressBar.Visible = False
            Me.QuitterBtn.Text = "Quitter"
        End Sub
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
       Private Sub QuitterBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles QuitterBtn.Click
            If Me.QuitterBtn.Text = "Quitter" Then
                Me.Close()
            Else
                Me.QuitterBtn.Text = "Quitter"
                Me.QuitterBtn.Refresh()
            End If
        End Sub
    Normalement, lorsque j'appuie sur QuitterBtn, son ".Text" devrait passer de "Arrêter" à "Quitter" et donc devrait déclencher la sortie de ma boucle "for n = 0 to 80". Mais QuitterBtn n'est plus accessible. Il ne se passe rien, ou pire, cela met mon application dans le mode "Ne reponds plus" et plus rien ne se met à jour dans l'interface. Les calculs continuent jusqu'à leur terme ou je retrouve enfin la main.

    Par rapport au lien de smyley, je n'ai pas bien compris ce que, dans mon code, je devais passer en BackgroundWorker et surtout comment.

    Si quelqu'un avait la patience de m'expliquer, ce serai vraiment sympa. Toutefois, j'aimerais autant que possible conserver la structure actuelle de mes traitements (1 à 3) et les laisser dans ma Sub "ElaguerToolStripMenuItem".

    Merci d'avance

    kwAz

  8. #8
    Membre très actif
    Avatar de Cyrilange
    Profil pro
    Inscrit en
    Février 2004
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 268
    Par défaut
    Tout d'abord, il faut faire un Import System.ComponentModel

    Et ton code devrait ressembler à ça :

    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
     
    Private WithEvents bgw As BackgroundWorker
     
    Private Delegate Function dElaguer(ByVal m As Byte, ByVal n As Byte) As Byte
    Private Delegate Function dGetmat() As Byte
     
    Private Sub ElaguerToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ElaguerToolStripMenuItem.Click
     
            Me.QuitterBtn.Text = "Arrêter"
            Me.ProgressBar.Visible = True
            Me.ProgressBar.Value = 0
            Me.startBgw()
     
    End Sub
     
    Private Sub startBgw()
     
            bgw = New BackgroundWorker
            bgw.WorkerReportsProgress = True
            bgw.WorkerSupportsCancellation = True
     
            bgw.RunWorkerAsync()
    End Sub
     
    Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgw.DoWork
     
            Dim m(8, 8) As Byte
            Dim n As Byte
     
            dElaguer = New dElaguer(AddressOf elaguer)
            dGetmat = New dGetmat(AddressOf getmat)
     
            m = dGetmat()
     
            For n = 0 To 80
                bgw.ReportProgress(n)
                m = dElaguer(m, n) 'gros traitement 2 qui prend jusqu'à 3 secondes
                If bgw.CancellationPending Then
                    Exit For
                End If
            Next
     
    End Sub
     
    Private Sub bgw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
            Me.ProgressBar.Visible = False
            Me.QuitterBtn.Text = "Quitter"
    End Sub
     
    Private Sub bgw_progress(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgw.ProgressChanged
            Me.ProgressBar.Value = e.ProgressPercentage
    End Sub
     
    Private Sub QuitterBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles QuitterBtn.Click
     
    If Me.QuitterBtn.Text = "Quitter" Then
                Me.Close()
            Else
                bgw.CancelAsync()
    End If
     
    End Sub
    Je pars du principe que la MaxValue de ta ProgressBar est de 80.

    Et tu n'as acun besoin de faire des Refresh. Ton interface restera fluide.

    J'utilise des Delegates pour appeller getmat et elaguer . En faite il faut toujours veiller à ce que le code à l'intérieur du Thread (DoWork) ne fasse aucun appel direct à une méthode extérieur au Thread.

    Comme ta méthode elaguer prend 3 secondes pour s'éxécuter, si l'utilisateur clique sur "Arrêter", cela prendra 1 à 3 secondes pour que le Thread s'arrête et que le bouton affiche de nouveau "Quitter". Si tu veux éviter ça, il faut que le code de ta méthode elaguer soit dans le DoWork pour pouvoir surveiller lors de son éxécution la propriété CancellationPending .

    Je ne l'ai pas testé mais en gros c'est ça

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 20
    Par défaut
    Merci beaucoup, Cyrilange

    J'essaye et je te tiens au courant.

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 20
    Par défaut
    Bon, c'était pas évident, mais ça marche.

    En fait, je me suis un peu emmélé. J'ai tenté de recoder comme me le conseillait Cyrilange, mais ça n'a pas marché, tout simplement parce que j'avais conservé mon ancien code (que j'avais renommé en me disant qu'il ne serait plus exécuté). Seulement, je n'avais pas changé le handle ElaguerToolStripMenuItem.Click, et donc il s'executait toujours, mais ça, je ne m'en suis rendu compte que bien après.

    Malgré tout, les conseils de Cyrilange m'ont permis de comprendre le lien de Smyley. J'ai tout recodé comme dans le lien. Ca ne marchait toujours pas. Et là, je me suis rendu compte de mon erreur (ancien code qui fonctionnait toujours). Je l'ai supprimé, et, ô miracle, ça marche !!! Youpi !!!

    Merci à tous

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

Discussions similaires

  1. MS Project - Comment définir une tâche insécable?
    Par TomTom29 dans le forum Project
    Réponses: 0
    Dernier message: 29/04/2008, 17h44
  2. Réponses: 1
    Dernier message: 17/04/2008, 16h57
  3. Comment spécifier une tâche cron ?
    Par Nibor dans le forum Administration système
    Réponses: 8
    Dernier message: 07/11/2007, 00h03
  4. Comment planifier une tâche avec MS SQL SERVER ?
    Par cadabricadabra dans le forum MS SQL Server
    Réponses: 11
    Dernier message: 18/07/2007, 16h40
  5. Comment ajouter une tâche a chaque selection
    Par niCo.nb dans le forum C
    Réponses: 2
    Dernier message: 01/11/2005, 17h26

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