Sign in to follow this  
Followers 0
Expansion

How to implement a blocking function in a GUI script?

14 posts in this topic

main() is a waiting for a specified window, and I can't use the interface during this period.

How should I develop a GUI application that uses blocking functions?

The only thing that I can think of right now are threads, but I have no clue about threads and AutoIt.

#include <GUIConstantsEx.au3>
#include <TreeviewConstants.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <StaticConstants.au3>
#Include <GuiButton.au3>
#Include <Array.au3>

Opt("GUIOnEventMode", 1)  ; Change to OnEvent mode 

Opt("MustDeclareVars", 1)

Func main()
    
dim  $treeview_hwnd 

$treeview_hwnd =WinWait("Select Folder","") 

......

EndFunc


    dim $mainwindow

    dim $start, $stop, $increment, $decrement, $status

    $mainwindow=GUICreate("My GUI edit", 600, 300)  
    
    $status = GUICtrlCreateEdit("status" ,  0 , 280 , 600, 20, $ES_READONLY)
   
   
    $start = GUICtrlCreateButton (  "Start", 300, 250, 90, 20)
        GUICtrlSetOnEvent(-1, "STARTClicked")
    $stop = GUICtrlCreateButton( "Stop", 400, 250, 90, 20)
        GUICtrlSetOnEvent(-1, 'STOPClicked')
        $increment = GUICtrlCreateButton("+", 100, 250, 90, 20)
        GUICtrlSetOnEvent(-1, "increment")
    $decrement = GUICtrlCreateButton( "-", 200, 250, 90, 20)
    GUICtrlSetOnEvent(-1, "decrement")



    GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")


GUISetState(@SW_SHOW)

Func decrement()
        .......
EndFunc
Func increment()
    .....
EndFunc

        
Func STARTClicked()
    main()
    GUICtrlSetData( $status,  "Started")
EndFunc

Func STOPClicked()
GUICtrlSetData( $status,  "Stopped")
EndFunc     


While 1
  Sleep(1000)  ; Idle around
WEnd

Share this post


Link to post
Share on other sites



Hi Expansion,

you could do a GUISetState(@SW_DISABLE).

Until the "Select Folder" dialogue has finished.

Regards,

Hannes

:)


Regards,Hannes[spoiler]If you can't convince them, confuse them![/spoiler]

Share this post


Link to post
Share on other sites

Hannes123, I don't want to disable the GUI window while main() is waiting for that window to appear. In fact, I want the opposite. I want to be able to use the GUI [clicking buttons, setting edit controls etc] while main() waiting for that window.

Share this post


Link to post
Share on other sites

AutoIt is single threaded, the only way would be to spin off a child process with Run(). There are examples posted where the the script launches another instance of itself with command line options to perform just the blocking functions.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

This sounds complicated, because everytime it finds that window, main() has to update some things on the GUI.

Edited by Expansion

Share this post


Link to post
Share on other sites

You can do it this way:

HotKeySet("^1", "main")
HotKeySet("^2", "block")
Send("^2")
main()

Func main()
    MsgBox(0,"","main")
EndFunc

Func block()
    HotKeySet("^2") ;Either unset the hotkey or ensure it will not interfere.
    ; <do your block routine here, which never returns but loops forever like main>
    ; For now this is testing code
    While 1
    $re=MouseGetPos()
    ToolTip($re[0] & " : " & $re[1], $re[0], $re[1])
    WEnd
    
EndFunc

Sleep(2000000)

Note that any modal dialogs, as demonstrated with the MsgBox(), from either function will pause both, but you can have as many normal (infinite) loops with routines running simultaneously as you wish without interference with each other this way. No need for process level duplication.

Share this post


Link to post
Share on other sites

Scratch that, further testing shows me to be wrong.

Share this post


Link to post
Share on other sites

I thought the OP was meaning to run FileSelectFolder() and keep the GUI responsive while it was up. If the "Select Folder" window already comes from a different process then you just need to do this:

#include <GUIConstantsEx.au3>
#include <TreeviewConstants.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <StaticConstants.au3>
#include <GuiButton.au3>
#include <Array.au3>

Opt("GUIOnEventMode", 1) ; Change to OnEvent mode
Opt("MustDeclareVars", 1)

