rol64
Messages postés33Date d'inscriptionlundi 21 janvier 2008StatutMembreDernière intervention28 novembre 2011
-
22 juin 2009 à 10:47
rol64
Messages postés33Date d'inscriptionlundi 21 janvier 2008StatutMembreDernière intervention28 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
**********************************************************************************************
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...
cs_Jack
Messages postés14006Date d'inscriptionsamedi 29 décembre 2001StatutModérateurDernière intervention28 août 201579 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
' 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)
rol64
Messages postés33Date d'inscriptionlundi 21 janvier 2008StatutMembreDernière intervention28 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+