Page 1 sur 1

[R] Fonctions AdlibRegister() imbriquées

Posté : ven. 26 juil. 2024 09:49
par jpascal
Bonjour,

J'utilise plusieurs fonctions _AnimXXX() permettant d'afficher une animation. Ces fonctions utilisent AdlibRegister() et AdlibUnRegister()
Si j'utilise ces fonctions dans une fonction lancée elle-même par un AdlibRegister(), cela ne fonctionne plus. Plus exactement, la fonction _AnimPlay() ne semble pas être exécutée.

Est-ce une limitation ? Y a-t-il une erreur dans mon code ?
Main()

Func Main()
   MsgBox(0, '', 'sans AdlibRegister() : OK')
   Test()

   ConsoleWrite('' & @CRLF)

   MsgBox(0, '', 'avec AdlibRegister() : BAD')
   AdlibRegister('Test')

   Sleep(5000)
EndFunc   ;==>Main

Func Test()
   AdlibUnRegister()
   _AnimStart()
   Sleep(2000)
   _AnimStop()
EndFunc   ;==>Test

Func _AnimStart()
   ConsoleWrite('START' & @CRLF)
   AdlibRegister("_AnimPlay", 10)
EndFunc   ;==>_AnimStart

Func _AnimStop()
   AdlibUnRegister("_AnimPlay")
   ConsoleWrite('STOP' & @CRLF)
EndFunc   ;==>_AnimStop

Func _AnimPlay()
   AdlibUnRegister()
   ConsoleWrite('PLAY' & @CRLF)
   AdlibRegister("_AnimPlay", 10)
EndFunc   ;==>_AnimPlay

Re: [..] Fonctions AdlibRegister() imbriquées

Posté : ven. 26 juil. 2024 23:43
par Nine
L'utilisation de AdlibUnRegister() sans paramètre est plutôt risquée si tu as plusieurs timers à la fois. Si c'est pour afficher des GIF je te suggère mon UDF (voir le site anglo)

Re: [..] Fonctions AdlibRegister() imbriquées

Posté : ven. 26 juil. 2024 23:45
par TommyDDR
AdlibRegister n'est pas fait pour être utilisé de cette façon.
La doc précise : "La fonction adlib doit être le plus simple possible car elle est exécutée souvent et que pendant son temps d'exécution le script principal est mis en pause."

Comme vous l'avez remarqué, quand une fonction appelée par un AdlibRegister, utilise elle même un AdlibRegister, celui-ci n'est pas exécuté car il me semble que la routine qui vérifie si les xxx millisecondes se sont bien écoulées pour éxécuter la fonction associée au AdlibRegister s'exécute dans "le script principal".

Essayez de supprimer la ligne 19 (_AnimStop()) vous verrez que lorsque vous sortez de votre fonction "test" et que vous revenez dans votre programme principal, le _AnimPlay est bien appelé

Re: [..] Fonctions AdlibRegister() imbriquées

Posté : lun. 29 juil. 2024 11:56
par jpascal
Bonjour messieurs,

Merci pour vos réponses instructives.

