Thread avec Gif [Résolu]

Messages postés
1855
Date d'inscription
jeudi 23 mai 2002
Dernière intervention
24 juin 2018
- - Dernière réponse : Whismeril
Messages postés
12389
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 décembre 2018
- 19 févr. 2017 à 21:16
Bonjour le Forum,
Lors de traitements assez lourds (création d'un fichier excel allant de 100 à 40.000 lignes, puis affichage de celles-ci dans un datagridview, je souhaite afficher un gif (sablier animé) pendant dans la durée de ces traitements.
Pour cela
Imports System.ComponentModel
Imports System.Threading
    Dim bw As BackgroundWorker = New BackgroundWorker
    Public Delegate Sub PictureVisibilityDelegate(ByVal visibility As Boolean)
    Dim ChangePictureVisibility As PictureVisibilityDelegate
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles MyBase.Load
        AddHandler bw.DoWork, AddressOf bw_DoWork
        AddHandler bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted
        ChangePictureVisibility = AddressOf ChangeVisibility
    Private Sub ComboBoxSheetHost_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBoxSheetsHost.SelectedIndexChanged
            Me.Invoke(ChangePictureVisibility, True)
            'MessageBox.Show("Toutes les fiches d un contrat sélectionné")

            SheetSelectFile(pathroot & "Client-" & selectedCustomer.ToString.Substring(0, 3) & ".xlsx", selectedHost.ToString)
            bw.RunWorkerAsync()
 
    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        MessageBox.Show("Done!")
    End Sub

    Public Sub ChangeVisibility(ByVal visibility As Boolean)
        Select Case visibility
            Case True
                PictureBoxSheets3.Visible = True
                PictureBoxSheets3.BringToFront()
            Case False
                PictureBoxSheets3.Visible = False
                Me.BringToFront()
        End Select
        ' MessageBox.Show("visibility.ToString = " & visibility.ToString)
    End Sub

    Private Sub bw_DoWork(sender As Object, e As DoWorkEventArgs)
        ' MessageBox.Show("Debut bw_DoWork")
        'Label1.Text = "Nombre de fiche : " & CStr(datasetIDMON.Tables("HOSTS").Rows.Count.ToString)
        writeExcel()
        'MessageBox.Show("Fin bw_DoWork")
    End Sub

    Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
        Me.Invoke(ChangePictureVisibility, False)
        Label1.Text = "Nombre de fiche : " & CStr(datasetIDMON.Tables("HOSTS").Rows.Count.ToString)
        LabelSheetsCountService.Text = "Nombre de service : " & CStr(datasetIDMON.Tables("SERVICES").Rows.Count.ToString)
        ' MessageBox.Show("bw_RunWorkerCompleted")
    End Sub

Le gif (PictureBoxSheets3) s'affiche correctement.
Par contre, dans la sub bw_DoWork, si je veux afficher Label1.Text, cette sub s'arrête, sans m'afficher le MessageBox.Show("Fin bw_DoWork") et passe à la sub bw_RunWorkerCompleted.
De même, dans la sub bw_DoWork, si je veux remplir un datagridview, il y a arrêt de cette sub.
Dans l'exemple ci-dessous, dans la sub bw_DoWork, la fonction WriteExcel s'exécute correctement, avec le gif animé en même temps, quoique le fichier excel n'est libéré qu'à la fermeture de l'application).
Auriez-vous une solution pour mon souci !!
Merci d'avance,
jean-marc
Afficher la suite 

Votre réponse

5 réponses

Messages postés
12389
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 décembre 2018
0
Merci
Bonjour

tu n'as pas le droit depuis un thread tiers de toucher aux contrôles du thread de la Form.

Deux options s'offrent à toi, car tu te sers d'un backgroundWorker:
  • Utiliser le suivi de progression prévu par le BGW,

backgroundWorker1.WorkerReportsProgress = True
AddHandler backgroundWorker1.ProgressChanged, AddressOf backgroundWorker1_ProgressChanged

Dans le thread tu utilises backgroundWorker1.ReportProgress(Interger, ObjectATransfer)
L'entier étant la progression de 0 à 100% et l'objet soit une classe que tu auras écrit exprès pour transmettre des infos, soit une collection.
La méthode backgroundWorker1_ProgressChanged appartient au thread principal, elle reçoit Interger, ObjectATransfer en paramètres et peut les afficher.
  • Utiliser le dispatcher, dont le rôle est justement, les interactions entre threads. C'est un peu plus compliqué, mais plus efficace et valable quel que soit le type de thread.

  Private Sub LancerLeThread()
 Dim monThread As New Thread(AddressOf LaMethodeDuThread)
   monThread.Start()
  End Sub

  Private monDispatcher As Dispatcher = Dispatcher.CurrentDispatcher
  Private Sub LaMethodeDuThread()
   For i As Integer = 0 To Integer.MaxValue - 1
    If i Mod 1e3 = 0 Then
     monDispatcher.BeginInvoke(New Action(Sub() label1.Text = i.ToString()))
    End If
    Thread.Sleep(1)
   Next i
  End Sub

Pour l'exemple j'ai fait un délégué, mais tu peux appeler une méthode, tu peux aussi choisir entre Invoke et BeginInvoke et gérer les prioritéq, là mon code envoie l'action quand il veut ce qui fait que le label peut afficher 9002 au lieu de 9000.

Quand j'étais petit, la mer Morte n'était que malade.
George Burns
Commenter la réponse de Whismeril
Messages postés
1855
Date d'inscription
jeudi 23 mai 2002
Dernière intervention
24 juin 2018
0
Merci
Bonjour Whismeril,

Merci pour tes explications. Je vais potasser tes deux options.
Bon week-end.

jean-marc
Whismeril
Messages postés
12389
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 décembre 2018
-
Tu trouveras plus facilement des tutos en c#, il suffit de passer le code dans un traducteur en ligne, ou alors de passer au c#!

Bon week-end en à toi aussi
Commenter la réponse de cs_JMO
Messages postés
1855
Date d'inscription
jeudi 23 mai 2002
Dernière intervention
24 juin 2018
0
Merci
Bonjour le Forum,

Bonjour Whismeril,
Merci pour tes conseils. J'ai utilisé le BackgroundWorker car je n'ai pas trouvé la référence à ajouter pour le Dispatcher (VS 2012 Express).

Exemple avec un PictureBox, un Label et un DatagridView (2 colonnes) :
Option Strict On
Option Explicit On
Imports System.ComponentModel

Public Class Form1
    Dim bw As BackgroundWorker = New BackgroundWorker
    Delegate Sub SetLabel1(text As String)
    Delegate Sub SetDataGridView1(ByVal row As Integer, ByVal cell As Integer)

    Public Shared Sub Main()
        Application.Run(New Form1())
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        AddHandler bw.DoWork, AddressOf bw_DoWork
        AddHandler bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted
        Me.PictureBox1.Visible = False
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If Not bw.IsBusy = True Then
            Me.PictureBox1.Visible = True
            bw.RunWorkerAsync()
        End If
    End Sub

    Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        SetLabel1_Delegate("Load ...")
        For i As Integer = 1 To 35000
            SetDataGridView1_Delegate(i, 35001 - i)
        Next
    End Sub

    Private Sub SetLabel1_Delegate(ByVal text As String)
        Dim newtext As String = text
        If Me.Label1.InvokeRequired Then
            Dim d As New SetLabel1(AddressOf SetLabel1_Delegate)
            Me.Invoke(d, New Object() {newtext})
        Else
            Label1.Text = newtext
            Me.Refresh()
        End If
    End Sub

    Private Sub SetDataGridView1_Delegate(ByVal row As Integer, ByVal cell As Integer)
        If Me.DataGridView1.InvokeRequired Then
            Dim d As New SetDataGridView1(AddressOf SetDataGridView1_Delegate)
            Me.Invoke(d, New Object() {row, cell})
        Else
            Dim newrow As String() = New String() {CStr(row), CStr(cell)}
            DataGridView1.Rows.Add(newrow)
        End If
    End Sub

    Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
        Me.PictureBox1.Visible = False
        Me.Label1.Text = "Done !!!"
    End Sub
End Class


jean-marc
Whismeril
Messages postés
12389
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 décembre 2018
-
Salut

https://msdn.microsoft.com/fr-fr/library/system.windows.threading.dispatcher(v=vs.110).aspx

Je site
Espace de noms: System.Windows.Threading
Assembly: WindowsBase (dans WindowsBase.dll)
cs_JMO
Messages postés
1855
Date d'inscription
jeudi 23 mai 2002
Dernière intervention
24 juin 2018
> Whismeril
Messages postés
12389
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 décembre 2018
-
Salut Whismeril,
Je l'ai lu hier ce lien.
Imports System.Windows.Threading 
provoque une erreur.
Whismeril
Messages postés
12389
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 décembre 2018
> cs_JMO
Messages postés
1855
Date d'inscription
jeudi 23 mai 2002
Dernière intervention
24 juin 2018
-
As tu la référence à WindowsBase.dll?
cs_JMO
Messages postés
1855
Date d'inscription
jeudi 23 mai 2002
Dernière intervention
24 juin 2018
> Whismeril
Messages postés
12389
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 décembre 2018
-
Non !!! pourtant FrameWork 4.0
Whismeril
Messages postés
12389
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 décembre 2018
> cs_JMO
Messages postés
1855
Date d'inscription
jeudi 23 mai 2002
Dernière intervention
24 juin 2018
-
Elle est dans la framework, il suffit d'ajouter la référence à ton projet
Commenter la réponse de cs_JMO
Messages postés
1855
Date d'inscription
jeudi 23 mai 2002
Dernière intervention
24 juin 2018
0
Merci
Merci Whismeril, trouvée et ajoutée !!!
Y a plus qu'à tester.

jean-marc
Commenter la réponse de cs_JMO
Messages postés
12389
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 décembre 2018
0
Merci
Bon test, il y a des pièges comme ça parfois.
Le plus c*n, c'est quand ça te mets System.Io (par exemple) et que tu l'as déjà et pourtant t'as pas accès à la classe. En fait une autre assembly existe qui enrichi l'espace de nom....
Il faut donc bien regarder l'espace de nom et l'assembly
Commenter la réponse de Whismeril

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.