Comment reprendre la main sur ma userform???

Résolu
rol64 Messages postés 33 Date d'inscription lundi 21 janvier 2008 Statut Membre Dernière intervention 28 novembre 2011 - 22 juin 2009 à 10:47
rol64 Messages postés 33 Date d'inscription lundi 21 janvier 2008 Statut Membre Dernière intervention 28 novembre 2011 - 24 juin 2009 à 08:49
Salut,
Alors je vous met ci-joint le code d'une procédure associée à un bouton:
Private Sub Plannifier_Click()<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" /??>

Dim op

Dim i As Integer

new_wnd = False

 

For i = i_debut To i_finListPDL

    'Récupération du numéro de poste et de la date de fabrication

    import_excel (i)

    'Effacement du presse-papier et chargement avec numéro PDL

    Clipboard.Clear

    Clipboard.SetText ref_PDL

    'Focus sur la fenêtre SAP

    lres = SetForegroundWindow(recherche_wnd)

    'Clic sur Sélection Multiple pour Poste Technique

    evt_clic = simu_leftClic(712, 165)

    'Boucle d'attente jusqu'à l'apparition de la fenêtre suivante

    Do While new_wnd = False

      DoEvents

      op = chgt_wnd("Séle")

    Loop

    new_wnd = False

    'Effacer les champs de la séléction multiple

    evt_clic = simu_leftClic(178, 490)

    Sleep 1000

    'Clic sur chargement du presse-papiers

    evt_clic = simu_leftClic(375, 492)

    Sleep 2000

    ' Touche F8 pour valider

    Call keybd_event(VK_F8, 0, 0, 0)

    Call keybd_event(VK_F8, 0, KEYEVENTF_KEYUP, 0)

    Sleep 1000

    ' Touche F8 pour rechercher

    Call keybd_event(VK_F8, 0, 0, 0)

    Call keybd_event(VK_F8, 0, KEYEVENTF_KEYUP, 0)

    Sleep 2000

    ' Selectionner tout

    evt_clic = simu_leftClic(13, 144)

    'Clic sur Mise à jour du préventitf

    evt_clic = simu_leftClic(389, 107)

    Do While new_wnd = False

      DoEvents

      op = chgt_wnd("Mise")

    Loop

    new_wnd = False

    ' F2 Valider Mise à jour

    evt_clic = simu_leftClic(48, 719)

    Do While new_wnd = False

      DoEvents

      op = chgt_wnd("Date")

    Loop

    ' Récupération de la date et écriture

    ecrire_date (date_planif)

    'Validation Entrée créer le plan d'entretient

    Call keybd_event(VK_RETURN, 0, 0, 0)

    Call keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0)

    Sleep 1000

    'Suite par Entrée

    evt_clic = simu_leftClic(229, 366)

    Sleep 1000

    'Retour

    evt_clic = simu_leftClic(271, 42)

    Sleep 1000

    'test du bouton quitter

    If BTN_quitter = True
      Exit For
    End If  
Next

End Sub

**********************************************************************************************
Je vous décris le but de cette procédure. Elle sert à simuler une séquence d'évènement clavier et souris pour automatiser l'import de données depuis un fichier excel vers une fenêtre SAP. Tout se fait par voie graphique, c'est une sorte de input batch mais via interface graphique ce qui comporte certains inconvénients notamment la nécessité d'avoir une syncronisation parfaite entre les simulations d'évènements et la succession des fenêtres SAP ( le pire dans l'histoire c'est qu'il existe une transaction prévue exprès sous SAP mais les admin ne veulent pas m'autoriser à l'utiliser...) . Lorsque cela a été possible, j'ai solutionné cette synchronisation en insérant des boucles d'attente comme

Do While new_wnd = False

      DoEvents

      op = chgt_wnd("Date")

    Loop

qui teste un booléen positionné à vrai par la fonction chgt_wnd("Date") lorsqu'une fenêtre ayant les meme 4 premiers caractères dans sa barre de titre existe. (l'argument "est" (ou sont?) les 4 premiers caractères du titre de la fenêtre qui apparait suite au clic/appui clavier précédent).

 

