Jump to content

How to achieve a responsive GUI while running a function with a loop?


Recommended Posts

Ahoy Autoit Community!

After many trials and errors I am unable to solve a problem I am facing and would appreciate any kind of input or better yet a solution :)

The Premise: An embeded slideshow viewer that runs after double-clicking an item in a ListView (each item will generate a different slideshow images).

The Setup: GUI with a ListView Control and a simple exit button.

The Issue: Once double clicked the slide plays however the GUI "locks"/non responsive until the slide is over. Same thing if I click on the "Test" button.

The Culprit: I believe since it's in the images loop it can't accept any other commands until that loop is over.

The Wish: I want to be able to use the GUI functions (selecting other items, clicking on button etc.) while the slideshow plays.

The Code (stripped and simplified as much as I could):

#include <GuiListView.au3>
#include <File.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1)

HotKeySet("{Esc}", "_Exit")

Global $c=0
Global $ssGDI[3], $ssGraphic[2], $ssImage
Global Const $bg_color = "000000"
Global Const $ssW = 480, $ssH = 320
Global $aFiles = _FileListToArrayRec("d:\testStage\", "*.jpg;*.png;*.bmp;*.gif;*.JPG;*.PNG;*.BMP;*.GIF", $FLTAR_FILES, $FLTAR_NORECUR ,$FLTAR_SORT ,$FLTAR_FULLPATH )


$guiW = 1200
$guiH = 726
$mainWindow = GUICreate("Slideshow Viewer", $guiW, $guiH, -1, -1, $WS_POPUP)
$Button1 = GUICtrlCreateButton("Exit", 0, 0, 50, 50)
GUICtrlSetOnEvent($Button1, "_Exit")
$Button1 = GUICtrlCreateButton("Test", 60, 0, 50, 50)
GUICtrlSetOnEvent($Button1, "Test")


Global $ListView = GUICtrlCreateListView("Entry Name|Category", 5, 75, 195, 280)
_GUICtrlListView_SetColumnWidth ($ListView, 0, 100)
_GUICtrlListView_SetColumnWidth ($ListView, 1, 100)
GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES)
GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_FULLROWSELECT, $LVS_EX_FULLROWSELECT)
GUICtrlCreateListViewItem("Name 1|Category 1", $ListView)
GUICtrlCreateListViewItem("Name 2|Category 2", $ListView)

screenshotWidgetInit($ssW,$ssH, 690, 100)
GUISetState(@SW_SHOW, $mainWindow)

GUIRegisterMsg($WM_NOTIFY, "WM_Notify_Events")

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            _Exit()
    EndSwitch
WEnd

Func Test()
    For $k = 1 To UBound($aFiles) - 1
        screenshotWidgetTransition($aFiles[$k])
    Next
EndFunc

Func ListView_Click()
    ConsoleWrite("Left Click")
EndFunc

Func ListView_DoubleClick()
    ConsoleWrite("Double Left Click")
    Test()
EndFunc

Func WM_Notify_Events($hWndGUI, $MsgID, $wParam, $lParam)
    #forceref $hWndGUI, $MsgID, $wParam
    Local $tagNMHDR, $event, $hwndFrom, $code
    $tagNMHDR = DllStructCreate("int;int;int", $lParam)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3)
    Select
    Case $wParam = $ListView
        Select
            Case $event = $NM_CLICK
                ListView_Click ()
            Case $event = $NM_DBLCLK
                ListView_DoubleClick ()
            EndSelect
    EndSelect
    Return $GUI_RUNDEFMSG
EndFunc

