Lazegalli Posted July 28, 2010 Share Posted July 28, 2010 Hello Autoit Geeks, I need a possibility to cancel an active filecopy prosess with a button in the GUI! Details: I coded a GUI were the User can select some Softwarepackages! These packages will be downloaded to the local drive. Due to the fact, that the packages are really big, I want to give the User a Button, with which he can cancel/stop the download. Everything I've tried went wrong. My problem is, that the GUI doesn't accept any input during an active filecopy action. This means, even if I click the "X" to close the whole application, the program will run until the function ProgressCopy is finished and then it will be closed. Here the code of my ProgressCopy Function (with progressbars): expandcollapse popupFunc ProgressCopy($current, $destination, $attrib = "-R", $overwrite = 1 ,$Run1 = 0 ) ;FirstTimeRun Get original DirSize and set up Gui If $Run1 = 0 Then Global $OverallQty, $Overall, $source, $overallpercent, $Progress0Text, $progressbar1, $Progress1Text, $progressbar2, $Progress2Text, $LocalPercent If not FileExists ($destination) then DirCreate ($destination) $source = $current If StringRight($current, 1) = '\' Then $current = StringTrimRight($current, 1) If StringRight($destination, 1) <> '\' Then $destination = $destination & "\" $tosearch = $current $Overall = DirGetSize($tosearch, 1) $OverallQty = $Overall[1] $Progress0Text = GUICtrlCreateLabel("Please Wait", 16, 190, 441, 20) $progressbar1 = GUICtrlCreateProgress(16, 205, 441, 20) GUICtrlSetColor(-1, 32250) $Progress1Text = GUICtrlCreateLabel("", 16, 227, 441, 20) $progressbar2 = GUICtrlCreateProgress(16, 242, 441, 20) $Progress2Text = GUICtrlCreateLabel("", 16, 262, 441, 20) GUICtrlSetData($Progress1Text, "Working Directory " & $tosearch) $Run1 = 1 EndIf $Size = DirGetSize($current, 3) $Qty = $Size[1] Local $search = FileFindFirstFile($current & "\*.*") While 1 Dim $file = FileFindNextFile($search) ; end loop if all files are done or if an error happens If @error Or StringLen($file) < 1 Then ExitLoop ; Check that the next file to copy is no directory If Not StringInStr(FileGetAttrib($current & "\" & $file), "D") And ($file <> "." Or $file <> "..") Then ; Set values for GUI Labels $Qty -= 1 $LocalPercent = 100 - (($Qty / $Size[1]) * 100) $OverallQty -= 1 $overallpercent = 100 - (($OverallQty / $Overall[1]) * 100) ; set GUI Label content GUICtrlSetData($Progress0Text, "Download " & Int($overallpercent) & "% completed") GUICtrlSetData($progressbar1, $overallpercent) GUICtrlSetData($progressbar2, $LocalPercent) GUICtrlSetData($Progress2Text, "Copying File " & $file) ; Copy only if the source files modified date is different from the destination file (if already exists) $SourceFile = $current & "\" & $file $DestinationFile = $destination & StringTrimLeft($current, StringLen($source)) & "\" & $file If FileGetTime($SourceFile,0,1) <> FileGetTime($DestinationFile,0,1) Then FileCopy($current & "\" & $file, $destination & StringTrimLeft($current, StringLen($source)) & "\" & $file,$overwrite) FileSetAttrib($destination & StringTrimLeft($current, StringLen($source)) & "\" & $file, $attrib) EndIf EndIf ; If next file is a directory, create it and call the copy function again for this directory If StringInStr(FileGetAttrib($current & "\" & $file), "D") And ($file <> "." Or $file <> "..") Then DirCreate($destination & StringTrimLeft($current, StringLen($source)) & "\" & $file) FileSetAttrib($destination & StringTrimLeft($current, StringLen($source)) & "\" & $file, $attrib) GUICtrlSetData($Progress1Text, $current & "\" & $file) ProgressCopy($current & "\" & $file, $destination, $attrib, $overwrite,1) EndIf WEnd FileClose($search) ; when overall percent = 100, set end gui text, delete progressbars and reset run1 to 0 If $overallpercent = 100 Then GUICtrlSetData($Progress0Text, "Package download 100% completed") GUICtrlSetData($progressbar1, 100) GUICtrlSetData($progressbar2, 100) GUICtrlSetData($Progress2Text, "Done!") Sleep(2000) GUICtrlDelete($Progress0Text) GUICtrlDelete($progressbar1) GUICtrlDelete($Progress1Text) GUICtrlDelete($progressbar2) GUICtrlDelete($Progress2Text) $Run1 = 0 EndIf EndFunc Any help would be appreciated! By the way: The function "ProgressCopy" is not made by myself. I found it somewhere and adapted it to my needs! Link to comment Share on other sites More sharing options...
PsaltyDS Posted July 28, 2010 Share Posted July 28, 2010 (edited) While the script is stuck inside the While/WEnd loop of your ProgressCopy(), no GuiGetMsg() is being done to handle inputs. Instead, use GuiOnEventMode for your GUI. Any events from clicking "X" or a CANCEL button will interrupt the function. Edited July 28, 2010 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 Link to comment Share on other sites More sharing options...
Phil Viton Posted July 28, 2010 Share Posted July 28, 2010 While the script is stuck inside the While/WEnd loop of your ProgressCopy(), no GuiGetMsg() is being done to handle inputs. Instead, use GuiOnEventMode for your GUI. Any events from clicking "X" or a CANCEL button will interrupt the function. I was also having a problem like this, and I was wondering: rather than re-code the logic of the app into OnEventMode, why couldn't you put the FileCopy stuff inside a function, and then within the function, call and check the state of GuiGetMsg? Or even (within the main loop) introduce a sub-loop while 1 $msg = GuiGetMsg() [check the state of $msg and quit if a button was pressed] [do the file copy] wend I've tried something like this, but it still doesn't seem to work. Can anyone explain why? Link to comment Share on other sites More sharing options...
Lazegalli Posted July 28, 2010 Author Share Posted July 28, 2010 (edited) I was also having a problem like this, and I was wondering: rather than re-code the logic of the app into OnEventMode, why couldn't you put the FileCopy stuff inside a function, and then within the function, call and check the state of GuiGetMsg? Or even (within the main loop) introduce a sub-loop while 1 $msg = GuiGetMsg() [check the state of $msg and quit if a button was pressed] [do the file copy] wend I've tried something like this, but it still doesn't seem to work. Can anyone explain why? I've done exactely the same, because I was to lazy to recode everything with OnEventMode! ;-) ...but I came to the result as you...it won't work and now I understand why! PsaltyDS is right. GuiGetMsg() seems to be stopped completely during while statements. Nevertheless it stores the last GuiGetMsg() in the variable and execute the corresponding action after all while statements are done. I proofed this with some tests I've made in the afternoon. This means, there's no other chance then recoding, because with OnEventMode everything works perfect (also proven during the test)! Thanks PsaltyDS Edited July 28, 2010 by Lazegalli Link to comment Share on other sites More sharing options...
Phil Viton Posted July 28, 2010 Share Posted July 28, 2010 I think I must be doing something wrong, because it doesn't seem to me that switching to OnEvent mode solves (my) problem. Here's a very simple app in this mode: The idea is that once the user clicks Start, we just increment an integer and display it. What I want to do is have the app react to either the Quit button or to the "X" on the app's title bar. As written, it doesn't seem to do this - so what am I doing wrong? (The app will exit when the counter exceeds 5, but that's just because I can't get it to react). expandcollapse popup#include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include<ButtonConstants.au3> Opt("GUIOnEventMode",1) $init = 0 $button_wid = 50 $main=GUICreate("Test", 420, 220, -1, -1) $st = GuiCtrlCreateButton("Start",150,180,$button_wid,-1) GUICtrlSetOnEvent($st,"StartFn") $st = GuiCtrlCreateButton("Quit",250,180,$button_wid,-1) GUICtrlSetOnEvent($st,"QuitFn") $labf=GUICtrlCreateLabel("Checking Library: ", 30, 70, 90) $libname = GUICtrlCreateLabel(" ", 120, 70, 50) GUISetOnEvent($GUI_EVENT_CLOSE,"QuitFn") GUISetState(@SW_SHOW) while 1 sleep(1000) wend Func QuitFn() exit EndFunc Func StartFn() GUICtrlSetState($libname,$GUI_SHOW) while 1 $init = $init +1 if $init > 5 then exit GUICtrlSetData($libname,$init) sleep(2500) wend EndFunc Link to comment Share on other sites More sharing options...
PsaltyDS Posted July 28, 2010 Share Posted July 28, 2010 You never want to stay inside the event handler function that long. While one event is being handled, others are blocked. So when an event occurs handle it short and fast. Here, the start function just sets some global variables and returns to the main loop: expandcollapse popup#include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include<ButtonConstants.au3> Opt("GUIOnEventMode", 1) Global $f_Run = False, $iTimer Global $init = 0, $button_wid = 50, $libname GUICreate("Test", 420, 220, -1, -1) GUISetOnEvent($GUI_EVENT_CLOSE, "QuitFn") GUICtrlCreateButton("Start", 150, 180, $button_wid, -1) GUICtrlSetOnEvent(-1, "StartFn") GUICtrlCreateButton("Quit", 250, 180, $button_wid, -1) GUICtrlSetOnEvent(-1, "QuitFn") GUICtrlCreateLabel("Checking Library: ", 30, 70, 90, 20) $libname = GUICtrlCreateLabel(" ", 120, 70, 50, 20) GUISetState(@SW_SHOW) While 1 Sleep(10) If $f_Run Then If TimerDiff($iTimer) >= 2500 Then $iTimer = TimerInit() $init = $init + 1 GUICtrlSetData($libname, $init) If $init > 5 Then $f_Run = False EndIf EndIf WEnd Func QuitFn() Exit EndFunc ;==>QuitFn Func StartFn() $f_Run = True $init = 0 GUICtrlSetData($libname, $init) $iTimer = TimerInit() EndFunc ;==>StartFn 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 Link to comment Share on other sites More sharing options...
Phil Viton Posted July 29, 2010 Share Posted July 29, 2010 Thank you very much! This is a big help to me. (I experimented with calling the windows WaitMessage from user32.dll, which, as I understand it, is supposed to allow an app to process its message queue, and which should in principle allow the main window to become responsive again. I've been successful with this in other languages, but either I was using it incorrectly or else it has no effect in an AutoIt script). Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now