Global $mainwindow, $treeview_hwnd, $f_WaitForFolder = False
Global $start, $stop, $increment, $decrement, $status

$mainwindow = GUICreate("My GUI edit", 600, 300)
GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")

$status = GUICtrlCreateEdit("status", 0, 280, 600, 20, $ES_READONLY)

$start = GUICtrlCreateButton("Start", 300, 250, 90, 20)
GUICtrlSetOnEvent(-1, "STARTClicked")
$stop = GUICtrlCreateButton("Stop", 400, 250, 90, 20)
GUICtrlSetOnEvent(-1, 'STOPClicked')
$increment = GUICtrlCreateButton("+", 100, 250, 90, 20)
GUICtrlSetOnEvent(-1, "increment")
$decrement = GUICtrlCreateButton("-", 200, 250, 90, 20)
GUICtrlSetOnEvent(-1, "decrement")

GUISetState(@SW_SHOW)

While 1
    If $f_WaitForFolder Then
        $treeview_hwnd = WinWait("Select Folder", "", 1)
        If $treeview_hwnd Then
            $f_WaitForFolder = False
            GUICtrlSetData($status, "Got handle:  " & $treeview_hwnd)
        EndIf
    EndIf
    Sleep(20) ; Idle around
WEnd

Func decrement()
    ; .......
EndFunc   ;==>decrement

Func increment()
    ; .....
EndFunc   ;==>increment

Func STARTClicked()
    $f_WaitForFolder = True
    GUICtrlSetData($status, "Started")
EndFunc   ;==>STARTClicked

Func STOPClicked()
    $f_WaitForFolder = False
    GUICtrlSetData($status, "Stopped")
EndFunc   ;==>STOPClicked

Func CLOSEClicked()
    Exit
EndFunc   ;==>CLOSEClicked

Fixed the bad structure of the OP's script, so it can be read with less confusion.

The problem was going into the event function STARTClicked() and not getting out again as soon as possible. There should be no Wait functions, Sleeps, or length processes in any event function. An event function should handle an event quickly and return so as not to block other events.

The fix here was to have the event functions only switch a flag variable that controls the window check in the main loop.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

Thank you guys!

PsaltyDS, I've followed your idea, but I haven't managed to make it work with GUI as it does without the GUI, yet.

Mainly because I don't have a debugger. I really need a line-by-line execution + a variable monitor, in order to correct it.

This script has the following purpose:

It waits for a specific treeview, and when it detects it, it creates a folder like this: $root & $folder & $number [ex. "C:\My PF\Test\temp \New\ 0" ] and autoselects this folder in the treeview. Eventually, it increments the $number and waits for the next treeview.

Problems that I have:

[partially solved with sleep()] The TreeView, detects newly created folder after a period of time. And TreeView autoselection might fail, if the folder isn't yet detected.

[not solved] it seems that I have to implement something that considers PID too, because the treeview's parent is not a child of the main app's window and I can't use the main app's window handle, and I might get wrong triggering with treeviews from other apps.

[not solved] after merging the "console" script with the GUI, this fails to work, and I haven't discovered my mistakes yet. I really need a line-by-line debugger.

Here's the actual complete code of the whole script.

#include <GUIConstantsEx.au3>
#include <TreeviewConstants.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <StaticConstants.au3>
#include <GuiButton.au3>
#include <Array.au3>

Opt("GUIOnEventMode", 1) ; Change to OnEvent mode
Opt("MustDeclareVars", 1)

Global $mainwindow,  $f_WaitForFolder = False
Global $start, $stop, $increment, $decrement, $status, $pause
Global $handlegui, $rootgui, $foldergui, $numbergui,  $readonlypath
Global $handle, $root, $folder, $number

Global $OSType




Func MakePath($root,$folder,$number)
    dim $path
        If $number<10 Then 
         $path=$root&"\"&$folder&"\"&"0"&$number;&"\0" 
     Else 
         $path=$root&"\"&$folder&"\"&$number;&"\0" 
     EndIf
     return $path
EndFunc


