Jump to content

How to keep GUI always in responsive state


Go to solution Solved by jdelaney,

Recommended Posts

Hi :) ,

How can i keep my GUI with buttons in a responsive state even if script is waiting for a window?

Example: Click in "Wait Excel" (waits for a Excel file to exist). The buttons "Stop" and "msgbox" dont work because is waiting for excel...

Its possible to make them work?

Thanks in advance

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>


#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Form1", 623, 446, 192, 114)
$Button1 = GUICtrlCreateButton("Wait excell", 192, 64, 105, 49)
$Button2 = GUICtrlCreateButton("Stop", 192, 136, 105, 49)
$Button3 = GUICtrlCreateButton("msgbox", 192, 208, 105, 49)

GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###




While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button2
            Exit
        Case $Button1
        WinWait("Microsoft Excel", "GSO")
        Case $Button3
            MsgBox(0, "test", "ABC")
    EndSwitch
WEnd
Edited by gspot
Link to comment
Share on other sites

You could use the timeout parameter of Winwait() and verify the return value of the function Winwait(). If the call is successful, you go on with your script. If it's not, set a constant to true when the process exits WinWait(). Then when coming back on top of the while loop,  check the constant value. If it's true, check if $nMsg is same as $Button3. If it is, run the $Button3 command (in your sample, display a msgbox). Then set $nMsg back to $Button1.

In short, replace your while loop with this:

 
Local $Flag = False
While 1
    $nMsg = GUIGetMsg()
if $Flag = True Then
if $nMsg = $Button3 Then
MsgBox(0, "test", "ABC")
EndIf
$nMsg = $Button1
EndIf
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button2
            Exit
        Case $Button1
        $Flag = WinWait("Microsoft Excel", "GSO", 1) = 0 ; will set $Flag to true if winwait did not find excel, else false
        Case $Button3
            MsgBox(0, "test", "ABC")
    EndSwitch
WEnd
Link to comment
Share on other sites

 

You could use the timeout parameter of Winwait() and verify the return value of the function Winwait(). If the call is successful, you go on with your script. If it's not, set a constant to true when the process exits WinWait(). Then when coming back on top of the while loop,  check the constant value. If it's true, check if $nMsg is same as $Button3. If it is, run the $Button3 command (in your sample, display a msgbox). Then set $nMsg back to $Button1.

In short, replace your while loop with this:

 
Local $Flag = False
While 1
    $nMsg = GUIGetMsg()
if $Flag = True Then
if $nMsg = $Button3 Then
MsgBox(0, "test", "ABC")
EndIf
$nMsg = $Button1
EndIf
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button2
            Exit
        Case $Button1
        $Flag = WinWait("Microsoft Excel", "GSO", 1) = 0 ; will set $Flag to true if winwait did not find excel, else false
        Case $Button3
            MsgBox(0, "test", "ABC")
    EndSwitch
WEnd

 

 

Didnt work for me. GUI doesn't respond after clicking "Wait Excel"... 

Link to comment
Share on other sites

You can "run" (NOT runwait) a second, parallel process (another script), durring the loop, wait for the process to end, and then get it's return value...forum search _Parallel_CreateProcess..._processexistsbyhandle.

That way, your gui will always respond, and you can get the return of your function.

Edited by jdelaney
IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.
Link to comment
Share on other sites

You can "run" (NOT runwait) a second, parallel process (another script), durring the loop, wait for the process to end, and then get it's return value...forum search _Parallel_CreateProcess..._processexistsbyhandle.

That way, your gui will always respond, and you can get the return of your function.

 

I think thats a little advanced for me, can you give a simple example or where i can see some examples? Thanks for the help

Link to comment
Share on other sites

  • Solution

Here is an example of the gui always being responsive:

#include <GUIConstantsEx.au3>
#include <WinAPI.au3>
#include <Constants.au3>
#include <WindowsConstants.au3>
$aProcess = ""
$iProcessesCreated = 1
$iMsgBoxCreated = 1
$iMsgBox = ""
$Form1 = GUICreate("Form1", 623, 446, 192, 114)
$Button1 = GUICtrlCreateButton("Wait excell", 192, 64, 105, 49)
$Button2 = GUICtrlCreateButton("Stop", 192, 136, 105, 49)
$Button3 = GUICtrlCreateButton("msgbox", 192, 208, 105, 49)

GUISetState(@SW_SHOW)