Func screenshotWidgetTransition($image, $delay = 0, $speed = 1, $sleep = 2000)
    Local $a, $d = $c, $iX, $iY
    $ssImage = _GDIPlus_ImageLoadFromFile($image)
    $iX = _GDIPlus_ImageGetWidth($ssImage)
    $iY = _GDIPlus_ImageGetHeight($ssImage)

    $FDesktop=$ssH/$ssW
    $Fact =1
    If $iX > $ssW And $FDesktop > ($iY/$iX) Then
        $Fact=$ssW/$iX
    ElseIf $iY > $ssH Then
        $Fact=$ssH/$iY
    EndIf
    $H1 = Round(($Fact * $iY),0)
    $W1 = Round(($Fact * $iX),0)

    _GDIPlus_GraphicsDrawImageRect($ssGraphic[$d], $ssImage,($ssW - $W1)/2, ($ssH - $H1) / 2,$W1,$H1)

    WinSetTrans($ssGDI[$d], "", 0)
    WinSetOnTop($ssGDI[$d], "", 1)
    For $a = 0 To 254 Step $speed
        WinSetTrans($ssGDI[$d], "", $a)
        Sleep($delay)
    Next
    WinSetTrans($ssGDI[$d], "", 254)
    WinSetOnTop($ssGDI[Not ($d)], "", 0)
    WinSetTrans($ssGDI[Not ($d)], "", 0)
    _GDIPlus_GraphicsClear($ssGraphic[Not ($d)])
    $c = 1 - $d

    _GDIPlus_ImageDispose ($ssImage) ; very important to realease the pics
    Sleep($sleep)
EndFunc   ;==>screenshotWidgetTransition

Func screenshotWidgetInit($ssW,$ssH,$ssX,$ssY)
    $ssGDI[2] = GUICreate("", $ssW, $ssH, $ssX, $ssY, $WS_POPUP, $WS_EX_MDICHILD, $mainWindow)
    $ssGDI[0] = GUICreate("", $ssW, $ssH, 3, 3, $WS_POPUP, $WS_EX_MDICHILD, $ssGDI[2])
    $ssGDI[1] = GUICreate("", $ssW, $ssH, 3, 3, $WS_POPUP, $WS_EX_MDICHILD, $ssGDI[2])
;    GUISetBkColor("0x" & $bg_color, $ssGDI[2])
    GUISetState(@SW_SHOW, $ssGDI[2])
    GUISetState(@SW_SHOW, $ssGDI[0])
    GUISetState(@SW_SHOW, $ssGDI[1])
    WinSetTrans($ssGDI[0], "", 0)
    WinSetTrans($ssGDI[1], "", 0)
    _GDIPlus_Startup()
    $ssGraphic[0] = _GDIPlus_GraphicsCreateFromHWND($ssGDI[0])
    $ssGraphic[1] = _GDIPlus_GraphicsCreateFromHWND($ssGDI[1])
    _GDIPlus_GraphicsClear($ssGraphic[0], "0xFF" & $bg_color)
    _GDIPlus_GraphicsClear($ssGraphic[1], "0xFF" & $bg_color)
EndFunc   ;==>screenshotWidgetInit

Func _Exit()
    _GDIPlus_ImageDispose($ssImage)
    _GDIPlus_GraphicsDispose($ssGraphic[0])
    _GDIPlus_GraphicsDispose($ssGraphic[1])
    GUIDelete($ssGDI[0])
    GUIDelete($ssGDI[1])
    GUIDelete($ssGDI[2])
    _GDIPlus_Shutdown()
    Exit
EndFunc   ;==>_Exit

I hope someone can shed light on this; perhaps a different approach is needed?

Thank you in advance!

P.S.
The script is patched from different scripts of different users in the forum - thank you again users! :)

Edited by 0Ethan0
Link to post
Share on other sites

You have some blocking function in it like sleep.
Also Guioneventmode give some problem in your case.

I fixed it, see the code.

#include <GuiListView.au3>
#include <File.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

HotKeySet("{Esc}", "_Exit")