Func TreeViewArray($path)
    
    Dim   $patharray, $temp , $treeviewarray
    
    
    $patharray=StringSplit ( $path, "\", 2) ;2 omits the first element, because it stores the number of strings returned
    
    $patharray[0]=$patharray[0]&")"

    $temp=_ArrayToString($patharray, "|") 
            
    if $OSType==1 Then
        $treeviewarray="Desktop|Computer|Local Disk ("&$temp        
        return $treeviewarray
    Elseif $OSType==2  Then 
        $treeviewarray="Desktop|My Computer|Local Disk ("&$temp 
        return $treeviewarray   
    Else
        return 100
    endif
EndFunc 

Func SelectTreeView($treeview_hwnd,$treeviewpath)
    
    Dim $return, $i,$treeviewarray, $temp, $safe
    
    ;MsgBox(4096, "Error",$treeviewpath )
    $treeviewarray=StringSplit ( $treeviewpath ,"|" , 2 )
    ;MsgBox(4096, "Error",UBound($treeviewarray))
    
    For $i = 1 To UBound($treeviewarray)-1 Step +1
        
    $temp=_ArrayToString($treeviewarray, "|" ,  0 , $i)
    
   ;MsgBox(4096, "temp",$temp)


    $safe=ControlTreeView ( $treeview_hwnd, "", "", "Select", $temp)
     If @error Then
            ;MsgBox(4096, "Error", "SelectTreeView error")
        endif
        Sleep(10)
Next
Endfunc 
        
    
    

Func GetOS()    
    If @OSVersion=="WIN_7" Then 
        $OSType=1
    ElseIf @OSVersion=="WIN_XP" Then 
        $OSType=2
    Else 
        MsgBox(4096, "OS not Win7 nor WinXP")   
    EndIf
EndFunc

Func SetNumber($value)
    Dim $value
$number=$value
EndFunc


Func IncrementNumber()
$number=$number+1
EndFunc


Func DecrementNumber()
$number=$number-1
EndFunc 



Func main($treeview_hwnd)
    

        dim $safe=DirCreate(MakePath($root,$folder,$number))
            $safe=DirCreate(MakePath($root,$folder,$number+1)) ;make the next folder in advance, so that treeview selection doesn't wait
            
        if $safe==1 Then 
            
                ;debug zone for treeview selection 
                ;SelectTreeView($treeview_hwnd, "#1|#1|#1") 
                ;SelectTreeView($treeview_hwnd, "Desktop|My Computer")
                ;SelectTreeView($treeview_hwnd, "Desktop|My Computer|Local Disk (C:)")
                ;SelectTreeView($treeview_hwnd, "Desktop|My Computer|Local Disk (C:)|My PF|") 
                ;SelectTreeView($treeview_hwnd, "Desktop|My Computer|Local Disk (C:)|My PF|Test|") ;Desktop|My Computer|Local Disk (C:)|My PF|Test|temp|New|00
                
                
                Sleep(100)
                
                SelectTreeView($treeview_hwnd, "Desktop|My Computer")
                SelectTreeView($treeview_hwnd, "Desktop|My Computer") ;just to make sure that it selects it, because sometimes it misses it.
                
                if $number==0 Then  ;first time has to wait longer so that treeview sees the folder
                    sleep(2000)
                Endif
                SelectTreeView($treeview_hwnd, TreeViewArray(MakePath($root,$folder,$number)))
                    
            while WinExists($treeview_hwnd) 
                sleep(100) 
            wend
            IncrementNumber()
            
             GUICtrlSetData($handlegui, $handle)
             GUICtrlSetData($rootgui, $root)
             GUICtrlSetData($foldergui, $folder)
             GUICtrlSetData($numbergui, $number)
             GUICtrlSetData($readonlypath, MakePath($root,$folder,$number)) 
             
         Else 
             MsgBox(4096, "Error","DirCreate")  
        EndIf
        
EndFunc





$mainwindow = GUICreate("My GUI edit", 600, 300)
GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")

    GUICtrlCreateLabel ( "handle", 10, 10  )
    $handlegui = GUICtrlCreateEdit("" , 50, 8, 200, 20)     ;isn't used yet, because it seems that the treeview's parent isn't a child of the main app window, I have to implement something that checks PID instead, in order not to interfere
    GUICtrlCreateLabel ( "root", 10, 80  )
    $rootgui = GUICtrlCreateEdit("" , 50,  40, 480, 80, $ES_OEMCONVERT)
    GUICtrlCreateLabel ( "folder", 10, 133  )
    $foldergui = GUICtrlCreateEdit("" , 50, 130, 200, 20)
    GUICtrlCreateLabel ( "number", 10, 163  )
    $numbergui = GUICtrlCreateEdit("" , 50, 161, 200, 20, $ES_NUMBER)
    GUICtrlCreateLabel ( "readonly path", 10, 203  )
    $readonlypath= GUICtrlCreateEdit("" , 90, 191, 440, 40, $ES_READONLY)




$status = GUICtrlCreateEdit("status", 0, 280, 600, 20, $ES_READONLY)

$start = GUICtrlCreateButton("Start", 300, 250, 90, 20)
GUICtrlSetOnEvent(-1, "STARTClicked")
$stop = GUICtrlCreateButton("Stop", 400, 250, 90, 20)
GUICtrlSetOnEvent(-1, 'STOPClicked')
$increment = GUICtrlCreateButton("+", 100, 250, 90, 20)
GUICtrlSetOnEvent(-1, "increment")
$decrement = GUICtrlCreateButton("-", 200, 250, 90, 20)
GUICtrlSetOnEvent(-1, "decrement")
$pause = GUICtrlCreateButton( "Pause", 500, 250, 90, 20)    

GUISetState(@SW_SHOW)

;;;;;;;init stuff
GetOS()
GUICtrlSetData($rootgui, "C:\My PF\Test\temp")
GUICtrlSetData($foldergui,"New")
GUICtrlSetData($numbergui, "0")
;;;;;;;


While 1
    If $f_WaitForFolder Then
       dim $treeview_hwnd = WinWait("Select Folder", "", 1)
        If $treeview_hwnd Then
            $f_WaitForFolder = False
            GUICtrlSetData($status, "Got handle:  " & $treeview_hwnd)
            
            main($treeview_hwnd)
            

        EndIf
    EndIf
    Sleep(20) ; Idle around
WEnd

Func decrement()
   DecrementNumber()
   GUICtrlSetData($readonlypath, MakePath($root,$folder,$number))
EndFunc   ;==>decrement

Func increment()
    IncrementNumber()
    GUICtrlSetData($readonlypath, MakePath($root,$folder,$number))
EndFunc   ;==>increment

Func STARTClicked()
    $f_WaitForFolder = True
    
    
    $root=$rootgui        ;example: "C:\My PF\Test\temp"
    $folder=$foldergui    ;example: "New"
    SetNumber($numbergui)   
    GUICtrlSetData($readonlypath, MakePath($root,$folder,$number))
    
    GUICtrlSetData($status, "Started")
EndFunc   ;==>STARTClicked

Func STOPClicked()
    $f_WaitForFolder = False
    GUICtrlSetData($status, "Stopped")
EndFunc   ;==>STOPClicked

Func CLOSEClicked()
    Exit
EndFunc   ;==>CLOSEClicked
Edited by Expansion

Share this post


Link to post
Share on other sites

Trying to read a scrambled script like that just isn't worth it. I straightened it out once to see what was going on; I'm not going to do again with an even longer version.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

I'll do that, just tell me what's the most effective way to debug in AutoIt. I can't just post MsgBox commands everywhere.

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

I like ConsoleWrite() and then running it in SciTE to see the console outputs. If there will be LOTS of logging info, then I prefer _FileWriteLog() to send it to a file, which also adds Date/Time stamps for you. Or there is _DebugOut().

Stepped execution is not available.

There are debug options in the Tools menu of SciTE4AutoIt3 but I find them excessive, preferring to only set up temporary debug outputs with ConsoleWrite() or _FileWriteLog().

The best practice layout of a script to make it easier for people to read, debug, and maintain is:

1. All compiler directives (i.e. #AutoIt3Wrapper_au3check_parameters)

2. All #includes (i.e. #include <Array.au3>)

3. All Global Opt() statements

4. All Global variable declarations

5. Initial script code

6. All locally declared functions grouped together at the bottom

7. Liberal use of comments throughout.

This things are not technically required by the language, but reduce the pain of reviewing lots of other people's code while trying to help them.

:)

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

Thank you, PsaltyDS.

I've managed to correct the problems using ConsoleWrite.

Share this post


Link to post
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
Sign in to follow this  
Followers 0