Thread avec Gif

Résolu
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 - 18 févr. 2017 à 12:33
Whismeril Messages postés 19027 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 24 avril 2024 - 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

5 réponses

Whismeril Messages postés 19027 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 24 avril 2024 656
Modifié par Whismeril le 18/02/2017 à 14:09
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
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
18 févr. 2017 à 14:18
Bonjour Whismeril,

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

jean-marc
0
Whismeril Messages postés 19027 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 24 avril 2024 656
Modifié par Whismeril le 18/02/2017 à 14:23
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
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
19 févr. 2017 à 09:33
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
0
Whismeril Messages postés 19027 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 24 avril 2024 656
19 févr. 2017 à 10:13
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)
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27 > Whismeril Messages postés 19027 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 24 avril 2024
19 févr. 2017 à 10:19
Salut Whismeril,
Je l'ai lu hier ce lien.
Imports System.Windows.Threading 
provoque une erreur.
0
Whismeril Messages postés 19027 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 24 avril 2024 656 > cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018
19 févr. 2017 à 13:57
As tu la référence à WindowsBase.dll?
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27 > Whismeril Messages postés 19027 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 24 avril 2024
19 févr. 2017 à 14:01
Non !!! pourtant FrameWork 4.0
0
Whismeril Messages postés 19027 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 24 avril 2024 656 > cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018
19 févr. 2017 à 14:02
Elle est dans la framework, il suffit d'ajouter la référence à ton projet
0
cs_JMO Messages postés 1854 Date d'inscription jeudi 23 mai 2002 Statut Membre Dernière intervention 24 juin 2018 27
19 févr. 2017 à 14:09
Merci Whismeril, trouvée et ajoutée !!!
Y a plus qu'à tester.

jean-marc
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Whismeril Messages postés 19027 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 24 avril 2024 656
19 févr. 2017 à 21:16
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
0
Rejoignez-nous