Global $c=0
Global $ssGDI[3], $ssGraphic[2], $ssImage
Global Const $bg_color = "000000"
Global Const $ssW = 480, $ssH = 320
Global $aFiles = _FileListToArrayRec("d:\testStage\", "*.jpg;*.png;*.bmp;*.gif;*.JPG;*.PNG;*.BMP;*.GIF", $FLTAR_FILES, $FLTAR_NORECUR ,$FLTAR_SORT ,$FLTAR_FULLPATH )


$guiW = 1200
$guiH = 726
$mainWindow = GUICreate("Slideshow Viewer", $guiW, $guiH, -1, -1, $WS_POPUP)
$Button1 = GUICtrlCreateButton("Exit", 0, 0, 50, 50)
$Button2 = GUICtrlCreateButton("Test", 60, 0, 50, 50)


Global $ListView = GUICtrlCreateListView("Entry Name|Category", 5, 75, 195, 280)
_GUICtrlListView_SetColumnWidth ($ListView, 0, 100)
_GUICtrlListView_SetColumnWidth ($ListView, 1, 100)
GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES)
GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_FULLROWSELECT, $LVS_EX_FULLROWSELECT)
GUICtrlCreateListViewItem("Name 1|Category 1", $ListView)
GUICtrlCreateListViewItem("Name 2|Category 2", $ListView)

screenshotWidgetInit($ssW,$ssH, 690, 100)
GUISetState(@SW_SHOW, $mainWindow)

GUIRegisterMsg($WM_NOTIFY, "WM_Notify_Events")

While 1
   _Check_MSG()
WEnd

Func _Check_MSG()
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            _Exit()
        Case $Button1
            _Exit()
        Case $Button2
            Test()
    EndSwitch
EndFunc

Func Test()
    For $k = 1 To UBound($aFiles) - 1
        screenshotWidgetTransition($aFiles[$k])
    Next
EndFunc

Func ListView_Click()
    ConsoleWrite("Left Click")
EndFunc

Func ListView_DoubleClick()
    ConsoleWrite("Double Left Click")
    Test()
EndFunc

Func WM_Notify_Events($hWndGUI, $MsgID, $wParam, $lParam)
    #forceref $hWndGUI, $MsgID, $wParam
    Local $tagNMHDR, $event, $hwndFrom, $code
    $tagNMHDR = DllStructCreate("int;int;int", $lParam)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3)
    Select
    Case $wParam = $ListView
        Select
            Case $event = $NM_CLICK
                ListView_Click ()
            Case $event = $NM_DBLCLK
                ListView_DoubleClick ()
            EndSelect
    EndSelect
    Return $GUI_RUNDEFMSG
EndFunc

Func screenshotWidgetTransition($image, $delay = 0, $speed = 1, $sleep = 2000)
    Local $a, $d = $c, $iX, $iY
    $ssImage = _GDIPlus_ImageLoadFromFile($image)
    $iX = _GDIPlus_ImageGetWidth($ssImage)
    $iY = _GDIPlus_ImageGetHeight($ssImage)

    $FDesktop=$ssH/$ssW
    $Fact =1
    If $iX > $ssW And $FDesktop > ($iY/$iX) Then
        $Fact=$ssW/$iX
    ElseIf $iY > $ssH Then
        $Fact=$ssH/$iY
    EndIf
    $H1 = Round(($Fact * $iY),0)
    $W1 = Round(($Fact * $iX),0)

    _GDIPlus_GraphicsDrawImageRect($ssGraphic[$d], $ssImage,($ssW - $W1)/2, ($ssH - $H1) / 2,$W1,$H1)

    WinSetTrans($ssGDI[$d], "", 0)
    WinSetOnTop($ssGDI[$d], "", 1)
    For $a = 0 To 254 Step $speed
        WinSetTrans($ssGDI[$d], "", $a)
        _Check_MSG()
        Sleep($delay)
    Next
    WinSetTrans($ssGDI[$d], "", 254)
    WinSetOnTop($ssGDI[Not ($d)], "", 0)
    WinSetTrans($ssGDI[Not ($d)], "", 0)
    _GDIPlus_GraphicsClear($ssGraphic[Not ($d)])
    $c = 1 - $d

    _GDIPlus_ImageDispose ($ssImage) ; very important to realease the pics
    $timer = TimerInit()
    While TimerDiff($timer) < $sleep
        _Check_MSG()
    WEnd

