Looping with a collection of variables

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Ryder
Posts: 61
Joined: 28 Apr 2022, 18:49

Looping with a collection of variables

Post by Ryder » 07 Oct 2022, 12:07

Hi all,

I want to use a looping structure with a collection of variables... my fantasy is like this psudo-code:

Code: Select all

Loop CheckMe, %AppTitle%, %ConfigTitle%, %FormatTitle%, %DBViewTitle% {
    if(WinExist(CheckMe)){
	Winclose, %CheckMe%
   }
}
Is there something like this?

Thanks for your kind help,

R

garry
Posts: 3771
Joined: 22 Dec 2013, 12:50

Re: Looping with a collection of variables

Post by garry » 07 Oct 2022, 12:11

example close process when guiclose

Code: Select all

;---
Guiclose:
esc::
ProcessNames := "ping.exe|cmd.exe"
Loop, Parse, ProcessNames, |
{
   Process, Exist, %A_LoopField%
   if (ErrorLevel <> 0)
      Process, Close, %ErrorLevel%
}
exitapp
OR

Code: Select all

settitlematchmode,2
DetectHiddenWindows, On
~$F6::
progr := ["URLCOPY","fkee3"]
Loop % progr.Length()
    {
	aa:=progr[A_Index]
	msgbox, 262180,TEST ,Want you really close ?`n%aa% 
    ifmsgbox,NO
       continue
    WinClose,%aa%
	}
return	
an example from @Rohwedder
viewtopic.php?f=76&t=94966

Code: Select all

;- https://www.autohotkey.com/boards/viewtopic.php?f=76&t=94966

q::
DetectHiddenWindows, On
WinGet, AHKList, List, ahk_exe Autohotkey.exe
Loop, %AHKList%
	IF (A_ScriptHwnd <> ID := AHKList%A_Index%)
		WinClose, ahk_id %ID%
ExitApp
and also from user @vsub
viewtopic.php?p=337200#p337200

Ryder
Posts: 61
Joined: 28 Apr 2022, 18:49

Re: Looping with a collection of variables

Post by Ryder » 07 Oct 2022, 15:43

garry wrote:
07 Oct 2022, 12:11
example close process when guiclose

and also from user @vsub
viewtopic.php?p=337200#p337200
Thanks, Garry... but I don't think any of that will work because they aren't working with a collection of variables...

That's the rub.

R

User avatar
flyingDman
Posts: 2817
Joined: 29 Sep 2013, 19:01

Re: Looping with a collection of variables

Post by flyingDman » 07 Oct 2022, 15:56

What is a collection of variables? An array? Show us what it is.
14.3 & 1.3.7

Ryder
Posts: 61
Joined: 28 Apr 2022, 18:49

Re: Looping with a collection of variables

Post by Ryder » 07 Oct 2022, 16:58

flyingDman wrote:
07 Oct 2022, 15:56
What is a collection of variables? An array? Show us what it is.
It's on the first line of the OP psudo-code: %AppTitle%, %ConfigTitle%, %FormatTitle%, %DBViewTitle%

ShatterCoder
Posts: 78
Joined: 06 Oct 2016, 15:57

Re: Looping with a collection of variables

Post by ShatterCoder » 07 Oct 2022, 17:19

I think what you are looking for is a for loop, coupled with an array:

Code: Select all

AppTitle := "MyApp"
ConfigTitle := "Xyz"
FormatTitle := "something"
DBViewTitle := "Something Else"

MyArray := [AppTitle, ConfigTitle, FormatTitle, DBViewTitle]

for key_index_var, value_var in MyArray
{
   msgbox, % "item number " key_index_var " contains: "  value_var
}

ShatterCoder
Posts: 78
Joined: 06 Oct 2016, 15:57

Re: Looping with a collection of variables

Post by ShatterCoder » 07 Oct 2022, 17:31

or if you prefer a dictionary style approach to the array:

Code: Select all

MyArray := {"AppTitle" : "MyApp", "ConfigTitle" : "Xyz", "FormatTitle" : "something", "DBViewTitle" : "Something Else"} ;setting it directly
;or
AppTitle := "MyApp"
ConfigTitle := "Xyz"
FormatTitle := "something"

MyArray := {}
MyArray["AppTitle"] := AppTitle
MyArray["ConfigTitle"] := ConfigTitle
MyArray["FormatTitle"] := FormatTitle
MyArray["DBViewTitle"] := "Something Else"

for key_var, value_var in MyArray
{
   msgbox, % "the value of " key_var " is: " value_var
}

lexikos
Posts: 9593
Joined: 30 Sep 2013, 04:07
Contact:

Re: Looping with a collection of variables

Post by lexikos » 07 Oct 2022, 20:50

Code: Select all

MyArray := [AppTitle, ConfigTitle, FormatTitle, DBViewTitle]

for key_index_var, value_var in MyArray
can be shortened to

Code: Select all

for key_index_var, value_var in [AppTitle, ConfigTitle, FormatTitle, DBViewTitle]

For the specific task in the example, if the variables do not change, the most (CPU) efficient method is to use a window group:

Code: Select all

; Define the group only once (i.e. in the auto-execute section).
; I call it "AppWindows", but you can call it whatever you want.
GroupAdd AppWindows, % AppTitle
GroupAdd AppWindows, % ConfigTitle
GroupAdd AppWindows, % FormatTitle
GroupAdd AppWindows, % DBViewTitle

Code: Select all

; Whenever you want to close them...
WinClose ahk_group AppWindows

garry
Posts: 3771
Joined: 22 Dec 2013, 12:50

Re: Looping with a collection of variables

Post by garry » 08 Oct 2022, 04:16

thank you all for the examples , array, groupadd ...

Ryder
Posts: 61
Joined: 28 Apr 2022, 18:49

Re: Looping with a collection of variables

Post by Ryder » 11 Oct 2022, 10:11

ShatterCoder wrote:
07 Oct 2022, 17:19
I think what you are looking for is a for loop, coupled with an array:

Code: Select all

AppTitle := "MyApp"
ConfigTitle := "Xyz"
FormatTitle := "something"
DBViewTitle := "Something Else"

MyArray := [AppTitle, ConfigTitle, FormatTitle, DBViewTitle]

for key_index_var, value_var in MyArray
{
   msgbox, % "item number " key_index_var " contains: "  value_var
}
I think what you have here is a loop through *values* in an array... not *variables*.

Can you put variables in an array?

Ryder
Posts: 61
Joined: 28 Apr 2022, 18:49

Re: Looping with a collection of variables

Post by Ryder » 11 Oct 2022, 10:16

ShatterCoder wrote:
07 Oct 2022, 17:31
or if you prefer a dictionary style approach to the array:

Code: Select all

MyArray := {"AppTitle" : "MyApp", "ConfigTitle" : "Xyz", "FormatTitle" : "something", "DBViewTitle" : "Something Else"} ;setting it directly
;or
AppTitle := "MyApp"
ConfigTitle := "Xyz"
FormatTitle := "something"

MyArray := {}
MyArray["AppTitle"] := AppTitle
MyArray["ConfigTitle"] := ConfigTitle
MyArray["FormatTitle"] := FormatTitle
MyArray["DBViewTitle"] := "Something Else"

for key_var, value_var in MyArray
{
   msgbox, % "the value of " key_var " is: " value_var
}
I don't think this is it either... but it's not clear as I don't understand it entirely.

I believe you are still putting values into an array, not variable names.

The distinction is: Looping through an collection of VALUES (which you're storing in an array), vs looping through a collection of VARIABLES (which I'm not sure how to collect them).

To better understand, say we had code thus:

Code: Select all

   if(WinExist(AppTitle)){ 			;check if appearance window is opened, then close it
	Winclose, %AppTitle%				
   }

   if(WinExist(ConfigTitle)){ 			;check if configuration window is opened, then close it
	Winclose, %ConfigTitle%
   }

   if(WinExist(FormatTitle)){ 			;check if Format Browser window is opened, then close it
	Winclose, %FormatTitle%
   }

   if(WinExist(DBViewTitle)){ 			;check if database view window is opened, then close it
	Winclose, %DBViewTitle%
   }  

   if(WinExist(LogOnTitle)){ 			;check if Format Browser window is opened, then close it
	Winclose, %LogOnTitle%
   }

   if(WinExist(EraseTitle)){ 			;check if File Erase window is opened, then close it
	Winclose, %EraseTitle%
   }

   if(WinExist(NewTitle)){ 			;check if File Erase window is opened, then close it
	Winclose, %NewTitle%
   }

   if(WinExist(OpenFile)){ 			;check if File Erase window is opened, then close it
	Winclose, %OpenFile%
   }
Another requirement is that you can not alter the form of the variable.
How would you shorten this in a loop form so that WinExist and WinClose appear only once?

Hope this example helps...

R

ShatterCoder
Posts: 78
Joined: 06 Oct 2016, 15:57

Re: Looping with a collection of variables

Post by ShatterCoder » 11 Oct 2022, 12:16

Really an array is just a collection of values. Those values can be the same as the values of your variables. If what you care about are the names of the variables, then you can store the names in the array instead of the values, or you can use a dict array like my second example and store both. Play with the examples we have given you, try to run them so you can understand what they are doing. In the Dictionary example the for loop gives you key_var which is the name of the variable, and value_var which contains the value of the variable.

Aside from that, I think the most efficient way to do what you ask (unsurprisingly) is to follow lexicos's advice. Use groupadd and then all you need to do is run winclose one time, no if needed, and no loop required either.

Ryder
Posts: 61
Joined: 28 Apr 2022, 18:49

Re: Looping with a collection of variables

Post by Ryder » 11 Oct 2022, 12:29

ShatterCoder wrote:
11 Oct 2022, 12:16
Really an array is just a collection of values. Those values can be the same as the values of your variables. If what you care about are the names of the variables, then you can store the names in the array instead of the values, or you can use a dict array like my second example and store both. Play with the examples we have given you, try to run them so you can understand what they are doing. In the Dictionary example the for loop gives you key_var which is the name of the variable, and value_var which contains the value of the variable.

Aside from that, I think the most efficient way to do what you ask (unsurprisingly) is to follow lexicos's advice. Use groupadd and then all you need to do is run winclose one time, no if needed, and no loop required either.
Thanks for your comments, but I still don't see a solution.

"Really an array is just a collection of values." - Right, which is why it doesn't work. Looking for a collection of variables.


In my last note, I supply code with many repeated commands applied one at a time to variables (as well as the restrictions). Creating a dictionary array defeats the purpose of both simplifying and shortening the code.

What would you do to take that code example (supplied again here) to shorten it into a loop? (imagine it is a couple hundred variables long)

Code: Select all

   if(WinExist(AppTitle)){ 			;check if appearance window is opened, then close it
	Winclose, %AppTitle%				
   }

   if(WinExist(ConfigTitle)){ 			;check if configuration window is opened, then close it
	Winclose, %ConfigTitle%
   }

   if(WinExist(FormatTitle)){ 			;check if Format Browser window is opened, then close it
	Winclose, %FormatTitle%
   }

   if(WinExist(DBViewTitle)){ 			;check if database view window is opened, then close it
	Winclose, %DBViewTitle%
   }  

   if(WinExist(LogOnTitle)){ 			;check if Format Browser window is opened, then close it
	Winclose, %LogOnTitle%
   }

   if(WinExist(EraseTitle)){ 			;check if File Erase window is opened, then close it
	Winclose, %EraseTitle%
   }

   if(WinExist(NewTitle)){ 			;check if File Erase window is opened, then close it
	Winclose, %NewTitle%
   }

   if(WinExist(OpenFile)){ 			;check if File Erase window is opened, then close it
	Winclose, %OpenFile%
   }

Ryder
Posts: 61
Joined: 28 Apr 2022, 18:49

Re: Looping with a collection of variables

Post by Ryder » 11 Oct 2022, 12:50

lexikos wrote:
07 Oct 2022, 20:50
For the specific task in the example, if the variables do not change, the most (CPU) efficient method is to use a window group:

Code: Select all

; Define the group only once (i.e. in the auto-execute section).
; I call it "AppWindows", but you can call it whatever you want.
GroupAdd AppWindows, % AppTitle
GroupAdd AppWindows, % ConfigTitle
GroupAdd AppWindows, % FormatTitle
GroupAdd AppWindows, % DBViewTitle

Code: Select all

; Whenever you want to close them...
WinClose ahk_group AppWindows
That's fascinating... though I see why it's limited to the specific task in the example... if it didn't happen to be window IDs it wouldn't fly. But it's a very interesting case.

Imagine if "Groups" were exactly like this... but wide open (not specifically Window parameters)... that's probably what I'm looking for.


[Mod edit: Removed the extraneous code tag that messed up the quote box.]

lexikos
Posts: 9593
Joined: 30 Sep 2013, 04:07
Contact:

Re: Looping with a collection of variables

Post by lexikos » 11 Oct 2022, 22:45

Ryder wrote:
11 Oct 2022, 12:29
"Really an array is just a collection of values." - Right, which is why it doesn't work. Looking for a collection of variables.
Please explain what need you have for the variable itself rather than the variable's value. For your example, putting aside window groups, I see no reason that the for loop method would be any less than ideal. (Specifically the one I referenced in my previous post.)

If you want to make a list of variables and act on it later, when the values may have changed (or if you want to assign values), you can store the variable names as was previously suggested, and use dynamic references (aka double deref, with percent signs).
Ryder wrote: Imagine if "Groups" were exactly like this... but wide open (not specifically Window parameters)... that's probably what I'm looking for.
That doesn't make sense. A window group is just an array of window criteria (mostly textual values), registered with a global name. WinClose and some others are specifically designed to handle groups by iterating over all matching windows. Most commands just find a single match (by iterating over the criteria in the group).

You can just make an array, and design your function to iterate over it. It is no different.

ShatterCoder
Posts: 78
Joined: 06 Oct 2016, 15:57

Re: Looping with a collection of variables

Post by ShatterCoder » 12 Oct 2022, 17:51

Ryder wrote:
11 Oct 2022, 12:29

Thanks for your comments, but I still don't see a solution.

"Really an array is just a collection of values." - Right, which is why it doesn't work. Looking for a collection of variables.


In my last note, I supply code with many repeated commands applied one at a time to variables (as well as the restrictions). Creating a dictionary array defeats the purpose of both simplifying and shortening the code.

What would you do to take that code example (supplied again here) to shorten it into a loop? (imagine it is a couple hundred variables long)
as I have no idea how you are setting the variables to begin with I can only say that rather than setting the value of the variables, you would instead write those values into an array:

Code: Select all

;instead of
AppTitle := "Some string or function output"
ConfigTitle := "Another String or Function output"
;do this
appwindows := {} ;declare the array one time
appwindows["AppTitle"] := "Some string or function output"
appwindows{"ConfigTitle"] :=  "Another String or Function output"

;then eventually loop through them all
for key, value in appwindows
{
   if(WinExist(v)
      Winclose, %v%
   ;if you care about the name of the variable you can still get it by using key as in: msgbox, % key
}
I dont see why you need the varible names in the case you outlined, really you just need the values/contents of those variables in order to loop through them and close the windows whose titles match the values of the variables. for that reason you can simplify the above to:

Code: Select all

appwindows := [] ;declare the array one time, note square braces are used to indicate simple numerically indexed arrays
appwindows.Push("Some string or function output") ;this method automatically adds the item into the array at the next numeric index
appwindows[2] :=  "Another String or Function output" ;this method of assignment allows you to put the value into a specific index
;Note that you can also use a variable like A_index to assign values as in appwindows[A_index] :=  "Another String or Function output"

for k, v in appwindows
{
    if(WinExist(v)
      Winclose, %v%
}

Ryder
Posts: 61
Joined: 28 Apr 2022, 18:49

Re: Looping with a collection of variables

Post by Ryder » 13 Oct 2022, 16:26

ShatterCoder wrote:
12 Oct 2022, 17:51

as I have no idea how you are setting the variables to begin with I can only say that rather than setting the value of the variables, you would instead write those values into an array:
I can't do that because it changes hundreds of lines of code where the variable names are already used, and then due to readability... the variable names are descriptive (making the code readable), vs an array which obscures the meaning of the elements (and makes the structure more fragile). Finally it's to maintain treating variables in the same basic way as many other highly similar variables in use. Breaking some out to then be hidden in an array makes the code a bit schizophrenic.

My task is to produce code that can be used and even modified by people that don't code. Variable names that are highly descriptive accomplishes this.

%ShieldForRenoSledTitle% = "Shield for Reno Sled.docx - Word"

Is a lot more meaningful/readable than:

SomeWindows[3] = "Shield for Reno Sled.docx - Word". The named key comes very close to working in this situation though... it is certainly more readable. I will consider it!

But generally, the rule is that the variable form may not be changed.


Thanks for your kind replies!

R

Post Reply

Return to “Ask for Help (v1)”