When function is called, break the former "for loop" called by the same function and start the new one Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
JemyM
Posts: 44
Joined: 04 Jul 2017, 11:57

When function is called, break the former "for loop" called by the same function and start the new one

11 Oct 2018, 02:12

I have been banging my head on this for weeks now... There must be a simple solution but I can't find it.

I have a function called "filter". When I click an item in a treeview, a listview to its right displays up to 6290 entries limited by a search criteria.

The function first delete the old list, then make a "for loop" through my main index. If an item in the index match the search criteria its added to the listview.

What I cannot do is to break the former loop when a new "filter" is added. If the "All" option is used, meant to display every entry in the index, the script blatantly ignore all new calls of Filter until it finished building the list of all 6290 entries.

Any idea how I can make it stop the old for loop when I call a new one?

I added a smaller version of the function as it is to illustrate what it looks like. I tried to add a "LoopBreak" variable that was checked right prior to the "All" filter, meant to break the loop, but I couldn't get it to work.

Code: Select all

Filter(Filter,Category:="None") ; This is the main Filter script
{
global

LV_Delete()

for ID, info in Index
	If (Filter = "All") and ConfigurationIndex[ID].ConfTitle ; All
		LV_Add("", info.Game,ID,SubStr(info.Year, -3),info.Publisher,info.Developer,info.Genre,info.SourceCount)
	else if (Category = "Year") and ConfigurationIndex[ID].ConfTitle and (SubStr(info.Year, -3) = Filter) ; Year
		LV_Add("", info.Game,ID,SubStr(info.Year, -3),info.Publisher,info.Developer,info.Genre,info.SourceCount)
	else if (Category = "Year") and ConfigurationIndex[ID].ConfTitle and (Filter = "Earlier") and info.Year and (SubStr(info.Year, -3) < 1981) ; Year
		LV_Add("", info.Game,ID,SubStr(info.Year, -3),info.Publisher,info.Developer,info.Genre,info.SourceCount)
	else if (Category = "Year") and ConfigurationIndex[ID].ConfTitle and (Filter = "Later") and info.Year and (SubStr(info.Year, -3) > 2001) ; Year
		LV_Add("", info.Game,ID,SubStr(info.Year, -3),info.Publisher,info.Developer,info.Genre,info.SourceCount)
	else if (Category = "Genre") and ConfigurationIndex[ID].ConfTitle and inStr(info.Genre,Filter) ; Genre
		LV_Add("", info.Game,ID,SubStr(info.Year, -3),info.Publisher,info.Developer,info.Genre,info.SourceCount)
}
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: When function is called, break the former "for loop" called by the same function and start the new one

11 Oct 2018, 05:41

I just read yesterday that continue is equivalent to reaching loop's end bracket. So it is going to help if you position a continue after each condition's action.

Check docs for the word continue in Loops

Ex:

Code: Select all

 if () 
{
Do this...
Continue
}
Else if()
{
Do this...
Continue
}
Not 100% sure its best practice but heres my grain of salt :)
JemyM
Posts: 44
Joined: 04 Jul 2017, 11:57

Re: When function is called, break the former "for loop" called by the same function and start the new one

11 Oct 2018, 06:48

Not quite sure what continues would do here tbh. :) A continue just means that the rest of the loop is ignored. But that loop is currently just one very long "if" or "if else" statement, so it will reach the end of the loop right where you added those continues anyway.

The big thing is to stop the for loop if a new one have been called. So far all my attempts to stop it have been ignored.
Guest

Re: When function is called, break the former "for loop" called by the same function and start the new one

11 Oct 2018, 07:12

You need a different approach I think, when you call a function, it will execute completely before it returns to the point in your script where you called it - e.g. you can't call the function to run multiple times at the same time.
So in the for loop check for a variable which you can control outside of the function - here stop - start the script, press ^z to stop as an example

Code: Select all

array:=[]
Loop 1000
	Array.push(A_Index)
stop:=0

func()
return