Comme vous pouvez le voir je ne peux pas toujours utiliser ce moyen de synchronisation (qui marche d'ailleurs à merveille!) puisque il peut arriver que je simule plusieurs évènement sur une fenêtre ayant toujours le même titre. Et en cherchant bien je n'ai pas trouvé d'autre moyen que de mettre une boucle d'attente sleep pour etre sur qu'il y ait suffisamment de temps entre deux simulations d'évènements, sans quoi les fenêtres SAP ne sont plus synchronisées avec mes simulations claviers/souris et la ca plante. Ca marche  plutot bien mais les sleep ne sont pas top pour 2 raisons:

1/ le temps n'est pas optimisé, donc je perds du temps si mon évènement ne nécessite que une demi seconde de temporisation et que j'en met pour 2 secondes. D'ou ma préférence de pouvoir lancer chaque simulation d'évènement qu'après confirmation par un moyen quelconque utilisant les API (un message qui indique la fin d'une fonction par exemple. Est il possible de savoir qund mon application a fini de répondre à l'èvènement clavier simulé précèdemment?)

2/ Je souhaiterai ajouter un bouton qui me permette de terminer la procédure ci-dessus (plannifier_click()) à tout moment. Cependant une fois ma procédure plannifier_click() lancée, je perds la main sur ma userform!!! Sans doute à cause des sleep!? Il m'est impossible de clicker sur le bouton quitter. Le curseur de souris a toujours le petit sablier et les clics ne sont pas pris en compte... Que dois je rajouter à ma procédure plannifier_click() pour qu'elle permette la prise en compte d'un évènement qui lui soit exterieur comme le clic sur le bouton quitter? Mon bouton quitter positionne un booleen (BTN_quitter  à "vrai" et est testé dans la boucle For).

En espérant que je sui assez claire...
N'hésitez pas à me demander des éclaircissements...

2 réponses

cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
22 juin 2009 à 14:39
Salut
Sleep n'est pas une pause, c'est seulement un blocage temporisé de ton application, donc pas reprise en main possible.
Pour pouvoir stopper ton programme, ajoute un DoEvents après chaque Sleep.
Pour interrompre par programme, ajoute ceci dans la partie déclaration de ton code :
   Private bStop As Boolean
puis, dans ton bouton de demande d'interruption :
   bStop = True
Bien sûr, dans le reste du programme (après tes DoEvents par exemple), il faudra tester l'état de booléen :
   If bStop Then Exit Function
Sans oublier la remise à zéro de ce booléen en tête de procédure.

Pour tes histoires de durée de Sleep, pas le choix : Soit tu estime le temps de réaction du programme que tu pilotes (ce que tu fais), soit tu utilises une méthode beaucoup plus lourde mais beaucoup plus efficace qui consiste à :
- Trouver le handle de la fenêtre cible - GetWindowText
- Une fois trouvé, rechercher les handles des objets enfants (Chid) pour retrouver un bouton ou une zône de saisie (GetWindow)
- Une fois le handle final trouvé, envoyer un clic (mouse_event) ou un texte (SendMessage).

Un exemple qui recherche une zone de saisie, écrit un texte, recherche le bouton Ok et clic dessus :

Public Function mChercheEditEtRemplit(ByVal ParentHwnd As Long, _
                                      ByVal sTexte As String) As Boolean




    ' Ecrit le nom du fichier à utiliser à une fentre de selection
    ' Renvoie True si Ok
    Dim sTemp As String
    Dim r As Long
    Dim sClasse As String
    Dim mHwnd As Long
    Dim Carré As RECT
   
    ' Cherche la ligne Edit 
    Screen.MousePointer = vbHourglass
        DoEvents
        Call Sleep(250)
    Screen.MousePointer = vbDefault
    mHwnd = GetWindow(ParentHwnd, GW_CHILD)
    Do While mHwnd <> 0
        sClasse = String(256, "<")
        r = GetClassName(mHwnd, sClasse, 256)
        sClasse = Left$(sClasse, r)
        If LCase(sClasse) = "edit" Then
            Exit Do
        End If
        mHwnd = GetWindow(mHwnd, GW_HWNDNEXT)
        DoEvents
    Loop
    If mHwnd = 0 Then Exit Function
   
    ' Envoie le texte
    DoEvents
    sTemp = StrConv(sTexte, vbFromUnicode, ByVal 1033)
    Call SendMessage(mHwnd, WM_SETTEXT, ByVal 0&, ByVal StrPtr(sTemp))
    DoEvents
   
    ' Cherche le bouton Ouvrir et Clic
    mHwnd = GetWindow(ParentHwnd, GW_CHILD)
    Do While mHwnd <> 0
        sClasse = String(256, "<")
        r = GetClassName(mHwnd, sClasse, 256)
        sClasse = Left$(sClasse, r)
        If LCase(sClasse) = "button" Then
            sTemp = String(256, "<")
            r = GetWindowText(mHwnd, sTemp, 256)
            sTemp = Left$(sTemp, r)
            If LCase(sTemp) Like "*ouvrir" Then
                Call GetWindowRect(mHwnd, Carré)
                With Carré
                    .Left = ((.Right - .Left) / 2) + .Left
                    .Top = ((.Bottom - .Top) / 2) + .Top
                End With
                Call SetCursorPos(Carré.Left, Carré.Top)
                Call mouse_event(MOUSEEVENTF_LEFTDOWN Or MOUSEEVENTF_LEFTUP, 0, 0, 0, ByVal 0)
                Exit Do
            End If
        End If
        mHwnd = GetWindow(mHwnd, GW_HWNDNEXT)
        DoEvents
    Loop
    If mHwnd = 0 Then Exit Function
   
    mChercheEditEtRemplit = True
   
End Function


Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés





<hr />

Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
3
rol64 Messages postés 33 Date d'inscription lundi 21 janvier 2008 Statut Membre Dernière intervention 28 novembre 2011
24 juin 2009 à 08:49
Salut Jack!
Je te remercie pour ta réponse, ca marche très bien!!!! Et ca m'a permis de comprendre le fonctionnement de cette bete noire d'api "sleep"!!!! Pour ce qui est de la seconde méthode je la met déjà plus ou moins en pratique, cependant mes fonctions sleep restent indispensables pour laisser un laps de temps entre une première simulation d'évènement clavier/souris et l'exécution de l'instruction suivante.
Encore merci!!! C'est vraiment appréciable de recvoir de l'aide de personnes plus expérimentées!!!
A+
0
Rejoignez-nous