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

Macros et VBA Excel Discussion :

Attendre la fin de l'actualisation des tables de données (QueryTables) via la classe d'evenements QueryTable


Sujet :

Macros et VBA Excel

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2010
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 194
    Points : 378
    Points
    378
    Par défaut Attendre la fin de l'actualisation des tables de données (QueryTables) via la classe d'evenements QueryTable
    Bonjour,

    il y a quelques temps j'ai répondu à une discussion ici

    à propos de l'attente de la fin de l'actualisation des tables de données externes. Hélas l'auteur du poste n'a jamais répondu or le sujet m’intéresse pour 2 raisons

    La première est que j'ai eu à résoudre ce problème pour l’importation de donnée issues de base accessible uniquement via une interface Web et qu'il m'a fallut trouver le moyen d'attendre la fin de l'actualisation. D'autant que le réseau est assez capricieux et peut significativement augmenter le temps de mise à jour. Donc dans un tel cas il n'était pas pensable d'utiliser une tempo.
    De plus je n'ai trouver aucun forum ou source qui proposait d'utiliser les evenements de la classe Querytable

    La deuxième raison est que j'aurais aimé savoir si cela fonctionne sur les autres type de Querytables

    Du coup si une ou plusieurs âmes charitables pouvais faire le teste avec d'autre type de Querytables cela permettrais de mieux partager cette solution.
    Vous trouverez le type de table rafraîchie qui s'écrit dans la fenêtre d’exécution.
    De plus je propose une amélioration de ce que j'ai posté, avec cette fois si la possibilité de non plus mettre à jour les tables une par une mais avec la méthode RefreshAll.
    Refreshall a l'avantage de paralléliser l'actualisation des tables alors que ma solution précédente sérialisait l'actualisation.
    Ce qui permet d’accélérer grandement la mise à jour si le fichier contient plusieurs tables.

    Voici le code :

    Dans le code ThisWorkBook :

    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
     
    Option Explicit
     
    Private Sub Workbook_Activate()
        Call XlAppli.InitQueryEvent(Me)
    End Sub
     
    Private Sub Workbook_BeforeClose(Cancel As Boolean)
        XlAppli.EmptyQtClass
    End Sub
     
    Private Sub Workbook_Deactivate()
        XlAppli.EmptyQtClass
    End Sub
     
    Private Sub Workbook_Open()
        Set XlAppli.Xl = Excel.Application 'on charge la classe
        Call XlAppli.InitQueryEvent(Me) 'on recupere toutes les querytables afin de les associées à leur classe d'evenements
    End Sub
    En partie haute d'un module on colle le code suivant :

    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
     
    Option Explicit
     
     'optionnel permettra par la suite de redonner le focus à excel en cas de demande éventuelle de mot de passe en début de requête 
    Declare Function SetForegroundWindow Lib "User32" (ByVal hwnd As Long) As Long
    'permettra de vérifier qu'une connexion réseau existe
    Declare Function InternetGetConnectedState Lib "wininet.dll" (lpdwFlags As Long, ByVal dwReserved As Long) As Boolean
     
    Public RefreshISDone As Boolean
    Public XlAppli As New XlClass
    Function ConnexionStatus() As Boolean
        'Verifi l'etat de la connection reseau
        Dim Status As Long
        ConnexionStatus = (InternetGetConnectedState(Status, 0&) <> 0)
    End Function
    on ajoute au projet un module de classe nommé XlClass
    Et on lui colle le code suivant :

    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
    Option Explicit
     
    Public WithEvents Xl As Excel.Application
    Dim Tableqt() As ClsModQT
     
    Public Sub InitQueryEvent(Wkb As Workbook)
        'ici on associe les querytables à leur classe d'evenements
     
        'on verifi que c'est bien le type d'objet attendu. Ici un workbook
        If TypeOf Wkb Is Workbook Then
            Dim Requete As QueryTable
            Dim Feuille As Worksheet
            Dim i As Integer
            i = 1
            For Each Feuille In Wkb.Worksheets
                If Feuille.QueryTables.Count > 0 Then
                    If i = 1 Then
                        ReDim Preserve Tableqt(Feuille.QueryTables.Count)
                    Else
                        ReDim Preserve Tableqt(UBound(Tableqt) + Feuille.QueryTables.Count)
                    End If
                    For Each Requete In Feuille.QueryTables
                        Set Tableqt(i) = New ClsModQT
                        Set Tableqt(i).qtQueryTable = Requete
                        i = i + 1
                    Next
                End If
            Next
        End If
    End Sub
    'Permet de vider la classe
    Public Sub EmptyQtClass()
        Dim j As Integer
        On Error Resume Next
        For j = 1 To UBound(Tableqt)
            Set Tableqt(j) = Nothing
        Next
    End Sub
    On ajoute un 2ieme module de classe que tu nommes ClsModQT
    puis on lui colles le code suivant :

    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
    Option Explicit
    'si quelqu'un voit une façon plus élégante que celle proposée ici afin de gérer la méthode refreshall sera le bien venu !
    Public WithEvents qtQueryTable As QueryTable
    Public NbQueryTableRefreshOn As Long, NbQueryTableRefreshOff As Long
     
    Private Sub qtQueryTable_AfterRefresh(ByVal Success As Boolean)
        If Success = True Then NbQueryTableRefreshOff = NbQueryTableRefreshOff + 1 'ici on compte le nombre de table actualisées avec succès
        If NbQueryTableRefreshOff = NbQueryTableRefreshOn Then 'on compare le nombre de table actualisées avec le nombre de table à actualiser
            RefreshISDone = Success
            NbQueryTableRefreshOff = 0
            NbQueryTableRefreshOn = 0
        End If
        Debug.Print qtQueryTable.Parent.Name & " refresh done ! "
    End Sub
     
    Private Sub qtQueryTable_BeforeRefresh(Cancel As Boolean)
        NbQueryTableRefreshOn = NbQueryTableRefreshOn + 1 'ici on compte le nombre de tables qui seront actualisées
        Debug.Print "Query tables On " & qtQueryTable.Parent.Name & " refreshing in progress..."
        Debug.Print "Type de la table : " & qtQueryTable.QueryType 'le type de table à actualiser
    End Sub
    Voila la méthode n'est pas simple à mettre en place mais fonctionne de mon coté

    petit rappel :
    /!\ En générale quand on utilise des modules de classe il est préférable de lancer les macros de test depuis excel et pas depuis l’éditeur VBA
    /!\ toutes modifications du code dans un module de class doit être suivi d'un rechargement de la classe !!! cela peut être fait en exécutant "Workbook_Open" du module ThisWorkbook et ce depuis l’éditeur VBA. Exception à la règle précédente
    /!\ tout ajout de table de requêtes dans le classeur doit être suivit d'un rechargement de la classe afin d'être prise en compte par la classe d'evenement. Soit comme expliqué précédemment ou par une fermeture du classeur puis une réouverture.

    Maintenant un code de demo à mettre dans le module ou ce trouve, entre autre, la déclaration de la variable "Public RefreshISDone As Boolean" :

    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
     
     
    Sub DemoRefreshAll()
    If ConnexionStatus = True Then
        Debug.Print "Debut test refresh all..."
        RefreshISDone = False
        ThisWorkbook.RefreshAll
        Do
            DoEvents
            If RefreshISDone = True Then Exit Do
        Loop
        MsgBox "all refreshs are done !"
    Else
        MsgBox "The status of Your Connexion is 'disconnected' !", vbExclamation, " Connection error..."
    End if
    End Sub
    Voila merci d'avance à celles et ceux qui auront le courage de tester tout cela et de me faire un retour.

    Philippe

  2. #2
    Membre averti
    Profil pro
    Inscrit en
    Février 2010
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 194
    Points : 378
    Points
    378
    Par défaut
    Un petit up pour dire que l'on ma fait un retour sur le fait que cela ne fonctionne pas pour les requêtes vers access !!!
    enfin... jusqu’à preuve du contraire

Discussions similaires

  1. Réponses: 12
    Dernier message: 05/10/2011, 15h53
  2. Generation des tables a partir du diagramme de classe - UML
    Par sjfs00 dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 06/04/2010, 23h35
  3. Accès à des tables SAS v9.2 via ODBC
    Par ALLB dans le forum Administration et Installation
    Réponses: 2
    Dernier message: 06/05/2009, 14h21
  4. actualisation des tables après trigger
    Par DarkDev dans le forum PL/SQL
    Réponses: 1
    Dernier message: 04/09/2007, 09h35
  5. Liés des tables de données externes via VBA..
    Par Fritzoune dans le forum Access
    Réponses: 3
    Dernier message: 12/04/2006, 11h08

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