EndFunc   ;==>screenshotWidgetTransition

Func screenshotWidgetInit($ssW,$ssH,$ssX,$ssY)
    $ssGDI[2] = GUICreate("", $ssW, $ssH, $ssX, $ssY, $WS_POPUP, $WS_EX_MDICHILD, $mainWindow)
    $ssGDI[0] = GUICreate("", $ssW, $ssH, 3, 3, $WS_POPUP, $WS_EX_MDICHILD, $ssGDI[2])
    $ssGDI[1] = GUICreate("", $ssW, $ssH, 3, 3, $WS_POPUP, $WS_EX_MDICHILD, $ssGDI[2])
;    GUISetBkColor("0x" & $bg_color, $ssGDI[2])
    GUISetState(@SW_SHOW, $ssGDI[2])
    GUISetState(@SW_SHOW, $ssGDI[0])
    GUISetState(@SW_SHOW, $ssGDI[1])
    WinSetTrans($ssGDI[0], "", 0)
    WinSetTrans($ssGDI[1], "", 0)
    _GDIPlus_Startup()
    $ssGraphic[0] = _GDIPlus_GraphicsCreateFromHWND($ssGDI[0])
    $ssGraphic[1] = _GDIPlus_GraphicsCreateFromHWND($ssGDI[1])
    _GDIPlus_GraphicsClear($ssGraphic[0], "0xFF" & $bg_color)
    _GDIPlus_GraphicsClear($ssGraphic[1], "0xFF" & $bg_color)
EndFunc   ;==>screenshotWidgetInit

Func _Exit()
    _GDIPlus_ImageDispose($ssImage)
    _GDIPlus_GraphicsDispose($ssGraphic[0])
    _GDIPlus_GraphicsDispose($ssGraphic[1])
    GUIDelete($ssGDI[0])
    GUIDelete($ssGDI[1])
    GUIDelete($ssGDI[2])
    _GDIPlus_Shutdown()
    Exit
EndFunc   ;==>_Exit

 

Edited by nend
Link to post
Share on other sites

nend, Thank you so much for the reply and the code - it gave me a clearer concept of how things work behind the Autoit scene : )

I also read in the Wiki about the exact problem I was facing --> https://www.autoitscript.com/wiki/Interrupting_a_running_function

