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

VB.NET Discussion :

Formulaire pour afficher la progression d'un processus externe. [Débutant]


Sujet :

VB.NET

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Par défaut Formulaire pour afficher la progression d'un processus externe.
    Bonsoir à tous,
    J'ai écris un programme pour convertir des vidéos avec ffmpeg.exe et j'ai enfin réussi à lire les messages de sorties de ce processus. Le but est d'afficher la progression sur un formulaire "frmProgress" spécialement dédié à cet usage.

    Problème :
    1- J'arrive à afficher les messages de sorties dans la fenêtre Debug de Visual Studio mais je n'ai rien qui s'affiche dans mon formulaire frmProgress qui contient un RichTextBox.
    2- Quelle est la méthode la plus propre pour passer les paramètres de progression à mon formulaire ?. Pour l'instant j'ecrits directement dans le RichTextBox pour faire des essais, par la suite je ferais une barre de progression + un label calculé à partir de la chaine de caractére retournée (voir ci-dessous).
    3- Le processus me retourne un string toute les secondes environ du style :
    "frame= 4169 fps= 81 q=39.0 size= 10513kB time=00:01:22.74 bitrate=1040.8kbits/s dup=2134 drop=0". Je pense faire une analyse cette chaine de caractère pour extraire la valeur 'frame' ou 'time' qui me servira d'indication de progression, la sortie se compose egalement d'autres chaines de caractères qui retourne par exemple quelques lignes d'erreurs (je vais devoir ignorer les chaines qui commence par Error:.....) est ce que c'est bien comme cela que l'on procède habituellement concernant ce principe d'extraction des infos de progression ?

    Le code exécuté dés que je lance la conversion depuis le formulaire principal :
    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
        Private Sub ShellExecute(ByVal ExeFile As String, CommandLine As String)
     
            Dim MonProcess As New Process
            AddHandler MonProcess.OutputDataReceived, AddressOf OutputDataReceived
            AddHandler MonProcess.ErrorDataReceived, AddressOf ErrortDataReceived
     
            MonProcess.StartInfo.FileName = ExeFile
            MonProcess.StartInfo.Arguments = CommandLine
            'MonProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized
            MonProcess.StartInfo.CreateNoWindow = True        ' True
            MonProcess.StartInfo.UseShellExecute = False      ' False
            MonProcess.StartInfo.RedirectStandardOutput = True
            MonProcess.StartInfo.RedirectStandardInput = True
            MonProcess.StartInfo.RedirectStandardError = True
     
            MonProcess.Start()
     
            frmProgress.Show()
            MonProcess.BeginOutputReadLine()
            MonProcess.BeginErrorReadLine()
     
     
            MonProcess.WaitForExit()
            MonProcess.Close()
        End Sub
    Les évenements pour capturer la sortie du processus :
    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
     
        Private Sub OutputDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            Try
                frmProgress.RichTextBox1.Text += e.Data.ToString
                frmProgress.RichTextBox1.Text += Environment.NewLine
                Debug.Print(e.Data.ToString)
            Catch ex As Exception
     
            End Try
     
        End Sub
     
        Private Sub ErrortDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            Try
                frmProgress.RichTextBox1.Text += e.Data.ToString
                frmProgress.RichTextBox1.Text += Environment.NewLine
                Debug.Print(e.Data.ToString)
            Catch ex As Exception
     
            End Try
     
        End Sub
    Merci à tous pour votre aide.

  2. #2
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Par défaut
    Bonsoir j'ai progressé sur les points 2 et 3 mais j'ai toujours le problème pour l'affichage sur mon formulaire de progression.
    Voici le message que j'obtiens sur la ligne : frmProgress1.CurrentValue += 1
    AccessibilityObject = {"Opération inter-threads non valide*: le contrôle 'RichTextBox1' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé."}

    Pour info j'ai modifié le code comme ceci et j'ai instancié frmProgress1 dans le module 'main' de démarrage de l'application :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
        Private Sub ErrorDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            Try
                frmProgress1.CurrentValue += 1   ' Incremente de 1 pour tester l'affichage
                Debug.Print(e.Data.ToString)
            Catch ex As Exception
     
            End Try
     
        End Sub
    Le Code du formulaire de progression :
    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
    Public Class frmProgress
        Private _CurrentValue As Integer
        Private _MaxValue As Integer
     
        Sub New()
            ' Cet appel est requis par le concepteur.
            InitializeComponent()
     
            ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
        End Sub
        Sub New(ByVal CurrentValue As Integer, ByVal MaxValue As Integer)
     
            ' Cet appel est requis par le concepteur.
            InitializeComponent()
     
            ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
            CurrentValue = _CurrentValue
            MaxValue = _MaxValue
     
        End Sub
        Public Property CurrentValue As Integer
            Get
                Return _CurrentValue
            End Get
            Set(ByVal value As Integer)
                _CurrentValue = value
                Call DisplayProgress()
            End Set
        End Property
        Public Property MaxValue As Integer
            Get
                Return _MaxValue
            End Get
            Set(ByVal value As Integer)
                _MaxValue = value
                Call DisplayProgress()
            End Set
        End Property
     
        Private Sub frmProgress_Load(sender As Object, e As System.EventArgs) Handles Me.Load
            Call DisplayProgress()
        End Sub
        Private Sub DisplayProgress()
            RichTextBox1.Text = CurrentValue.ToString & " / " & MaxValue.ToString
        End Sub
    End Class

  3. #3
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Par défaut
    Bonjour,

    Vous ne pouvez pas mettre à jours les contrôles graphiques depuis un autre thread.
    OutputDataReceived et ErrortDataReceived provenant de votre Process externe tournant dans un autre thread ne peut pas mettre directement à jour le RichtextBox. Il faut utiliser Invoke.

    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
        Delegate Sub EcritTexteCallback(ByVal Texte As String)
        Private Sub EcritTexte(ByVal texte As String)
            ' InvokeRequired compare l'ID du thread appelant à l'ID du thread qui a créé le controle. Si ces threads sont différent, renvoie true.
            If frmProgress1.RichTextBox1.InvokeRequired Then
                frmProgress1.RichTextBox1.Invoke(New EcritTexteCallback(AddressOf EcritTexte), texte)
            Else
                frmProgress1.RichTextBox1.Text += texte
                frmProgress.RichTextBox1.Text += Environment.NewLine
            End If
        End Sub
     
        Private Sub OutputDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
                EcritTexte(e.Data.ToString)
        End Sub
        Private Sub ErrortDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
                EcritTexte(e.Data.ToString)
        End
    Faites une recherche sur invoke vous aurez des exemples comme ceci.
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

  4. #4
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Par défaut
    Merci beaucoup rv26t, je vais essayer ça.

  5. #5
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Par défaut
    Bonjour à tous,
    N'etant pas très à l'aise avec Invoke j'ai tenté d'utiliser un backgroundWorker que je connais un peu mieux mais je me heurte à un nouveau problème. En effet je dois lancer plusieurs Processus, le 2éme devant se lancer après que le 1er soit terminé.
    Comment faire pour que les BackgroundWorker s’exécute les uns après les autres ?
    Peut-être que je fais un mauvais choix avec le BackGroundWorker dans ce cas précis et je devrais peut-être m'en tenir à la méthode Invoke proposé plus haut mais dans ce cas mon formulaire frmProgress1 comprenant plusieurs controles d'affichage (plusieurs Label et plusieurs progressbar pour affichage des progressions de la tache en cours et pour la progression de l'ensemble des taches), est ce que je devrais vérifier chaque contrôle un par un avant d’exécuter ma méthode frmProgress1.AfficheLaProgression ou est-ce que l'on peut controler le formulaire tout entier : frmProgress1.InvokeRequired ?


    Pour simplifier je fait quelques choses qui ressemble à ç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
     
    For Tache = 1 to MaxTache
    frmProgress1.Show()
    If TotalPass=2 then
    ' Passe 1/2 :
               ProcessCommandeLine = "ffmpeg.exe Pass=1.......etc"
               BackgroundWorker1.RunWorkerAsync()
    ' Passe 2/2 :
               ProcessCommandeLine = "ffmpeg.exe Pass=2.......etc"
               BackgroundWorker1.RunWorkerAsync()
    else
    ' Passe 1
              ProcessCommandeLine = "ffmpeg.exe Pass=1.......etc"
              BackgroundWorker1.RunWorkerAsync()
     
    end if
    Next Tache
    Le code de l’événement ErrorDataReceived de l'objet MonProcess
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        Private Sub ErrorDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            ' Cet evenement s'execute dans le Thread qui a lancé le Processus
                ProcessOutputData = e.Data.ToString
                BackgroundWorker1.ReportProgress(0)  ' Notifie le BackgroundWorker pour affichage de la progression
                Debug.Print(e.Data.ToString)
        End Sub
    Le code de l’événement DoWork de l'objet BackGroundWorker1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Private Sub BackGroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs)
            ' Cet evenement s'execute dans le Thread qui a lancé le BackGroundWorker
            Call ShellExecute2("ffmpeg.exe", ProcessCommandeLine)
        End Sub
    Le Code de l'evenement ProgressChanged de l'objet BackGroundWorker1
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       Private Sub BackGroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs)
            ' Cet evenement s'execute dans le Thread principale et permet l'affichage de la progression
                ' Affichage de la progression :
            frmProgress1.AfficheLaProgression(ProcessOutputData) ' La méthode du formulaire frmProgress1 pour afficher la progression.
     End Sub
    Pour merci beaucoup si vous pouvez m’éclairer ou me donner des conseils n’étant pas très à l'aise avec les Threads. Je suis très intéressé par vos suggestions.
    Christian.

  6. #6
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Par défaut
    Bonsoir, j'ai abandonné la solution avec le BackGroundWorker, la méthode Invoke me semble plus approprié, j'ai malgré tout un problème sur la ligne suivante :
    frmProgress1.Invoke(MyDelegate)
    En pas à pas je perds la main dés que j’exécute cette ligne et je n'ai pas de message d'erreur. Ma seule possibilité est de stopper le programme depuis visual Studio.

    Le code principale :
    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
    For Tache = 1 to MaxTache
    frmProgress1.Show()
    If TotalPass=2 then
    ' Passe 1/2 :
               CommandeLine = "ffmpeg.exe Pass=1.......etc"
               Call ShellExecute2("ffmpeg.exe", CommandeLine)
    ' Passe 2/2 :
               CommandeLine = "ffmpeg.exe Pass=2.......etc"
               Call ShellExecute2("ffmpeg.exe", CommandeLine)
    else
    ' Passe 1
              CommandeLine = "ffmpeg.exe Pass=1.......etc"
              Call ShellExecute2("ffmpeg.exe", CommandeLine)
     
    end if
    Next Tache
    Le code de lancement du processus :
    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
        Private Sub ShellExecute2(ByVal ExeFile As String, CommandLine As String)
     
            Dim MonProcess As New Process
            AddHandler MonProcess.OutputDataReceived, AddressOf OutputDataReceived 
            AddHandler MonProcess.ErrorDataReceived, AddressOf ErrorDataReceived  
     
            MonProcess.StartInfo.FileName = ExeFile
            MonProcess.StartInfo.Arguments = CommandLine
            'MonProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized
            MonProcess.StartInfo.CreateNoWindow = True        ' True
            MonProcess.StartInfo.UseShellExecute = False      ' False
            MonProcess.StartInfo.RedirectStandardOutput = True
            MonProcess.StartInfo.RedirectStandardInput = True
            MonProcess.StartInfo.RedirectStandardError = True
     
            frmProgress1.Show() 
            MonProcess.Start()
     
            MonProcess.BeginOutputReadLine() 
            MonProcess.BeginErrorReadLine()  
     
            MonProcess.WaitForExit()
            MonProcess.Close()
        End Sub
    L'evenement de l'objet MonProcess :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
       Private Sub ErrorDataReceived(sender As Object, e As System.Diagnostics.DataReceivedEventArgs)
            ' Cet evenement s'execute dans le Thread qui a lancé le Processus
                ProcessOutputData = e.Data.ToString
                Invoquer(e.Data.ToString)
                Debug.Print(e.Data.ToString)
        End Sub
    La méthode Invoke et l'affichage de la progression.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        Delegate Sub DelegateAffichage(Texte As String)
        Private Sub Invoquer(ByVal texte As String)
            Dim MyDelegate As New DelegateAffichage(AddressOf Affiche)
            ' InvokeRequired compare l'ID du thread appelant à l'ID du thread qui a créé le controle. Si ces threads sont différent, renvoie true.
            If frmProgress1.RichTextBox1.InvokeRequired Then
                frmProgress1.Invoke(MyDelegate)
            Else
                Affiche(texte)
            End If
        End Sub
        Private Sub Affiche(Texte As String)
            frmProgress1.RichTextBox1.Text = texte
            frmProgress.RichTextBox1.Text += Environment.NewLine
        End Sub

  7. #7
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Par défaut
    Déjà en passant le texte, non? (pour voir l'affichage)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    frmProgress1.RichTextBox1.Invoke(MyDelegate, Texte)
    après, je n'ai pas suivi tout le reste.
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

  8. #8
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Par défaut
    Bonjour rv26t et merci de m'aider.
    Oui j'avais déja corrigé cette erreur en effet mais ça ne change rien sur le fait que je suis obligé de lancer le processus dans un nouveau Thread pour pouvoir afficher la sortie de ce processus. Du coup je ne peux plus exécuter les Processus les uns après les autres correctement.
    Pour mieux comprendre ce qu'il se passe j'ai rajouter cette ligne juste avant de démarrer le Process :
    Debug.Print(CommandLine)
    MonProcess.Start()

    C'est ainsi que je me suis appercu que j'ai 2 Process qui se lance avec une ligne de commande qui contient Pass=2. Je voudrais (dans le cas de l'encodage 2 passes) la Passe 1 se lance d'abord puis quand celle-ci est terminé je lance la passe 2.

    Merci beaucoup si quelqu'un peut m'aider.




    C'est à dire que dans ma procédure principale je passe comme argument une ligne de commande qui indique notamment le N° de la passe relatif à l'encodage (puisqu'il s'agit d'un processus d'encodage de vidéo).

  9. #9
    Modérateur

    Homme Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 722
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 722
    Par défaut
    Citation Envoyé par BasicZX81 Voir le message
    Je voudrais (dans le cas de l'encodage 2 passes) la Passe 1 se lance d'abord puis quand celle-ci est terminé je lance la passe 2.
    Sinon utiliser un timer qui scrute si le thread de la première passe est actif, quand il est fini lancer la deuxième passe.
    Traductions d'articles :
    La mémoire en .NET - Qu'est-ce qui va où ?
    Architecture DAL de haute performance et DTO ; Version C# : Partie 1,Partie 2,Partie 3 — Version VB.NET : Partie 1,Partie 2,Partie 3
    N'hésitez pas à consulter la FAQ VB.NET, le cours complet de Philippe Lasserre et tous les cours, articles et tutoriels.

  10. #10
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Par défaut
    Bon finalement ça ne fonctionne pas. . Le processus de la passe 1 ne se lance pas et l’exécution démarre directement par la passe 2 si j'utilise les Threads. Et si je n'utilise pas les Threads je ne n'arrive pas a afficher la progresssion. Je tourne en rond....
    Si quelqu'un a une idée ça m'interresse beaucoup sinon je vais devoir ma passer de l'affichage de la progression.

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

Discussions similaires

  1. [AC-2007] Formulaire pour afficher un enregistrement d'un Etat
    Par magic57 dans le forum IHM
    Réponses: 2
    Dernier message: 26/05/2011, 10h48
  2. Probleme formulaire pour afficher donnée
    Par nuFox dans le forum IHM
    Réponses: 1
    Dernier message: 04/12/2008, 16h02
  3. Pb bouton d'options pour afficher ou non un formulaire
    Par Patrick78 dans le forum Access
    Réponses: 11
    Dernier message: 07/09/2006, 16h48
  4. [MySQL] Un formulaire pour afficher et modifier un enregistrement
    Par Atchoum_002 dans le forum PHP & Base de données
    Réponses: 5
    Dernier message: 26/09/2005, 14h13
  5. Problème pour afficher un contrôle dans un formulaire
    Par JahRastafari dans le forum IHM
    Réponses: 5
    Dernier message: 16/06/2005, 10h15

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