Local $Flag = False
While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            If IsArray($aProcess) Then
                ConsoleWrite("Killing prior task that was initiated" & @CRLF)
                ProcessClose($aProcess[0])
            EndIf
            If $iMsgBox Then ProcessClose($iMsgBox)
            Exit
        Case $Button2
            If IsArray($aProcess) Then
                ConsoleWrite("Killing prior task that was initiated" & @CRLF)
                ProcessClose($aProcess[0])
            EndIf
            If $iMsgBox Then ProcessClose($iMsgBox)
            Exit
        Case $Button1
            $iCounter = 1
            If IsArray($aProcess) Then
                ConsoleWrite("Killing prior task that was initiated" & @CRLF)
                ProcessClose($aProcess[0])
            EndIf
            $sCommand = 'AutoIt3.exe /ErrorStdOut /AutoIt3ExecuteLine "Exit (Sleep(5000))+' & $iProcessesCreated & '"'
            $iProcessesCreated+=1
            $aProcess = _Parallel_CreateProcess($sCommand)
        Case $Button3
            If $iMsgBox Then ProcessClose($iMsgBox)
            $sCommand = 'AutoIt3.exe /ErrorStdOut /AutoIt3ExecuteLine "MsgBox(0, ''test'', ''ABC...Initiated=[' & $iMsgBoxCreated & ']x'')"'
            $iMsgBoxCreated += 1
            $iMsgBox = Run($sCommand)
    EndSwitch
    If IsArray($aProcess) Then
        $iCounter+=1
        If IsInt($iCounter/50) Then
            ConsoleWrite("Your command is still running" & @CRLF)
        EndIf
        If Not _ProcessExistsByHandle($aProcess[1],10) Then
            $iReturnOfResult=@extended
            ConsoleWrite("Returned=" & $iReturnOfResult & @CRLF)
            $aProcess = 0
        EndIf
    EndIf
    Sleep (10)
WEnd
Exit

Func _Parallel_CreateProcess($sCommand, $sWrkDir="", $iShow=@SW_MINIMIZE, $iOpts=0)
; #FUNCTION# ====================================================================================================================
; Name ..........: _Parallel_CreateProcess
; Description ...: Launch a new process.
; Syntax ........: _Parallel_CreateProcess($sCommand, $sWrkDir, $iShow, $iOpts)
; Parameters ....: $sCommand            - Command line including parameters.
;                  $sWrkDir             - Working directory. Default = "".
;                  $iShow               - Initial state of any application window, any of the @SW_ macros.
;                  $iOpts               - Options 0x10 or 0x10000 from internal Run() command, BitOR'd.
; Return values .: Success - A two element array:
;                           [0] - PID
;                           [1] - process handle (MUST be closed when finished with it)
;                  Failure - Sets @error = 1 and returns 0 as PID and handle
; Author ........: Erik Pilsits
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
    ; use options provided by internal Run() command for consistent usage
    ; but only supports 0x10 and 0x10000
    ;
    Local $aRet[2] = [0, 0]
    Local $sSTARTUP = DllStructCreate($tagSTARTUPINFO)
    Local $sPROCINFO = DllStructCreate($tagPROCESS_INFORMATION)
    DllStructSetData($sSTARTUP, "Size", DllStructGetSize($sSTARTUP))
    DllStructSetData($sSTARTUP, "Flags", $STARTF_USESHOWWINDOW)
    DllStructSetData($sSTARTUP, "ShowWindow", $iShow)
    ;
    ; check options
    If BitAND($iOpts, 0x10) = 0x10 Then
        ; inherit parent stdio handles
        DllStructSetData($sSTARTUP, "Flags", BitOR($STARTF_USESHOWWINDOW, $STARTF_USESTDHANDLES))
        DllStructSetData($sSTARTUP, "StdInput", _WinAPI_GetStdHandle(0))
        DllStructSetData($sSTARTUP, "StdOutput", _WinAPI_GetStdHandle(1))
        DllStructSetData($sSTARTUP, "StdError", _WinAPI_GetStdHandle(2))
    EndIf
    Local $dwCreationFlags = 0
    If BitAND($iOpts, 0x10000) = 0x10000 Then
        ; CREATE_NEW_CONSOLE = 0x10
        $dwCreationFlags = 0x10
    EndIf
    ; check working dir
    Local $sWrkDirType = "wstr"
    If $sWrkDir = "" Then
        $sWrkDirType = "ptr"
        $sWrkDir = 0
    EndIf
    ;
    Local $ret = DllCall("kernel32.dll", "bool", "CreateProcessW", "ptr", 0, "wstr", $sCommand, "ptr", 0, "ptr", 0, "bool", 0, _
            "dword", $dwCreationFlags, "ptr", 0, $sWrkDirType, $sWrkDir, "struct*", $sSTARTUP, "struct*", $sPROCINFO)
    If @error Or Not $ret[0] Then Return SetError(1, 0, $aRet)
    ;
    ; close unused thread handle
    _WinAPI_CloseHandle(DllStructGetData($sPROCINFO, "hThread"))
    ;
    ; return array of info, [0] = PID, [1] = process handle
    $aRet[0] = DllStructGetData($sPROCINFO, "ProcessID")
    $aRet[1] = DllStructGetData($sPROCINFO, "hProcess")
    Return SetError(0, 0, $aRet)
EndFunc   ;==>_Parallel_CreateProcess

