none
AIUTO - Attivare Progress bar in un processo RRS feed

  • Domanda

  • Salve a tutti, ho un grosso problema, vorrei attivare una progress ba in un processo e non riesco ad attivarla, come posso procedere?

    grazie a tutti

           Dim psi As New ProcessStartInfo With { _

                        .WorkingDirectory = "...", _
                        .CreateNoWindow = True, _
                       .FileName = "...", _
                       .Arguments = argomento, _
                       .UseShellExecute = False, _
                       .RedirectStandardOutput = True, _
                       .WindowStyle = ProcessWindowStyle.Hidden}

                Dim p As New Process With { _
                .StartInfo = psi}

                p.Start()

    martedì 11 giugno 2019 20:19

Tutte le risposte

  • visto che non ho capito bene il tuo intento ti faccio un esempio di popolamento di una listbox con progressbar

        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Dim n As Integer = 100
            ProgressBar1.Visible = True
            ProgressBar1.Minimum = 1
            ProgressBar1.Maximum = n
            ProgressBar1.Value = 1
            ProgressBar1.[Step] = 1
            For i As Integer = 1 To n
                ListBox1.Items.Add("elemento " + i.ToString)
                ProgressBar1.PerformStep()
            Next
        End Sub

    mercoledì 12 giugno 2019 06:53
  • Ciao e grazie dell'aiuto e scusa se non mi sono spiegato bene

    la progress bar so come "" farla funzionare "" 

    il problema che non riesco e' implementarla in un processo come da richuesta descritto

    io lancio un processo (come se lo lanciassi da terminale in cmd) raccoglie i dai e li trasporta in una listbox poi io da li elaboro il risultato, e vorrei che mentre il programma lancia il comando si attivi la progress bar, cosa che non succede (esempio anche l'ora si blocca) perche da quando parte il processo fino al termine il programma e' come se bloccasse qualche processo altro, --- ho provato anche a far partire un time appena il processo inizia, ma senza risultato preche' blocca anche l'avvio del timer

    spero di essere stato piu chiaro

    mercoledì 12 giugno 2019 13:35
  • Descrivi un comportamento strano, almeno leggendo il codice che hai scritto.

    In teoria, lanciare il processo non ti blocca il tuo thread principale, quindi "l'orologio" dovrebbe comunque funzionare.

    Differente invece se hai anche aggiunto un WaitForExit() al tuo processo. In questo caso il thread chiamante resta in attesa di vedere il processo terminato, ed il tuo orologio non funziona più.

    Per il discorso progressbar, invece, dovresti capire se il tuo processo ti mette a disposizione dei messaggi, naturalmente leggibili dal tuo software, che ti permettano di sapere a che punto sei.

     

    mercoledì 12 giugno 2019 14:11
  • Dim psi As New ProcessStartInfo With { _
                       .FileName = "c:\Python27\Scripts\esptool.py", _
                       .Arguments = " --port COM3 erase_flash", _
                       .UseShellExecute = False, _
                       .RedirectStandardOutput = True, _
                       .WindowStyle = ProcessWindowStyle.Hidden, _
                       .CreateNoWindow = True}

                    Dim p As New Process With { _
                    .StartInfo = psi}

                    p.Start()

                    ListBox1.Items.AddRange(p.StandardOutput.ReadToEnd.Split(New String() {Environment.NewLine}, StringSplitOptions.None))

    questo e' uno dei processi reali che devo eseguire - ( per gli altri processi cambia solo il "Arguments " )

    e quindi ogni volta finche non finisce questa comando ( la procedura di esptools ) non posso fare nulla, percio' vorrei integrare la progress bar per avere la conoscenza del tempo di esecuzione dell'azione

    giovedì 20 giugno 2019 14:11
  • come già anticipato da vbmizio il programma vb non può sapere quando finirà il processo e quindi non può monitorarlo con una progress bar
    venerdì 21 giugno 2019 08:42
  • Grazie a tutti per l'aiuto

    e come posso ovviare a questo?, ho proprio bisogno di integrare lo stato di avanzamento del programma

    sabato 22 giugno 2019 13:54
  • Cosa fa esptool.py?

    Hai modo di sapere prima quanti dati dovrai elaborare - quanto durerà esptool?

    In alternativa….

    Se esptool inviasse sullo stoutput qualcosa come:

    <START_ELAB>

    10

    20

    e così via fino a …..

    100

    <START_DATA>

    e qui l'output che ti ha sempre inviato

    Potresti intercettare questi output del programma e popolare la progressbar e poi dopo aver ricevuto

    lo start data usi quel pezzo successivo come hai sempre fatto per la listbox

    Ovviamente i numeri 10 - 20 .…. sono la percentuale di avanzamento da mettere nella barra.

    Se così ti viene complicato, come soluzione sporca ma efficace fai scrivere su un file di testo la percentuale e la leggi con un timer o con quel famoso sistema per monitorare i cambiamenti dei file che non uso mai e quindi non mi ricordo come si chiama.

    domenica 23 giugno 2019 07:04
  • tramite esptools si scrive su schede ESP8266 (tipo SONOFF) per cambiare firmware

    durante il processo c'e' la percentuale di avanzemento ( che viene riportata nella listbox ) che pero' non riesco ad elaborare una volta partito il processo  p.Start()


    domenica 23 giugno 2019 12:41
  • Riprendendo quanto ti ho scritto sopra, ad occhio, mi sembra strano che il codice che hai scritto ti blocchi il thread fino alla completa esecuzione del processo che lanci. Da quanto leggo, il codice dovrebbe lanciare il processo e continuare per i fatti suoi.

    Sei sicuro che dopo aver eseguito il tuo "p.Start", il thread resti bloccato, l'orologio si fermi ecc.?

    Metti un breakpoint sia su p.Start che sull'istruzione seguente. 

    Quando raggiungi il breakpoint, esegui il p.Start e vedi se il breakpoint seguente viene raggiunto subito o se prima deve terminare il processo lanciato.

    Se è come penso io, dovresti raggiungere subito l'istruzione seguente.

    mercoledì 26 giugno 2019 06:55
  • Ciao vbMizio, scusa il ritardo, sono stato impegnato

    ripendendo il discorso ho seguito il tuo consiglio

    e la procedura si blocca a questa istruzione

     ListBox_ESPTOOL.Items.AddRange(p.StandardOutput.ReadToEnd.Split(New String() {Environment.NewLine}, StringSplitOptions.None))

    e comunque non riesco a rilevare i dati di avanzamento del processo stesso

    Grazie

    *****************codice procedura **************
                Dim psi As New ProcessStartInfo With { _
                    .WorkingDirectory = "c:\Python27\Scripts\", _
                       .CreateNoWindow = True, _
                       .FileName = "c:\Python27\Scripts\esptool.py", _
                       .Arguments = argomento, _
                       .UseShellExecute = False, _
                       .RedirectStandardOutput = True, _
                       .WindowStyle = ProcessWindowStyle.Hidden}


                Dim p As New Process With { _
                .StartInfo = psi}

                p.Start()

                ListBox_ESPTOOL.Items.Add("****************WRITE BOARD********************")
                ListBox_ESPTOOL.Items.AddRange(p.StandardOutput.ReadToEnd.Split(New String() {Environment.NewLine}, StringSplitOptions.None))

    *****************codice procedura **************

    giovedì 12 settembre 2019 14:47
  • Ciao,

    quindi era come pensavo, non è lo start che ti blocca tutto.

    La tecnica che usi tu per leggere lo stream di ritorno non l'ho mai usata, ma andando a naso (prendila per quella che è) potrebbe essere che la chiamata a StandardOutput.ReadToEnd usata non termini perché ancora non è terminato il processo.

    Quello che farei io, è reindirizzare i messaggi che arrivano dal processo ad una sub che li elabori.

    Come penso saprai, i processi espongono due eventi (sono in realtà quattro quelli disponibili) che ti possono aiutare in questi casi.

    Gli eventi sono OutputDataReceived e ErrorDataReceived, dove il primo dovrebbe essere quello adatto a te.

    Scrivi un gestore di eventi (una sub, quindi) per questi eventi, assegni il gestore, lanci il processo e dopo aver lanciato il processo esci dalla tua sub o aspetti che il processo sia terminato, nel caso in cui non vuoi far fare altro al software e/o utente

    Sarà poi il gestore di eventi che riceve il messaggio, lo elabora, se serve e mediante un oggetto di sincronizzazione (non sei più sul thread principale), accede alla listbox ( o alla progressbar, o tutti e due) ed aggiunge gli elementi.

    Capisco che detta così può sembrare complicato, intanto vai qui alla sezione eventi per avere una idea degli eventi della classe Process e come gestirli.


    giovedì 12 settembre 2019 15:15
  • Ciao vbMizio, grazie ancora per l'aiuto

    hai ragione ""che detta così può sembrare complicato"", e sinceramente non so come procedere, sto cercando di  avere una idea degli eventi della classe Process e come gestirli, ma ancora nulla

    Se per te' e' possibile darmi un aiuto in piu' te ne sarei davvero grato

    non conosco e non riesco a gestire gli eventi ( in visual studio non riesco a trovare nessun esempio  ( non in C ) )

    OutputDataReceived e ErrorDataReceived,

    ************************************

    ( questo e' un esempio di quello che mi consigli ? )

    ho trovato e provato questo, ma mi restituisce errore e non so come passare allo step successivo

    ""Operazione cross-thread non valida: è stato eseguito l'accesso al controllo 'ListBox_ESPTOOL' da un thread diverso da quello da cui è stata eseguita la creazione.""

    Private Sub StartProcess()
            'Dim Proc As New Process

            Proc.StartInfo.FileName = "c:\Python27\Scripts\esptool.py"
            Proc.StartInfo.WorkingDirectory = "c:\Python27\Scripts"
            Proc.StartInfo.Arguments = " --port " & Label_PORTA_COM.Text & " --baud 115200 flash_id"

            Proc.StartInfo.UseShellExecute = False
            Proc.StartInfo.RedirectStandardOutput = True
            Proc.StartInfo.CreateNoWindow = True

            AddHandler Proc.OutputDataReceived, AddressOf OutputHandler

            Proc.Start()
            Proc.BeginOutputReadLine()
            Proc.WaitForExit()

            Proc.Dispose()
            Proc = Nothing

        End Sub

        Private Async Sub OutputHandler(sendingProcess As Object, outLine As DataReceivedEventArgs)
            If Not String.IsNullOrEmpty(outLine.Data) Then
               ListBox_ESPTOOL.Items.Add(outLine.Data)   

        End If
        End Sub

    Saluti



    • Modificato GiaSca giovedì 12 settembre 2019 21:30
    giovedì 12 settembre 2019 18:13
  • Ciao,

    direi che sei molto vicino alla soluzione. L'eccezione, "Operazione cross-thread non valida", ti viene sollevata proprio perché, come ti scrivevo, nel gestore di evento OutputHandler (p.s. perché lo hai etichettato come Async? ) sei in un thread diverso rispetto a quello principale, quindi non puoi andare a lavorare sull'interfaccia grafica, a meno di non disabilitare il controllo sull'accesso all'interfaccia utente da un thread diverso.

    Ecco perché nel mio post precedente ti scrivevo che dovrai usare un oggetto di sincronizzazione o comunque un metodo che permetta l'accesso all'interfaccia utente.

    Per fare questo hai un paio di soluzioni, puoi usare un oggetto WindowsFormsSynchronizationContext, e puoi iniziare a leggere quaslcosa qui, oppure usare il metodo Invoke del controllo a cui vuoi accedere, e in questo caso il link da seguire è questo

    Per quel che mi riguarda, utilizzo indifferentemente tutti e due i metodi, dipende al momento quale mi ispira di più.

    lunedì 16 settembre 2019 06:51
  • Ciao vbMizio

    ho scritto ( sempre con l'aiuto di esempi trovati in rete ) quest'altro pezzo di codice ( vedi in fondo alla pagina ) ( e credo che sia piu' fluido )

    i dati vengono riportati tranquillamente nel --> MsgBox(processOutput.ToString())

    e poi mi blocco, sto cercano di capire come invocare ( tramite INVOKE ) ma ancora sono bloccato, il programma si blocca sempre a questo comando

    ListBox_ESPTOOL.Items.AddRange(processOutput.ToString().Split(New String() {Environment.NewLine}, StringSplitOptions.None))

    ti chiede un aiuto su come risolvere la situazione, anche per capire meglio da un esempio pratico

    Ti ringrazio sempre dell'aiuto e della disponibilita'

    ************codice****************

    Private Shared processOutput As StringBuilder = Nothing

        Public Shared Sub StartSomeProcess()
            processOutput = New StringBuilder()
            Dim NewProcess As New System.Diagnostics.Process()
            With NewProcess.StartInfo
                .CreateNoWindow = True
                .FileName = "c:\Python27\Scripts\esptool.py"
                .Arguments = " --port COM7 --baud 115200 flash_id"
                .UseShellExecute = False
                .RedirectStandardOutput = True
                .RedirectStandardError = True
                .WindowStyle = ProcessWindowStyle.Hidden
            End With

            ' Set our event handler to asynchronously read the sort output.
            AddHandler NewProcess.OutputDataReceived, AddressOf OutputHandler
            NewProcess.Start()
            NewProcess.BeginOutputReadLine()
            NewProcess.WaitForExit()

            MsgBox(processOutput.ToString())


        End Sub

        Private Shared Sub OutputHandler(sendingProcess As Object, outLine As DataReceivedEventArgs)
            ' Collect the sort command output.
            If Not String.IsNullOrEmpty(outLine.Data) Then
                ' Add the text to the collected output.
                processOutput.AppendLine(outLine.Data)

            End If
        End Sub

    lunedì 16 settembre 2019 18:37
  • GiaSca, come saprai su questo forum non è ben visto il fornire codice pronto all'uso, a meno che non ci sia una difficoltà con un metodo specifico.

    Per questo motivo non posso darti il codice così come servirebbe a te, ma posso farti un esempio molto semplice sull'uso del metodo Invoke chiamato su un controllo, e darti una spiegazione di cosa accade.

    Iniziamo con qualche riga di codice

        Private Sub AggiornaLabel(ByVal Testo As String)
    
            If Me.Label1.InvokeRequired Then
                Me.Label1.Invoke(Sub() AggiornaLabel(Testo))
            Else
                Me.Label1.Text = Testo
            End If
    
        End Sub

    Nel nostro caso, sto assegnando il valore dell'argomento Testo al testo della Label1. Come prima cosa, nel blocco If Then, cerco di capire se ho effettivamente bisogno di passare per l'Invoke semplicemente andando a leggere la proprietà InvokeRequired del controllo, e se effettivamente ne ho bisogno (InvokeRequired restituirà True se la chiamata viene da un thread secondario) , chiamo il metodo Invoke sul controllo, passando un delegato costruito "al volo". Il delegato punta alla stessa sub, e visto che la sub viene chiamata dal metodo Invoke, quindi già nel thread principale, la proprietà InvokeRequired restituirà False e verrà quindi eseguita la riga Me.Label1.Text = Testo

    Nel tuo caso specifico, scriverei una sub simile, dove naturalmente farai riferimento al controllo Listbox, come argomento passerei il testo che vuoi che venga aggiunto alla Listbox stessa.

    L'elaborazione del testo e la chiamata alla sub la farei direttamente nel gestore di evento OutputHandler.

    Per essere più chiari, nella tua OutputHandler andrei a leggere i messaggi che mi arrivano dal processo, elaborerei ciascun messaggio che arriva estraendone il testo che vuoi aggiungere alla Listbox, e per ogni riga di testo chiamerei la Sub (l'equivalente della mia AggiornaLabel) che aggiunge testo alla Listbox passando come argomento proprio il testo che vuoi aggiungere.

    Spero che questo ti possa aiutare 

    martedì 17 settembre 2019 07:29
  • Grazie ancora vbMizio,  ho integrato la SUB come da tua indicazione, richiamando dal BUTTON che serve i processi ( puoi dare uno sguardo e farmi capire ancora dove sbaglio? grazie

    StartSomeProcess()
    Timer_PROGRESSBAR.Start()

    ****************************

    Private Shared processOutput As StringBuilder = Nothing

        Public Shared Sub StartSomeProcess()
            processOutput = New StringBuilder()
            Dim NewProcess As New System.Diagnostics.Process()
            With NewProcess.StartInfo
                .CreateNoWindow = True
                .FileName = "c:\Python27\Scripts\esptool.py"
                .Arguments = " --port COM7 --baud 115200 flash_id"
                .UseShellExecute = False
                .RedirectStandardOutput = True
                .RedirectStandardError = True
                .WindowStyle = ProcessWindowStyle.Hidden
            End With

            ' Set our event handler to asynchronously read the sort output.
            AddHandler NewProcess.OutputDataReceived, AddressOf OutputHandler
            NewProcess.Start()
            NewProcess.BeginOutputReadLine()
            NewProcess.WaitForExit()

            ' MsgBox(processOutput.ToString())



        End Sub

        Private Shared Sub OutputHandler(sendingProcess As Object, outLine As DataReceivedEventArgs)
            ' Collect the sort command output.
            If Not String.IsNullOrEmpty(outLine.Data) Then
                ' Add the text to the collected output.
                processOutput.AppendLine(outLine.Data)
                'MsgBox(processOutput.AppendLine(outLine.Data).ToString

                'MsgBox(processOutput.ToString())
                Form1.AggiornaLabel(processOutput.AppendLine().ToString)

            End If

        End Sub

        Private Sub AggiornaLabel(ByVal Testo As String)

            If Me.ListBox_ESPTOOL.InvokeRequired Then
                Me.ListBox_ESPTOOL.Invoke(Sub() AggiornaLabel(processOutput.AppendLine().ToString))
            Else
                'Me.ListBox_ESPTOOL.Items.AddRange(processOutput.ToString().Split(New String() {Environment.NewLine}, StringSplitOptions.None))
                Me.ListBox_ESPTOOL.Items.Add(processOutput.AppendLine().ToString)
            End If

        End Sub

    martedì 17 settembre 2019 20:57
  • Ciao,

    naturalmente non posso provare quanto da te scritto, avrei bisogno dell'eseguibile che lanci e probabilmente un po' di altre cose.

    Vado quindi a ruota libera, dando una letta al tuo codice.

    Prima cosa non capisco l'utilizzo di procedure e campi Shared; vero è che non so esattamente come stai utilizzando il codice, ma quegli Shared non li vedo proprio bene.

    Nel gestore di eventi OutputHandler chiami poi il metodo Form1.AggiornaLabel, ma qui c'è una incongruenza; sei in un metodo Shared, chiami un metodo di istanza, ma l'istanza non c'è.

    Ogni messaggio che ti arriva viene aggiunto ad una stringona che contiene tutti i messaggi, e sempre per ogni messaggio, tenti di aggiungere la stringona alla Listbox. Quindi, ammettiamo che ti arrivino in sequenza 4 messaggi, ciascuno con una parola, ad esempio il primo messaggio è "ciao", il secondo "io", il terzo "sono" ed il quarto "GiaSca", tu poi visualizzerai...

    ciao

    ciao io

    ciao io sono

    ciao io sono GiaSca

    è questo quello che vuoi?

    Andando a naso dovresti riportare i tuoi metodi come metodi di istanza, e non shared, eliminerei la variabile per lo stringone e andrei ad aggiungere alla Listbox i messaggi così come arrivano, ma ripeto, non so esattamente come vuoi usare il tutto, quindi potrei fraintendere.

     

    mercoledì 18 settembre 2019 06:53
  • dalla MsgBox(processOutput.ToString()) il risultato e' questo e per questo risultato il programma va in blocco per circa 3-4 secondi

    "" l'utilizzo di procedure e campi Shared "" l'ho trovata in rete per utilizzare ""  AddHandler NewProcess.OutputDataReceived, AddressOf OutputHandler "" come mi hai consigliato ( ma non sapendo utilizzare queste funzioni cerco di adattarle per il mio utilizzo ) 

    il comando   esptool.py --port COM7 --baud 115200 flash_id ( lanciato da terminale restituisce delle informazione, ed io sto cercando di realizzare tramite un solo button l'invio di alcuni comando e di elaborare le info ricevute ) ( ti posso dare il link del programma per farti una idea di come lo sto realizzando), ho realizzato il tutto ma la parte x me piu' difficile e' proprio integrare la progress bar ( scusami se sono ripetitivo nelle spiegazioni e spreo di essere stato chiaro ) 

    una altro comando mi restituisce anche la percentuale di lavoro

    Serial port COM7
    Connecting....
    Detecting chip type... ESP8266
    Chip is ESP8266EX
    Features: WiFi
    MAC: xxxxxxxxxxxxxx
    Uploading stub...
    Running stub...
    Stub  running...
    Manufacturer: 20
    Device: 4016
    Detected flash size: 4MB
    Hard resetting via RTS pin...
    sabato 21 settembre 2019 14:36
  • Ciao,

    scusa ma comincio a fare fatica a seguirti.

    Vedo che hai reintrodotto la chiamata al WaitForExit sul processo che lanci.

    Tramite il WaitForExit, blocchi il thread chiamante fino a che il processo stesso non è terminato, quindi se il processo ci mette 4 secondi ad uscire, tu per quei 4 secondi sei bloccato.

    Se questa chiamata la fai dal thread principale, questo resta bloccato e non hai modo di aggiornare niente.

    Ripeto, non so come funziona il processo che lanci, se restituisce tutti i dati in un colpo solo o se manda messaggi vari ecc, ma a naso farei:

    Lancio il processo ed esco dalla routine, nel gestore di eventi vado a leggere i messaggi che arrivano, li elaboro, vedo (o calcolo) la percentuale di lavoro svolto, dato che siamo in un thread diverso dal principale tramite un metodo di sincronizzazione (ad esempio il metodo Invoke che abbiamo visto)  aggiorno la progressbar.


    lunedì 23 settembre 2019 08:23
  • Ciao vbMizio, grazie ai tuoi consigli, il tuo aiuto, la tua guida credo di essere ad un buon punto, sono riuscito a non far bloccare il programma in fase di esecuzione della procedura, sono ancora in fase di lavoro, non sono riuscito a concliudere il tutto, ma come dicevo ho gia' superato qualche ostacolo

    come faccio a capire quando e' terminato/finito il processo?

    ti ringrazio ancora e lascio ancora aperta la discussione, se possibile, finche' non risolvo del tutto

    Grazie


    • Modificato GiaSca domenica 6 ottobre 2019 21:10
    sabato 5 ottobre 2019 11:42
  • Ciao,

    per sapere quando un processo è terminato, puoi intercettare l'evento Exited alzato dal processo.

    Qui la documentazione.

    lunedì 7 ottobre 2019 06:37
  • Scusa vbMizio

    non riesco ad intercettare 

    "intercettare l'evento Exited"

    mercoledì 9 ottobre 2019 18:48
  • Hai impostato EnableRaisingEvents = true?
    giovedì 10 ottobre 2019 07:43
  • Ciao Spaccabit

    ""Hai impostato EnableRaisingEvents = true? ""

    grazie del suggerimento

    credo di essere riuscito a risolvere il problema, metto insieme tutti i pezzi

    venerdì 18 ottobre 2019 09:17