func()
	{
	global
	for k, v in Array
		{
		 ToolTip %v%
		 Sleep 50
		 If stop
		 	Break
		}
	}
	
^z::
stop:=1
Return
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: When function is called, break the former "for loop" called by the same function and start the new one

11 Oct 2018, 07:14

^^ ok I understand. Atleast I suppose Continue would help if you have lots of conditions to validate on each loop. As soon as it finds one condition it would stop checking the rest of conditions uselessly? Am I right?

For the stoping I think you could try comparing at the top of the loop, if the search content is equal to previous search content? if it is not the same, then break out of loop and restart with new search content. But how to do it exactly I don't know enough and don't want to mislead you :P
JemyM
Posts: 44
Joined: 04 Jul 2017, 11:57

Re: When function is called, break the former "for loop" called by the same function and start the new one

11 Oct 2018, 15:21

Guest wrote:You need a different approach I think, when you call a function, it will execute completely before it returns to the point in your script where you called it - e.g. you can't call the function to run multiple times at the same time.
So in the for loop check for a variable which you can control outside of the function - here stop - start the script, press ^z to stop as an example

Code: Select all

array:=[]
Loop 1000
	Array.push(A_Index)
stop:=0

func()
return

func()
	{
	global
	for k, v in Array
		{
		 ToolTip %v%
		 Sleep 50
		 If stop
		 	Break
		}
	}
	
^z::
stop:=1
Return
I tried something similar to no success so far.

The only intuitive thing for the end user to stop the previous "loop" is clicking on a different part of the Treeview, which means calling the function. That means that the time the previous function needs to stop, is when a new one is called. But most of my attempts to add a "stop" variable somewhere in the code have failed. Even if a hotkey that way might work, its counter intuitive for the end user. The user interface is identical to how a normal explorer window works, the user click on folders, which change the directory in the right-hand part of the window. In my treeview its clicking one of the nodes that update a list on the right side.

We worked for quite some time to get anything to work, but so far we haven't been successful.
just me
Posts: 9449
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: When function is called, break the former "for loop" called by the same function and start the new one  Topic is solved

11 Oct 2018, 22:45

If you call the function directly from the TreeView's g-label, this label cannot be triggered again before the function returns. Something like the following might help:

Code: Select all

#NoEnv
BreakTheLoop := False
Gui, Add, TreeView, w200 r20 gTV_Label
Loop, 20
   TV_Add("Node " . A_index)
Gui, Add, ListView, x+10 yp wp hp, Column 1
Gui, Show, , Test
Return

GuiClose:
ExitApp

TV_Label:
   If (A_GuiEvent = "DoubleClick") {
      TheItem := A_EventInfo
      TheGUI := A_Gui
      BreakTheLoop := True
      SetTimer, CallTheFunction, -100 ; set a timer to call the function and return
   }
Return

CallTheFunction:
   TheFunction(TheItem)
Return

TheFunction(Item) {
   Global
   BreakTheLoop := False
   TV_GetText(TheText, Item)
   LV_Delete()
   Loop, 7000
      LV_Modify(LV_Add("", TheText . " # " . A_Index), "Vis")
   Until (BreakTheLoop)
   If !(BreakTheLoop)
      MsgBox, 0, %A_ThisFunc%, Done!
}
JemyM
Posts: 44
Joined: 04 Jul 2017, 11:57

Re: When function is called, break the former "for loop" called by the same function and start the new one

12 Oct 2018, 05:33

just me wrote:If you call the function directly from the TreeView's g-label, this label cannot be triggered again before the function returns. Something like the following might help:
We reached a conclusion about the same time you posted this, but your solution was much simpler and straight forward.

A big caveat we noted however was that for it to work I had to add this in the Timer;
Gui, Main:Default

... else the timer would cause the script to "forget" what to do with LV_Add in my script.

Since I am also dependent on for loops (due to associative arrays) I improved it one step further.

Code: Select all

for ID, info in Index
        If BreakFilter
            Return
        else if (Filter = "All")
...

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 337 guests