J'ai découvert avec bonheur l'UDF de Nine (https://www.autoitscript.com/forum/topi ... on-cached/)

Je fais cependant face à un problème insoluble.
Comme il est recommandé de ne pas utiliser de fonctions bloquantes dans WM_NOTIFY(), j'ai pris la (mauvaise ?) habitude d'utiliser AdlibRegister().
Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
...
      Case $idListview
         Switch $iCode
            Case $NM_CLICK
AdlibRegister('MaFonction')
...
EndFunc

Func MaFonction()
AdlibUnregister()
...
EndFunc

J'ai pensé que l'UDF de Nine allait fonctionner car le chargement du GIF animé, même s'il utilise AdlibRegister()
  ; if first GIF, start the timer
  If UBound($aGIF_Animation) = 1 Then AdlibRegister(__GIF_Animation_DrawTimer, 10)
  Return $idPic

EndFunc   ;==>_GUICtrlCreateAnimGIF
... est initialisé avant l'utilisation de WM_NOTIFY() et ensuite, le code est un simple :
Func Test()
   AdlibUnRegister('Test')

   GUICtrlSetState($idPic_AnimGIF, $GUI_SHOW)
   For $i = 1 To 4
      Sleep(500)
      ConsoleWrite($i & @CRLF)
   Next
   GUICtrlSetState($idPic_AnimGIF, $GUI_HIDE)
EndFunc   ;==>Testc
mais cela ne fonctionne pas.

Si je remplace AdlibRegister('Test') par Test() dans WM_NOTIFY(), cela fonctionne.

De plus, si je lance AdlibRegister('Test') après _GUICtrlCreateAnimGIF() pour tester simplement sans ajouter de contrainte supplémentaire, cela ne fonctionne pas non plus.

Du coup le problème ne vient pas seulement de l'imbrication des fonctions AdlibRegister() ?!


AVANT DE POSTER ce message, j'ai quand même préféré tester avec un code simple (celui fourni par Nine avec son UDF) et je ne rencontre pas le problème.
#include <GUIConstants.au3>
#include <Constants.au3>
#include "Cached GIF Animation.au3"
#include <WinAPISysWin.au3>

OnAutoItExitRegister(_GIF_Animation_Quit)

Global $hGUI = GUICreate("GIF Animation", 500, 500, -1, -1, $WS_POPUP, $WS_EX_LAYERED)
GUISetBkColor(0xFFFFFF)
Global $IMG_Ctrl1 = _GUICtrlCreateAnimGIF("9.gif", 150, 0, 192, 172, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl2 = _GUICtrlCreateAnimGIF("gif-Green-UFO.gif", 0, 180, 150, 80, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl3 = _GUICtrlCreateAnimGIF("Catalog.gif", 160, 180, 320, 184, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl4 = _GUICtrlCreateAnimGIF("Kafu.gif", 30, 260, 90, 90, -1, $GUI_WS_EX_PARENTDRAG)
Local $idButton = GUICtrlCreateButton("Hide", 10, 10, 80, 30)
Local $idQuit = GUICtrlCreateButton("Quit", 10, 50, 80, 30)
Local $idAdlib = GUICtrlCreateButton("Adlib", 10, 90, 80, 30)

_WinAPI_SetLayeredWindowAttributes($hGUI, 0xFFFFFF)

GUISetState(@SW_SHOW, $hGUI)

Local $aCaption[4] = ["Show", "Delete", "Recreate", "Hide"], $iCounter = -1


While True
   Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE, $idQuit
         ExitLoop
      Case $idAdlib
         AdlibRegister('Test')
      Case $idButton
         $iCounter += 1
         $iCounter = Mod($iCounter, 4)
         GUICtrlSetData($idButton, $aCaption[$iCounter])
         Switch $iCounter
            Case 0 ; hide
               GUICtrlSetState($IMG_Ctrl2, $GUI_HIDE)
            Case 1 ; show
               GUICtrlSetState($IMG_Ctrl2, $GUI_SHOW)
            Case 2 ; delete
               _GUICtrlDeleteAnimGIF($IMG_Ctrl2)
            Case 3 ; recreate
               $IMG_Ctrl2 = _GUICtrlCreateAnimGIF("gif-Green-UFO.gif", 0, 180, 150, 80, -1, $GUI_WS_EX_PARENTDRAG)
               _WinAPI_SetLayeredWindowAttributes($hGUI, 0xFFFFFF)
         EndSwitch
   EndSwitch
WEnd

_GIF_Animation_Quit()


Func Test()
   AdlibUnRegister('Test')

   GUICtrlSetState($IMG_Ctrl2, $GUI_HIDE)
   For $i = 1 To 3
      Sleep(500)
      ConsoleWrite($i & @CRLF)
   Next
   GUICtrlSetState($IMG_Ctrl2, $GUI_SHOW)
EndFunc   ;==>Test

Je cherche...

Re: [..] Fonctions AdlibRegister() imbriquées

Posté : lun. 29 juil. 2024 12:20
par jpascal
Et ce n'est pas un problème lié à Opt("GUIOnEventMode", 1)

#include <ResourcesEx.au3>

#include <GUIConstants.au3>
#include <Constants.au3>
#include "Cached GIF Animation.au3"
#include <WinAPISysWin.au3>

Opt("GUIOnEventMode", 1)

;~ OnAutoItExitRegister(_GIF_Animation_Quit)

Global $hGUI = GUICreate("GIF Animation", 500, 500, -1, -1, $WS_POPUP, $WS_EX_LAYERED)
GUISetOnEvent($GUI_EVENT_CLOSE, 'ExitApp')
GUISetBkColor(0xFFFFFF)
Global $IMG_Ctrl1 = _GUICtrlCreateAnimGIF("9.gif", 150, 0, 192, 172, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl2 = _GUICtrlCreateAnimGIF("gif-Green-UFO.gif", 0, 180, 150, 80, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl3 = _GUICtrlCreateAnimGIF("Catalog.gif", 160, 180, 320, 184, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl4 = _GUICtrlCreateAnimGIF("Kafu.gif", 30, 260, 90, 90, -1, $GUI_WS_EX_PARENTDRAG)
Global $idButton = GUICtrlCreateButton("Hide", 10, 10, 80, 30)
GUICtrlSetOnEvent(-1, 'Button')
GUICtrlCreateButton("Quit", 10, 50, 80, 30)
GUICtrlSetOnEvent(-1, 'ExitApp')
GUICtrlCreateButton("Adlib", 10, 90, 80, 30)
GUICtrlSetOnEvent(-1, 'Adlib')

_WinAPI_SetLayeredWindowAttributes($hGUI, 0xFFFFFF)

GUISetState(@SW_SHOW, $hGUI)

Global $aCaption[4] = ["Show", "Delete", "Recreate", "Hide"], $iCounter = -1

While 1
   Sleep(100)
WEnd

Func Button()
   $iCounter += 1
   $iCounter = Mod($iCounter, 4)
   GUICtrlSetData($idButton, $aCaption[$iCounter])
   Switch $iCounter
      Case 0         ; hide
         GUICtrlSetState($IMG_Ctrl2, $GUI_HIDE)
      Case 1         ; show
         GUICtrlSetState($IMG_Ctrl2, $GUI_SHOW)
      Case 2         ; delete
         _GUICtrlDeleteAnimGIF($IMG_Ctrl2)
      Case 3         ; recreate
         $IMG_Ctrl2 = _GUICtrlCreateAnimGIF("gif-Green-UFO.gif", 0, 180, 150, 80, -1, $GUI_WS_EX_PARENTDRAG)
         _WinAPI_SetLayeredWindowAttributes($hGUI, 0xFFFFFF)
   EndSwitch
EndFunc   ;==>Button

Func ExitApp()
   _GIF_Animation_Quit()
   Exit
EndFunc   ;==>ExitApp

Func Adlib()
   AdlibRegister('Test')
EndFunc   ;==>Adlib

Func Test()
   AdlibUnRegister()

   GUICtrlSetState($IMG_Ctrl2, $GUI_HIDE)
   For $i = 1 To 3
      Sleep(500)
      ConsoleWrite($i & @CRLF)
   Next
   GUICtrlSetState($IMG_Ctrl2, $GUI_SHOW)
EndFunc   ;==>Test

Re: [..] Fonctions AdlibRegister() imbriquées

Posté : lun. 29 juil. 2024 13:07
par jpascal
Je viens de comprendre d'où venait le problème sans pour autant avoir de solution.

Dans le code ci-dessus, l'image est affichée. La fonction Test() cache l'image pendant 1500 ms puis l'affiche à nouveau.

Dans le code ci-dessous, l'image est cachée. La fonction Test() doit afficher l'image pendant 1500 ms puis la cacher à nouveau. Cela ne fonctionne pas.

Le problème vient en fait de l'utilisation de :
   For $i = 1 To 3
      Sleep(500)
   Next
ou
   Local $hTimer = TimerInit()
   While 1
      If TimerDiff($hTimer) > 1500 Then ExitLoop
   WEnd
qui "bloque" la fonction __GIF_Animation_DrawTimer()

Dans le code du dessus, nous ne voyons pas ce "blocage" car l'image est cachée.

Sachant que mon but est d'afficher l'image pendant un traitement puis de la cacher ensuite, le problème reste entier.
#include <ResourcesEx.au3>

#include <GUIConstants.au3>
#include <Constants.au3>
#include "Cached GIF Animation.au3"
#include <WinAPISysWin.au3>

Opt("GUIOnEventMode", 1)

;~ OnAutoItExitRegister(_GIF_Animation_Quit)

Global $hGUI = GUICreate("GIF Animation", 500, 500, -1, -1, $WS_POPUP, $WS_EX_LAYERED)
GUISetOnEvent($GUI_EVENT_CLOSE, 'ExitApp')
GUISetBkColor(0xFFFFFF)
Global $IMG_Ctrl1 = _GUICtrlCreateAnimGIF("9.gif", 150, 0, 192, 172, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl2 = _GUICtrlCreateAnimGIF("gif-Green-UFO.gif", 0, 180, 150, 80, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl3 = _GUICtrlCreateAnimGIF("Catalog.gif", 160, 180, 320, 184, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl4 = _GUICtrlCreateAnimGIF("Kafu.gif", 30, 260, 90, 90, -1, $GUI_WS_EX_PARENTDRAG)
Global $idButton = GUICtrlCreateButton("Show", 10, 10, 80, 30)
GUICtrlSetOnEvent(-1, 'Button')
GUICtrlCreateButton("Quit", 10, 50, 80, 30)
GUICtrlSetOnEvent(-1, 'ExitApp')
GUICtrlCreateButton("Adlib", 10, 90, 80, 30)
GUICtrlSetOnEvent(-1, 'Adlib')

_WinAPI_SetLayeredWindowAttributes($hGUI, 0xFFFFFF)

GUISetState(@SW_SHOW, $hGUI)

GUICtrlSetState($IMG_Ctrl2, $GUI_HIDE) ; l'image est cachée au départ

Global $aCaption[4] = ["Show", "Delete", "Recreate", "Hide"], $iCounter = 0

While 1
   Sleep(100)
WEnd

Func Button()
   $iCounter += 1
   $iCounter = Mod($iCounter, 4)
   GUICtrlSetData($idButton, $aCaption[$iCounter])
   Switch $iCounter
      Case 0         ; hide
         GUICtrlSetState($IMG_Ctrl2, $GUI_HIDE)
      Case 1         ; show
         GUICtrlSetState($IMG_Ctrl2, $GUI_SHOW)
      Case 2         ; delete
         _GUICtrlDeleteAnimGIF($IMG_Ctrl2)
      Case 3         ; recreate
         $IMG_Ctrl2 = _GUICtrlCreateAnimGIF("gif-Green-UFO.gif", 0, 180, 150, 80, -1, $GUI_WS_EX_PARENTDRAG)
         _WinAPI_SetLayeredWindowAttributes($hGUI, 0xFFFFFF)
   EndSwitch
EndFunc   ;==>Button

Func ExitApp()
   _GIF_Animation_Quit()
   Exit
EndFunc   ;==>ExitApp

Func Adlib()
   AdlibRegister('Test')
EndFunc   ;==>Adlib

Func Test()
   AdlibUnRegister()

   GUICtrlSetState($IMG_Ctrl2, $GUI_SHOW)
;~    For $i = 1 To 3
;~       Sleep(500)
;~    Next
   Local $hTimer = TimerInit()
   While 1
      If TimerDiff($hTimer) > 1500 Then ExitLoop
   WEnd
   GUICtrlSetState($IMG_Ctrl2, $GUI_HIDE)
EndFunc   ;==>Test

Re: [..] Fonctions AdlibRegister() imbriquées  

Posté : lun. 29 juil. 2024 14:13
par Nine
La solution est de vérifier le timer dans la boucle principale et non dans une boucle secondaire.

Code : Tout sélectionner

#include <GUIConstants.au3>
#include <Constants.au3>
#include "Cached GIF Animation.au3"
#include <WinAPISysWin.au3>

Global $hGUI = GUICreate("GIF Animation", 500, 500, -1, -1, $WS_POPUP, $WS_EX_LAYERED)
GUISetBkColor(0xFFFFFF)
Global $IMG_Ctrl1 = _GUICtrlCreateAnimGIF("9.gif", 150, 0, 192, 172, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl2 = _GUICtrlCreateAnimGIF("gif-Green-UFO.gif", 0, 180, 150, 80, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl3 = _GUICtrlCreateAnimGIF("Catalog.gif", 160, 180, 320, 184, -1, $GUI_WS_EX_PARENTDRAG)
Global $IMG_Ctrl4 = _GUICtrlCreateAnimGIF("Kafu.gif", 30, 260, 90, 90, -1, $GUI_WS_EX_PARENTDRAG)
Global $idButton = GUICtrlCreateButton("Show", 10, 10, 80, 30)
Global $idQuit = GUICtrlCreateButton("Quit", 10, 50, 80, 30)
Global $idAdlib = GUICtrlCreateButton("Adlib", 10, 90, 80, 30)

_WinAPI_SetLayeredWindowAttributes($hGUI, 0xFFFFFF)

GUISetState(@SW_SHOW, $hGUI)

GUICtrlSetState($IMG_Ctrl2, $GUI_HIDE) ; l'image est cachée au départ

Global $aCaption[4] = ["Show", "Delete", "Recreate", "Hide"], $iCounter = 0
Global $hTimer, $bRun = False

While True
  Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE, $idQuit
      ExitApp()
    Case $idButton
      Button()
    Case $idAdlib
      If $bRun Then ContinueLoop
      $bRun = True
      GUICtrlSetState($IMG_Ctrl2, $GUI_SHOW)
      $hTimer = TimerInit()
  EndSwitch
  If $bRun And TimerDiff($hTimer) > 1500 Then
    GUICtrlSetState($IMG_Ctrl2, $GUI_HIDE)
    $bRun = False
  EndIf
WEnd

Func Button()
  $iCounter += 1
  $iCounter = Mod($iCounter, 4)
  GUICtrlSetData($idButton, $aCaption[$iCounter])
  Switch $iCounter
    Case 0           ; hide
      GUICtrlSetState($IMG_Ctrl2, $GUI_HIDE)
    Case 1           ; show
      GUICtrlSetState($IMG_Ctrl2, $GUI_SHOW)
    Case 2           ; delete
      _GUICtrlDeleteAnimGIF($IMG_Ctrl2)
    Case 3           ; recreate
      $IMG_Ctrl2 = _GUICtrlCreateAnimGIF("gif-Green-UFO.gif", 0, 180, 150, 80, -1, $GUI_WS_EX_PARENTDRAG)
      _WinAPI_SetLayeredWindowAttributes($hGUI, 0xFFFFFF)
  EndSwitch
EndFunc   ;==>Button

Func ExitApp()
  _GIF_Animation_Quit()
  Exit
EndFunc   ;==>ExitApp
ps. j'ai converti en non-event par simplification de code

Re: [..] Fonctions AdlibRegister() imbriquées

Posté : lun. 29 juil. 2024 14:16
par TommyDDR
Je pense qu'à votre place, je créerais une variable globale que je changerai à "true" dans le WM_NOTIFY ou autre endroit où vous mettez votre AdlibRegister (à la place du AdlibRegister) et je ferais le traitement dans la boucle principale si cette variable est à True

Re: [..] Fonctions AdlibRegister() imbriquées

Posté : mar. 30 juil. 2024 09:30
par jpascal
Merci messieurs pour vos solutions parfaites et simples à mettre en place. :-)