I hope it's OK to share the link here, just for others who stumble upon this topic can have a better understanding.

 

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
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By It_is_me_Me
      I am making some GUI with combobox for the Baudrates communications and I listed 9600, 57600, 115200. 
      I wrote the code to be defaulted to 57600 like this:
      GUICtrlSetData($comboBox_opticalBaudRate, "9600|57600|115200", "57600")
      But I wanted the GUI to remember the last item the user picks so the baudrates will NOT be defaulted to 57600.
      Example, I pick 9600 as my baudrates, then I close the GUI, after opening it, it always prompt 57600 since that is what I did in my code. But I want that if I choose 9600 and close the GUI, opening it again will show 9600 now instead of 57600.
      Is there a way to do it in GUI setting?
       
      Thanks.
    • By ashraful089
      #include <ButtonConstants.au3>
      #include <ComboConstants.au3>
      #include <GUIConstantsEx.au3>
      #include <WindowsConstants.au3>
      #Region ### START Koda GUI section ### Form=C:\Users\Engr. Ashraful\Videos\koda_1.7.3.0\Forms\ProgramPlayer\FormProgamToOpen.kxf
      $FormInput = GUICreate("Input", 302, 205, 454, 285)
      $Resolution = GUICtrlCreateCombo("Resolution", 80, 24, 145, 25)
      GUICtrlSetData(-1, "1920|VM1920|1366")
      $ComboProgramType = GUICtrlCreateCombo("Program Type Selection", 80, 64, 145, 25, BitOR($CBS_DROPDOWN,$CBS_AUTOHSCROLL))
      GUICtrlSetData(-1, "Multimedia|Official|Design|Web")
      $ButtonEnter = GUICtrlCreateButton("Enter", 104, 104, 75, 25)
      GUISetState(@SW_SHOW)
      #EndRegion ### END Koda GUI section ###
      While 1
          $nMsg = GUIGetMsg()
          Switch $nMsg
              Case $GUI_EVENT_CLOSE
                  Exit
          EndSwitch
      WEnd
       
      please help me to read combo box input and use the value for another function/ work
       
    • By Aapjuh
      Hi,
      I am having a problem properly saving the Width of a resizable Gui.
      When a user resizes the Gui it gets saved in an ini when the Gui closes to then restore the new Width upon reopening the app.
      with GUICreate("myGui",300,200,Default,Default,$WS_SIZEBOX)
      WinGetPos($hGUI) returns 314, and WinGetClientSize($hGUI) returns 298
      when its then saved in the ini the gui keeps expanding or shrinking every time its opened by +14 or -2
      I figure it has to do with borders etc, but i also guess borders depend on the window theme and whatnot or is user specific, so i can't just do $GuiWidth = $GetGuiWidth[arr] -14 or +2 right?

      is there a proper way of doing this?
      Thanks in advance,
      Aapjuh
    • By ahha
      Under program control is there an easy way to move a slider (thumb) to the top or bottom?
      I am aware of Melba23's GUIScrollbars_Ex UDF (https://www.autoitscript.com/forum/topic/113723-scrollbars-made-easy-bugfix-version-2-may-21/) but I believe it's overkill for my simple needs.
      In a listview with a vertical scrollbar when the window is active one can hit Ctrl+Home to move the scrollbar slider (thumb) to the top and Ctrl+End to the bottom.
      One can also right click the slider and choose Scroll Here, Top, Bottom, Page UP, Page Down, Scroll Up, and Scroll Down.
      I must be doing something basically wrong but am stuck.  Move the thumb to the middle before clicking the Top button to test the code below (Bottom is not coded).  I've commented out other trys.  try #3 is a strange fail.
      Any comments on what I'm missing greatly appreciated as I'm stuck
      #AutoIt3Wrapper_run_debug_mode=Y #include <Debug.au3> #include <GUIConstantsEx.au3> #include <GuiListView.au3> #include <GuiScrollBars.au3> AutoItSetOption("MustDeclareVars", 1) ;v1b - cut out extraneous code Example() Exit Func Example() Local $i, $j, $x, $hGUI, $idListView, $bTop, $bBottom $hGUI = GUICreate("Scrollbar Question", 300, 400) ;get handle in case we need it later $idListView = GUICtrlCreateListView("Col 0", 10, 10, 280, 300) $bTop = GUICtrlCreateButton("Top", 10, 350, 60, 25) $bBottom = GUICtrlCreateButton("Bottom", 120, 350, 60, 25) ;Pause("$hGUI = '" & $hGUI &"'"& @CRLF & "$idListView = '" & $idListView &"'") For $i = 1 to 100 _GUICtrlListView_AddItem($idListView, $i) Next GUISetState(@SW_SHOW) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $bTop ;drag thumb to middle of scrollbar before clicking Top button ;try #1 - FAILS Opt("WinTitleMatchMode", 2) ;2 = Match any substring in the title $x = WinActivate("Scrollbar Question") ;not $idListview but main GUI $hGUI - neither working If $x <> $hGUI Then Pause("WinActivate FAILED") Send("^{HOME}") ;Ctrl+home ;try#2 - FAILS ;~ $x = WinActivate($hGUI) ;try Main GUI ;~ If $x <> $hGUI Then Pause("WinActivate FAILED") ;~ Send("^{HOME}") ;Ctrl+home ;try#3 - strange FAILS ;~ $x = WinActivate($idListview) ;try $idListview ;~ If $x <> $idListview Then Pause("WinActivate FAILED") ;strange it works BUT if I comment out this line it fails ;~ ;Sleep(1000) ;it's not a time delay issue ;~ Send("^{HOME}") ;Ctrl+home ;try#4 - same strange fail as #3 ;~ $x = WinActivate($idListview) ;try $idListview ;~ If $x <> $idListview Then Pause("WinActivate FAILED") ;~ Send("{UP 100}") ;try#5 - what the heck is going on? same strange fail as #3 ;$x = WinActivate($idListview) ;try $idListview ;~ $x = WinActivate($hGUI) ;try Main GUI ;~ If $x <> $idListview Then Pause("WinActivate FAILED") ;~ MouseWheel($MOUSE_WHEEL_UP, 100) ;_GUIScrollBars_ScrollWindow($hGUI, 0, 100) ;NO - moves the ListView window in the $hGUI ;_GUIScrollBars_ScrollWindow($idListview, 0, 100) ;does not seem to work ;_GUIScrollBars_SetScrollInfoPos($hGUI, $SB_VERT, 30) ;does not work ;_GUIScrollBars_SetScrollInfoPos($idListview, $SB_VERT, 30) ;does not work ;I'm doing something very basic wrong. I need help. Pause("Scrollbar thumb should be at Top") Case $bBottom Pause("In: Case $bBottom") Pause("Scroll bar should be at BOttom") EndSwitch WEnd GUIDelete($idListView) EndFunc ;Func Example() Func Pause($text="") MsgBox(262144, "DEBUG", "Paused: " & $text) EndFunc  
    • By ahha
      Newbie to _GUICtrlListView_RegisterSortCallBack and can't get it to sort properly on date in format MM/DD/YYYY.
      Example code below.  Q - How do I get the date to sort properly?
      ;#AutoIt3Wrapper_run_debug_mode=Y #include <GUIConstantsEx.au3> #include <GuiListView.au3> Global $g_id_ListView Example() Exit Func Example() Local $idRow1, $idRow2, $idRow3 GUICreate("ListView Sort Question", 300, 200) $g_id_ListView = GUICtrlCreateListView("Row#|Name|Date", 10, 10, 280, 180) $id_Row1 = GUICtrlCreateListViewItem("#1|Alice|01/15/2022", $g_id_ListView) $id_Row2 = GUICtrlCreateListViewItem("#2|Bob|02/22/2021", $g_id_ListView) $id_Row3 = GUICtrlCreateListViewItem("#3|Carol|03/13/2021", $g_id_ListView) $id_Row10 = GUICtrlCreateListViewItem("#10|Dave|10/09/2021", $g_id_ListView) $id_Row11 = GUICtrlCreateListViewItem("#11|Eve|11/21/2021", $g_id_ListView) GUISetState(@SW_SHOW) ;$vCompareType = 0 ;not ok as Row# sort #1, #10, and want #1, #2, ;$vCompareType = 1 ;not ok as Row# sort #1, #10, and want #1, #2, $vCompareType = 2 ;Row# okay but Date messed up _GUICtrlListView_RegisterSortCallBack($g_id_ListView, $vCompareType) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $g_id_ListView ;MsgBox(0,"","col="&GUICtrlGetState($g_id_ListView)) _GUICtrlListView_SortItems($g_id_ListView, GUICtrlGetState($g_id_ListView)) EndSwitch WEnd _GUICtrlListView_UnRegisterSortCallBack($g_id_ListView) GUIDelete($g_id_ListView) EndFunc ;Func Example()  
×
×
  • Create New...