Page 1 sur 2
[R] Sortie de boucle & plantage
Posté : lun. 12 mai 2014 17:06
par aulus
Bonjour,
De la GUI mère, j'appelle par un bouton la fonction créant et affichant une GUI fille dont je vous montre le code ci-dessous.
Un bouton [Quitter] appartenant à cette GUI fille termine la boucle et la GUI fille est détruite. Le programme se plante alors sur la GUI mère.
La boucle (qui fonctionne bien) affiche un mot latin puisé dans une base SQLite, laisse quelques secondes à l'utilisateur pour trouver sa traduction, puis affiche la réponse, laisse quelques secondes pour la lire, puis affiche un nouveau mot.
► Afficher le texte
Code : Tout sélectionner
Func CarnetMemoriser()
$arret = 0
$CmGui = GUICreate($version & " : Carnet de mots - Mémorisation", 400, 300, (@DesktopWidth/2) - 200, (@DesktopHeight/2) - 150)
$QuitterBouton = GUICtrlCreateButton("Quitter", 100, 150, 150, 30)
GUICtrlSetOnEvent($QuitterBouton,"quitter")
$QuestionLabel = GUICtrlCreateLabel("",20,20,500,40)
$ReponseLabel = GUICtrlCreateLabel("",20,60,500,40)
GUISetState()
Local $sLocalSQLiteDll = @ScriptDir & "\sqlite3.dll"
_SQLite_Startup($sLocalSQLiteDll, False, 1)
$Base_SQLite = _SQLite_Open($sqlite)
Local $aRow, $hQuery
[color=#FF0000]Do[/color]
_SQLite_Query(-1, "SELECT * FROM liste ORDER BY Random() LIMIT 1;", $hQuery)
[color=#0040FF]While[/color] _SQLite_FetchData($hQuery, $aRow, False, False) = $SQLITE_OK
GUICtrlSetData($QuestionLabel,$aRow[0])
Local $Reponse = ""
$Reponse = $aRow[1]
[color=#0040FF]WEnd[/color]
sleep (3000)
GUICtrlSetData($ReponseLabel,$Reponse)
sleep (2000)
GUICtrlSetData($ReponseLabel,"")
[color=#FF0000]Until $arret = 1[/color]
GUICtrlDelete($QuestionLabel)
GUICtrlDelete($ReponseLabel)
GUIDelete($CmGui)
_SQLite_QueryFinalize($hQuery)
_SQLite_Close ()
_SQLite_Shutdown ()
EndFunc
Func quitter()
$arret = 1
EndFunc
Je vous remercie de m'éclairer sur la cause de ce plantage à la fermeture de la GUI fille.
Re: [..] sortie de boucle & plantage
Posté : lun. 12 mai 2014 17:27
par TommyDDR
Je vous conseille de créer vos gui en début de script et de les afficher / cacher quand vous en avez besoin (au lieu de la créer et supprimer à chaque appel à une fonction), vous gagnez en performance.
Même chose pour le _SQLite_Startup et _SQLite_Shutdown, je vous conseille de faire un startup en début de script et de mettre un OnAutoitExitRegister("exit_sqlite") et de créer la fonction exit_sql qui contiendra le _SQLite_Shutdown, de cette façon vous d'ouvrez la dll qu'une fois et vous êtes dur de la fermer (la dll ^^) lorsque le script sera quitté (regardez l'aide de OnAutoitExitRegister pour plus d'info)
► Afficher le texte
Code : Tout sélectionner
Local $sLocalSQLiteDll = @ScriptDir & "\sqlite3.dll"
_SQLite_Startup($sLocalSQLiteDll, False, 1)
OnAutoItExitRegister("exit_sqlite")
Func exit_sqlite()
_SQLite_Shutdown()
EndFunc
Pour ce qui est de votre problème de plantage, avez-vous la possibilité de fournir un code fonctionnel (cad un code que nous pouvons exécuter tel quel pour reproduire le plantage) ?
Re: [..] sortie de boucle & plantage
Posté : lun. 12 mai 2014 18:01
par mikell
TommyDDR a écrit :de cette façon vous d'ouvrez la dll qu'une fois et vous êtes dur de la fermer
Tu es enrhumé Tommy ?

Re: [..] sortie de boucle & plantage
Posté : lun. 12 mai 2014 18:07
par Tlem
Non non, il est
enrubé enrudé ...

Re: [..] Sortie de boucle & plantage
Posté : lun. 12 mai 2014 18:29
par jchd
Soyez pas rudes avec Tommy.
J'ajouterais aussi qu'il est suffisant d'ouvrir la base au début du programme et de la fermer (la base !) à la fin.
La bonne séquence est donc :
Code : Tout sélectionner
_SQLite_Startup(...)
_SQLite_Open(...)
... corps du programme
_SQLite_Close(...)
_SQLite_Shutdown()
Re: [..] sortie de boucle & plantage
Posté : lun. 12 mai 2014 19:51
par aulus
TommyDDR a écrit :
Pour ce qui est de votre problème de plantage, avez-vous la possibilité de fournir un code fonctionnel (cad un code que nous pouvons exécuter tel quel pour reproduire le plantage) ?
J'ai réduit mon programme originel, mais je l'ai tellement réduit que la fonction Memoriser() ne se lance pas. Je ne vois pas pourquoi.
► Afficher le texte
Code : Tout sélectionner
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#AutoIt3Wrapper_Res_Language=1036
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
#AutoIt3Wrapper_AU3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <GUIConstantsEx.au3>
#include <SQLite.au3>
Global $arret
Global $QuestionLabel
Global $ReponseLabel
Global $MemoriserGui
Global $sqlite = @ScriptDir & "\base.sqlite"
Global $sLocalSQLiteDll = @ScriptDir & "\sqlite3.dll"
_SQLite_Startup($sLocalSQLiteDll, False, 1)
If @error Then MsgBox(0, "Fichier manquant", "Le fichier SQLite3.dll est introuvable !")
Global $Base_SQLite = _SQLite_Open($sqlite)
If @error > 0 Then Exit MsgBox(16, "SQLite Erreur", "La base ne peut être chargée !")
Global $hGUI = GUICreate("Exemple")
Global $mem = GUICtrlCreateButton("Mémoriser", 100, 100, 85, 25)
GUICtrlSetOnEvent($mem,"Memoriser")
Global $iOK = GUICtrlCreateButton("Quitter", 310, 370, 85, 25)
GUICtrlSetOnEvent($iOK,"quitter")
GUISetState(@SW_SHOW, $hGUI)
While 1
Sleep(1000)
WEnd
Opt("GUIOnEventMode", 1) ; Passe en mode événement
Func Memoriser()
$arret = 0
$MemoriserGui = GUICreate("Mémorisation", 600, 600, (@DesktopWidth/2) - 300, (@DesktopHeight/2) - 300)
GuiSetOnEvent(-1, "arret", $MemoriserGui)
$QuestionLabel = GUICtrlCreateLabel("question",20,20,400,40)
$ReponseLabel = GUICtrlCreateLabel("réponse",20,60,400,40)
GUICtrlCreateButton("Quitter", 100, 150, 150, 30)
GUICtrlSetOnEvent(-1,"arret")
GUISetState(@SW_SHOW, $MemoriserGui)
Local $Reponse = ""
Local $aRow, $hQuery
Do
_SQLite_Query(-1, "SELECT * FROM liste ORDER BY Random() LIMIT 1;", $hQuery)
While _SQLite_FetchData($hQuery, $aRow, False, False) = $SQLITE_OK
GUICtrlSetData($QuestionLabel,$aRow[0])
$Reponse = ""
$Reponse = $aRow[1]
WEnd
sleep (3000)
GUICtrlSetData($ReponseLabel,$Reponse)
sleep (2000)
GUICtrlSetData($ReponseLabel,"")
Until $arret = 1
GUICtrlSetData($QuestionLabel, "")
GUICtrlSetData($ReponseLabel, "")
GUICtrlDelete($QuestionLabel)
GUICtrlDelete($ReponseLabel)
GUIDelete($MemoriserGui)
;GUISetState($MemoriserGui, $GUI_HIDE)
EndFunc
Func arret()
$arret = 1
EndFunc
Func quitter()
_SQLite_Close ()
_SQLite_Shutdown ()
Exit
EndFunc
Re: [..] Sortie de boucle & plantage
Posté : lun. 12 mai 2014 23:17
par mikell
J'ai simplifié ton code au max pour isoler le problème et je vois pas pourquoi, mais il semble que la boucle dans la fonction Memoriser() bloque l'exécution du GUICtrlSetOnEvent, c'est très facile à vérifier en manipulant le code cy-dessous
► Afficher le texte
Code : Tout sélectionner
#include <GUIConstantsEx.au3>
#include <SQLite.au3>
Opt("GUIOnEventMode", 1)
Global $arret= 0, $mem, $ok2, $MemoriserGui
Global $hGUI = GUICreate("Exemple")
Global $mem = GUICtrlCreateButton("Mémoriser", 100, 100, 85, 25)
GUICtrlSetOnEvent($mem,"Memoriser")
Global $iOK = GUICtrlCreateButton("Quitter", 310, 370, 85, 25)
GUICtrlSetOnEvent($iOK,"quitter")
GUISetState(@SW_SHOW, $hGUI)
While 1
Sleep(10)
WEnd
Func Memoriser()
$arret = 0
$MemoriserGui = GUICreate("Mémorisation", 600, 600, (@DesktopWidth/2) - 300, (@DesktopHeight/2) - 300)
$ok2 = GUICtrlCreateButton("Quitter", 100, 150, 150, 30)
GUICtrlSetOnEvent($ok2,"arret")
GUISetState(@SW_SHOW, $MemoriserGui)
;While $arret = 0
; sleep (10)
;Wend
;GUIDelete($MemoriserGui)
EndFunc
Func arret()
$arret = 1
msgbox(0,"", $arret)
; GUIDelete($MemoriserGui)
EndFunc
Func quitter()
Exit
EndFunc
Si quelqu'un a la réponse je prends (peut-être un GuiRegisterMsg ?)
En attendant je ne peux que te suggérer de trouver une solution alternative à cette boucle, un AdLibRegister par exemple

Re: [..] Sortie de boucle & plantage
Posté : lun. 12 mai 2014 23:25
par TommyDDR
Voici votre code en un peu plus organisé pour y voir plus clair et en utilisant un AdlibRegister.
Si vous voulez des explication demandez moi.
► Afficher le textecode
Code : Tout sélectionner
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#AutoIt3Wrapper_Res_Language=1036
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
#AutoIt3Wrapper_AU3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <GUIConstantsEx.au3>
#include <SQLite.au3>
Opt("GUIOnEventMode", 1)
Global $hGUI
Global $mem
Global $MemoriserGui
Global $QuestionLabel
Global $ReponseLabel
Global $sqlite = @ScriptDir & "\base.sqlite" ; /!\ /!\ /!\ CREER MANUELLEMENT CE FICHIER AVANT DE LANCER LE PROGRAMME /!\ /!\ /!\
Global $sLocalSQLiteDll = @ScriptDir & "\sqlite3.dll"
Global $Base_SQLite
InitSql()
InitBase()
InitGuis()
GUISetState(@SW_SHOW, $hGUI)
While 1
Sleep(1000)
WEnd
Func InitMemoriser()
GUISetState(@SW_SHOW, $MemoriserGui)
AdlibRegister("Memoriser", 3000)
EndFunc
Func Memoriser()
Local $Reponse = ""
Local $aRow, $hQuery
_SQLite_Query(-1, "SELECT * FROM liste ORDER BY Random() LIMIT 1;", $hQuery)
If(_SQLite_FetchData($hQuery, $aRow, False, False) = $SQLITE_OK) Then
GUICtrlSetData($QuestionLabel,$aRow[0])
$Reponse = ""
$Reponse = $aRow[1]
EndIf
sleep(3000)
GUICtrlSetData($ReponseLabel,$Reponse)
sleep(2000)
GUICtrlSetData($ReponseLabel,"")
GUICtrlSetData($QuestionLabel, "")
GUICtrlSetData($ReponseLabel, "")
EndFunc
Func arret()
GUISetState(@SW_HIDE, $MemoriserGui)
AdlibUnRegister("Memoriser")
EndFunc
Func exit_sqlite()
_SQLite_Close()
_SQLite_Shutdown()
EndFunc
Func InitSql()
_SQLite_Startup($sLocalSQLiteDll, False, 1)
If @error Then
MsgBox(0, "Fichier manquant", "Le fichier SQLite3.dll est introuvable !")
Exit
EndIf
$Base_SQLite = _SQLite_Open($sqlite)
If @error > 0 Then
MsgBox(16, "SQLite Erreur", "La base ne peut être chargée !")
Exit
EndIf
OnAutoItExitRegister("exit_sqlite")
EndFunc
Func InitBase()
;CREATION DE LA BASE-ESSAI A LA PREMIERE OUVERTURE DU PROGRAMME
; à COMMENTER PAR LA SUITE
_SQLite_Exec($Base_SQLite, "CREATE TABLE IF NOT EXISTS liste (latin,francais);")
_SQLite_Exec($Base_SQLite, "INSERT INTO liste VALUES ('cum','quand');")
_SQLite_Exec($Base_SQLite, "INSERT INTO liste VALUES ('dum', 'pendant que');")
_SQLite_Exec($Base_SQLite, "INSERT INTO liste VALUES ('sicut','comme');")
_SQLite_Exec($Base_SQLite, "INSERT INTO liste VALUES ('pater','père');")
_SQLite_Exec($Base_SQLite, "INSERT INTO liste VALUES ('mater', 'mère');")
_SQLite_Exec($Base_SQLite, "INSERT INTO liste VALUES ('sed','mais');")
EndFunc
Func InitGuis()
$hGUI = GUICreate("Exemple")
GUISetOnEvent($GUI_EVENT_CLOSE, "quitter", $hGUI)
$mem = GUICtrlCreateButton("Mémoriser", 100, 100, 85, 25)
GUICtrlSetOnEvent($mem,"InitMemoriser")
$MemoriserGui = GUICreate("Mémorisation", 600, 600, (@DesktopWidth/2) - 300, (@DesktopHeight/2) - 300)
GuiSetOnEvent($GUI_EVENT_CLOSE, "arret", $MemoriserGui)
$QuestionLabel = GUICtrlCreateLabel("",20,20,400,40)
$ReponseLabel = GUICtrlCreateLabel("",20,60,400,40)
EndFunc
Func quitter()
Exit
EndFunc
Edit : Mikell...

Edit 2 : Le plus gros problème était que le GUIOnEventMode se situait après la while 1 ^^' donc nous n'étions pas en mode évenementiel.
Re: [..] Sortie de boucle & plantage
Posté : lun. 12 mai 2014 23:50
par mikell
Hum, dans mon petit code de diagnostic Opt("GUIOnEventMode", 1) est en tête de script et ça merdoie derechef
Ta solution est impec avec son AdLibRegister, mais j'aimerais bien savoir le pourquoi du comment de cette histoire de boucle
Félicitations pour cette prompte guérison
Re: [..] Sortie de boucle & plantage
Posté : mar. 13 mai 2014 08:33
par aulus
Bonjour,
Au vu de la complexité de la chose, je comprends que toutes mes heures passées à cogiter et à tester aient été si nombreuses et sans succès... Je ne pouvais pas m'en sortir.
Je vais appliquer votre code à mon programme durant l'après-midi... Je vous tiendrai au courant.
Grand merci.
Re: [..] Sortie de boucle & plantage
Posté : mar. 13 mai 2014 09:27
par TommyDDR
Si mes souvenirs sont bons, les messages des GUICtrlSetOnEvent ne sont reçu que lorsque nous nous situons dans la boucle principale, un clic enverra bien le message, mais la fonction associée ne sera appelée qu'au retour à la boucle infinie.
Tu peux tester en remplaçant :
Par :
Lance le script, clique sur Memoriser puis sur quitter dans la foulée et attends
Tu verras que rien ne se passe tant qu'on est dans la fonction memoriser et une fois que le sleep est terminé, la fonction se lance.
Re: [..] Sortie de boucle & plantage
Posté : mar. 13 mai 2014 11:49
par TommyDDR
Humm... ce script fonctionne pourtant bien...
► Afficher le textecode
Code : Tout sélectionner
; includes
#include <GUIConstantsEx.au3>
Opt("GUIOnEventMode", 1)
; Ecran principal
$Form1 = GUICreate("test", 200, 200, 300, 200)
GUISetOnEvent($GUI_EVENT_CLOSE, "quit", $Form1)
$bouton1 = GUICtrlCreateButton("OK", 60, 130, 75, 25)
GUICtrlSetOnEvent($bouton1, "btnOk")
GUISetState(@SW_SHOW, $Form1)
While(True)
RunMe()
Sleep(50)
WEnd
Func btnOk()
MsgBox(0, "", "Clic")
EndFunc
Func RunMe()
While(True);
Sleep(50)
WEnd
EndFunc
Func quit()
Exit
EndFunc
EDIT : Ok j'ai compris ! Un evenement n'est déclenché qu'après que l’événement d'avant ai fait sont retour. Ici, l'appel à mémoriser est fait avec un OnEvent donc, tant que celui-ci n'est pas terminé, les events se mettent dans une file en attente.
Re: [..] Sortie de boucle & plantage
Posté : mar. 13 mai 2014 11:54
par GaRydelaMer
Bonjour
la solution c'est d'utiliser:
GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND")
est de modifier la variable globale $Arret dans cette fonction si on clique sur le bouton.
Re: [..] Sortie de boucle & plantage
Posté : mar. 13 mai 2014 12:14
par TommyDDR
Je tiens à préciser qu'il n'est pas très propre de mettre des boucles infinies dans des fonctions appelés par GUICtrlSetOnEvent, vous pouvez toujours vous débrouiller autrement.
Re: [..] Sortie de boucle & plantage
Posté : mar. 13 mai 2014 20:49
par mikell
TommyDDR a écrit :Je tiens à préciser qu'il n'est pas très propre de mettre des boucles infinies dans des fonctions appelés par GUICtrlSetOnEvent
C'est pas faux, surtout si on peut plus sortir de ces boucles
Gary est peut-être un brin catégorique en affirmant que GUIRegisterMsg est LA solution (surtout sans proposer de code) mais dès que j'ai un moment j'essaie ça
Re: [..] Sortie de boucle & plantage
Posté : mar. 13 mai 2014 22:52
par GaRydelaMer
Je confirme que c'est la solution, car en mode événementiel et l'utilisation de de boucle infini c'est la seule solution proposer par AutoIt pour interpréter des messages que windows va envoyer.
Voila du code pour jouer avec les 2 cas commente la ligne GUIRegisterMsg. Dans un autre cas commente la boucle dans la fonction.
► Afficher le texte
Code : Tout sélectionner
Opt("GUIOnEventMode", 1)
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <ButtonConstants.au3>
Global $Arret = False, $hGUI1, $hGUI2
Global $bt_stop1, $bt_stop2, $lbl1, $lbl2
GUIRegisterMsg($WM_COMMAND, "My_WM_Command")
GUI_Main()
While 1
GUICtrlSetData($lbl1, "b1=>" & @HOUR & ":" & @MIN & ":" & @SEC)
If $hGUI2 Then
GUICtrlSetData($lbl2, "b1=>" & @HOUR & ":" & @MIN & ":" & @SEC)
EndIf
Sleep(10)
WEnd
Func GUI_Main()
$hGUI1 = GUICreate("GUI principale")
GUISetOnEvent($GUI_EVENT_CLOSE, "GUIS_Close")
GUICtrlCreateButton("Ouvrir GUI enfant", 10, 10)
GUICtrlSetOnEvent(-1, "GUI_Child")
$lbl1 = GUICtrlCreateLabel("", 10, 50, 100, 20)
$bt_stop1 = GUICtrlCreateButton("Stop", 10, 70)
GUICtrlSetOnEvent(-1, "My_Event_Stop")
GUISetState()
EndFunc
Func GUI_Child()
$hGUI2 = GUICreate("GUI enfant")
GUISetOnEvent($GUI_EVENT_CLOSE, "GUIS_Close")
$bt_stop2 = GUICtrlCreateButton("Stop", 10, 10)
GUICtrlSetOnEvent(-1, "My_Event_Stop")
$lbl2 = GUICtrlCreateLabel("", 10, 50, 100, 20)
GUISetState()
$Arret = False
While 1
Sleep(10)
GUICtrlSetData($lbl2, "b2=>" & @HOUR & ":" & @MIN & ":" & @SEC)
If $Arret Then
ConsoleWrite("Arrêt de la boucle" & @LF)
ExitLoop
EndIf
WEnd
EndFunc
Func GUIS_Close()
Local $hGUI = @GUI_WinHandle
Switch $hGUI
Case $hGUI1
Exit
Case Else
GUIDelete($hGUI2)
$hGUI2 = 0
EndSwitch
EndFunc
Func My_Event_Stop()
ConsoleWrite("My_Event_Stop" & @LF)
$Arret = True
EndFunc
Func My_WM_Command($hGUI, $iMsg, $wParam, $lParam)
#forceref $hGUI, $iMsg, $wParam, $lParam
Local $nID = BitAND($wParam, 0x0000FFFF)
Local $hCtrl = $lParam
Local $iCode = BitShift($wParam, 16)
Switch $iCode
Case $BN_CLICKED
Switch $nID
Case $bt_stop1, $bt_stop2
ConsoleWrite("My_WM_Command" & @LF)
My_Event_Stop()
EndSwitch
EndSwitch
EndFunc
Re: [..] Sortie de boucle & plantage
Posté : mar. 13 mai 2014 22:53
par mikell
Merchi
aulus tu as ta solution
Re: [..] Sortie de boucle & plantage
Posté : mar. 13 mai 2014 23:00
par GaRydelaMer
De rien ^^
Tu peux aussi commenter l'association des événements des boutons, le click sur le bouton est géré dans la fonction My_WM_Command.
Autre point, pendant que la boucle tourne, tu peux même pas fermer la fenêtre mais AutoIt va le garder en file d'attente (teste en cliquant sur la croix, puis clicke le bouton stop).
Edit:
Remarque aussi l'utilisation des macros @GUI_WinHandle dans la fonction GUIS_Close(), il y'en a d'autre à utiliser dans le mode événementiel.
@GUI_CtrlHandle
@GUI_CtrlId
Re: [..] Sortie de boucle & plantage
Posté : mar. 13 mai 2014 23:20
par mikell
C'est beau ...

Re: [..] Sortie de boucle & plantage
Posté : mar. 13 mai 2014 23:33
par jchd
N'y a-t-il pas une échappatoire plus simple en utilisant le (tout récent) qualificatif Volatile pour les fonction "OnEvent" ?
C'est une question, pas une piste. Pour tout dire ces prises de têtes d'IHM me gonflent les choses autant que les joues du chaton...