Func _ProcessExistsByHandle($hProc,$iTimeOutMilSec)
; #FUNCTION# ====================================================================================================================
; Name ..........: _ProcessExistsByHandle
; Description ...: Check if a process exists by handle.
; Syntax ........: _ProcessExistsByHandle($hProc)
; Parameters ....: $hProc               - Open handle to a process, for example from a call to OpenProcess.
; Return values .: Success - 0 if process has ended, 1 if it still exists
;                  @extended contains the exit code
;                  Failure - 0 and sets @error
; Author ........: Erik Pilsits
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
    ; there was an error creating the process
    If Not $hProc Then Return SetError(1, 0, 0)
    ;
    Local $iExit = DllCall("kernel32.dll", "bool", "GetExitCodeProcess", "handle", $hProc, "dword*", -1)
    If @error Or (Not $iExit[0]) Then
        ; error
        Return SetError(1, 0, 0)
    ElseIf $iExit[2] = 259 Then
        ; process STILL_ACTIVE
        ; extra check if process used STILL_ACTIVE as a valid exit code, $WAIT_OBJECT_0
        If _WinAPI_WaitForSingleObject($hProc, $iTimeOutMilSec) = 0 Then
            If $iExit[2] = 259 Then
                _ProcessExistsByHandle($hProc,$iTimeOutMilSec)
                Return SetExtended(@extended,0)
            Else
                Return SetExtended($iExit[2], 0)
            EndIf
        Else
            Return 1
        EndIf
    Else
        ; process does not exist, return exit code in @extended
        Return SetExtended($iExit[2], 0)
    EndIf
EndFunc   ;==>_ProcessExistsByHandle
Edited by jdelaney
IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.
Link to comment
Share on other sites

Personally, I would have done it like this:
 

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GuiMenu.au3>
 #include <WinAPI.au3>

Global $Counter = 0;
Global $isCounting = False;

Global $WaitExcel = False;
Global $WaitExcelTimeOut = 0;
Global $ExcelTimeNow = null;

$Form1 = GUICreate("Count 1 to 100", 250, 240)
$Button1 = GUICtrlCreateButton("Start", 15, 15, 75, 25)
$Label1 = GUICtrlCreateLabel("0", 135, 16, 40, 17)
$Button2 = GUICtrlCreateButton("Stop", 15, 55, 75, 25)
$Button3 = GUICtrlCreateButton("Reset", 15, 95, 75, 25)

$Button4 = GUICtrlCreateButton("Start Excel", 15, 155, 75, 25)
$Button5 = GUICtrlCreateButton("Stop waiting Excel", 15, 195, 100, 25)
GUISetState(@SW_SHOW)

GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")

While 1
    Sleep(10);

    ;----- loop that can be broken: ----------
    if ($isCounting AND $Counter < 100) Then
        While $Counter < 100 AND $isCounting
            $Counter += 1
            GUICtrlSetData($Label1, $Counter)
            Sleep(100)
        WEnd
        $isCounting = False;
    EndIf
    ;-----------------------------------------

    ;-----------------------------------------
    if ($WaitExcel) Then
        While 1
            if WinExists("Microsoft Excel", "") Then
                MsgBox(0, "Success", "Excel is up and running!")
                ExitLoop
            EndIf
            if NOT $WaitExcel Then
                MsgBox(0, "Canceled", "You are no longer waiting for excel!")
                ExitLoop
            EndIf
            if $ExcelTimeNow <> null AND $WaitExcelTimeOut > 0 Then
                if (TimerDiff($ExcelTimeNow) >= $WaitExcelTimeOut*1000) then
                    MsgBox(0, "Timed out", "You are no longer waiting for excel!" & @CRLF & "Timed out.")
                    ExitLoop
                EndIf
            EndIf
            Sleep(10);
        WEnd
        $WaitExcel = False;
    EndIf
    ;-----------------------------------------
WEnd


Func WM_SYSCOMMAND($hWnd, $iMsg, $WParam, $LParam)
    Switch $hWnd
        Case $Form1
            Switch $WParam
                Case $SC_CLOSE ;X button in the GUI form
                    Exit;
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc

Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
    Local $nID = BitAND($iwParam, 0x0000FFFF)
    #forceref $hWnd, $iMsg, $iwParam, $ilParam
    $iCode = _WinAPI_HiWord($iwParam)
    Switch $nID
        Case $Button1
            $isCounting = True;
        Case $Button2
            $isCounting = False;
        Case $Button3
            $Counter = 0;
            GUICtrlSetData($Label1, $Counter)
        Case $Button4
            $WaitExcelTimeOut = 30; wait for 30 seconds.
            $ExcelTimeNow = TimerInit();
            ShellExecute("excel.exe");
            $WaitExcel = True;
        Case $Button5
            $WaitExcel = False;
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc
Link to comment
Share on other sites

I like how you break out the gui control loop.

You should add a little more, such as waiting for YOUR instance of excel being opened, and not just ANY instance of a window with "Microsoft Excel" being open.

Edited by jdelaney
IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...