Using an Array in ControlGetText? (Plus a Bunch of Object Q&A!) Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Using an Array in ControlGetText? (Plus a Bunch of Object Q&A!)

13 Mar 2017, 15:24

The setup: I have an array of objects. Each object contains several variables. The setup is basically this:

Code: Select all

global Varlist := {myVar1 : "test", myVar2 : "default", myVar3 : "empty"}
Loop, 16
	MyArray[A_Index] := new Varlist
Now I'm trying to store the results of a ControlGetText into a specific variable in one of the objects in the array, but I can't figure out the syntax. I've tried
ControlGetText, MyArray[A_Index].myVar1,, ahk_id winHwnd
but it says the variable name contains an illegal character.

For now I'm solving the problem with this:

Code: Select all

ControlGetText, HoldingVar,, ahk_id winHwnd
MyArray[A_Index].myVar1 := HoldingVar
But I would like to not need to do that. :)
Last edited by MaxAstro on 23 Mar 2017, 17:06, edited 1 time in total.
BoBo
Posts: 6564
Joined: 13 May 2014, 17:15

Re: Using an Array in ControlGetText?

13 Mar 2017, 18:40

Code: Select all

ControlGetText, % MyArray[A_Index] ".myVar1",, ahk_id winHwnd
Expressions > Force an Expression

:?:
lexikos
Posts: 9554
Joined: 30 Sep 2013, 04:07
Contact:

Re: Using an Array in ControlGetText?

13 Mar 2017, 20:27

Each object contains several values, or array elements, not variables. (Actually, each object in your array only contains a reference to its base object, and nothing else.)

You cannot use an expression in an OutputVar parameter.
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: Using an Array in ControlGetText?

13 Mar 2017, 22:12

AHK v2 code:
(commands can use function syntax)

Code: Select all

MyArray[A_Index].myVar1 := ControlGetText("", "ahk_id %winHwnd%")

MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: Using an Array in ControlGetText?

14 Mar 2017, 09:35

Seems like I have a number of problems. xD Yeah, I think I figured out the "only contains a reference" thing when some other things I was trying to do didn't work. I ended up switching to a pseudoarray (MyArray%A_Index%.myVar1) to make things work. And went with the HoldingVar solution.

Sounds like v2 might make things easier on me; I've been debating if I should switch over or not, but it seems like most of the documentation doesn't cover v2?
Guest

Re: Using an Array in ControlGetText?

14 Mar 2017, 17:15

You can write your own ControlGetText function in AHK v1 too and do the same as in v2 (slightly different syntax). Here is a recent attempt (although I'd ditch the CF_ part of it) https://autohotkey.com/boards/viewtopic.php?f=6&t=26900
lexikos
Posts: 9554
Joined: 30 Sep 2013, 04:07
Contact:

Re: Using an Array in ControlGetText?

14 Mar 2017, 18:49

MaxAstro wrote:... it seems like most of the documentation doesn't cover v2?
The v2 documentation covers v2. https://autohotkey.com/v2/
Guest wrote:Here is a recent attempt
I don't know how far along it is, but there's also https://github.com/cocobelgica/AutoHotkey-Future
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: Using an Array in ControlGetText?

15 Mar 2017, 10:42

Thanks, I didn't know there was specific documentation for v2. Makes perfect sense, I just never found it. I'll definitely take a look at seeing if I should port over.

Is there a way to make an array of objects? Here is what the purpose of my script is: Each object holds information defining a certain product - so bar code, price, description, etc - that my script grabs from another program. The script then takes that information and uses it to fill out a form-fillable PDF. Each PDF holds 12-16 products, and what products go into it in what order is up to the user.

So basically there needs to be 16 objects, and the script needs to be able to save product information to the correct object without knowing anything but the object's number. The objects also need to be accessible to every function in my script, as lots of different functions interact with them in different ways.
lexikos
Posts: 9554
Joined: 30 Sep 2013, 04:07
Contact:

Re: Using an Array in ControlGetText?

15 Mar 2017, 16:16

Is there a way to make an array of objects?
Of course there is. Create it the same way you'd create an array of numbers, or an array of strings. Just create an array and put objects into it.
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: Using an Array in ControlGetText?

15 Mar 2017, 16:30

I guess I'm confused as to why what I was trying to do wouldn't work, then? Other than ControlGetText not accepting an expression, of course... You said that the way I did it, each element in the array only contained a reference to the base object, not actually an object.
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: Using an Array in ControlGetText?

15 Mar 2017, 17:46

He was just being pedantic and correcting your misuse of the term 'variable' in your OP when you should have used the word 'key'. Objects have key-value pairs

4GForce
Posts: 553
Joined: 25 Jan 2017, 03:18
Contact:

Re: Using an Array in ControlGetText?

15 Mar 2017, 17:55

Aren't numbers and strings objects in some way ?
Anyway, no cigar for ControlGetText ...
You should consider a class for your Products
Something like this ... (UNTESTED)

Code: Select all

loop 16 
{
	ControlGetText, barCode,, ahk_id winHwnd
	ControlGetText, price,, ahk_id winHwnd
	ControlGetText, description,, ahk_id winHwnd
	new Product(barCode, price, description)
}

for key, prod in Product.AllProducts {
	msgbox % "Product " . key . " has barCode " . prod.BarCode
}
class Product {
	static AllProducts := []
	__new(barCode, price, description) {
		this.BarCode := barCode
		this.Price := price
		this.Description := description
		Product.AllProducts.Push(this)
	}
}
Edit: Maybe using barCode has a key might be better ... depending on how you intent to use it.
lexikos
Posts: 9554
Joined: 30 Sep 2013, 04:07
Contact:

Re: Using an Array in ControlGetText?

15 Mar 2017, 20:48

Let me rephrase;
MaxAstro wrote:Is there a way to make an array of objects?
Of course there is. You already did it in your first post.
I guess I'm confused as to why what I was trying to do wouldn't work, then? Other than ControlGetText not accepting an expression, of course...
Are you implying that it doesn't work, or that you thought I was indicating it wouldn't work? I wasn't. There is nothing in your first post to indicate there was any problem other than ControlGetText requiring a variable. You even said that you had it working with a temporary variable (HoldingVar).

new Varlist creates a new object derived from Varlist, but it does not copy the values from Varlist. MyArray[A_Index].myVar1 initially is not defined, so it returns the default value defined in Varlist. MyArray[A_Index].myVar1 := HoldingVar stores the value in the derived object, MyArray[A_Index]. So as I said, each of the 16 objects contain nothing other than a reference to Varlist (initially), but there's nothing wrong with that. I mentioned it because it can be important to understand how this works; for instance, modifying Varlist will affect all instances, except those which have their own values defined.
guest3456 wrote:He was just being pedantic and correcting your misuse of the term 'variable' in your OP when you should have used the word 'key'.
No, now I'm being pedantic:

I was not "just being pedantic" about the term "variable". To be pedantic is to be excessively concerned with minor details. In this case, making a distinction between "variable" and "array element" is not excessive nor a minor detail; it is the fundamental reason that MaxAstro's original code and any other attempt to pass an array element will not work. ControlGetText requires a variable, and this is not a variable.

My "(Actually ..." comment was perhaps more detail than necessary, and apparently only served to confuse the OP.
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: Using an Array in ControlGetText?

16 Mar 2017, 09:49

@lexikos Thank you for the detailed explanation; I'm very new to objects as a whole and learning slowly. That does I think explain why something else I was trying to do failed. I need to save products that have been loaded into the script when the script exits and reload them. I have been using a JSON script that someone else wrote to do this. However, when I attempt to do JSON.Dump(MyArray[A_Index]), it does not seem to work correctly; it ends up with a blank object in the resulting JSON string. Switching it to JSON.Dump(MyArray%A_Index%), on the other hand, works fine.

@4GForce I understand classes even less than objects, but I do agree it sounds like what I want. I mostly understand the code you provided (although I'm shaky on the syntax), except for one thing - how does the static array work? I think I understand what it does - it makes it so that, for example, if there are five items I can reference the fifth one with Product.AllProducts[5], right? But I'm not sure I understand how it achieves that.

I think it's also not quite what I need, because it looks like it always places new items at the end and I need to be able to insert an item at a specific point in the array. For example, even if the last item defined was #12, I need the user to be able to say "replace item #5 with this new item". Could I achieve that by just replacing Push with InsertAt and adding a variable to specify where to insert?

Of course its entirely possible what you gave me can already do that and I just don't understand the syntax. :)
4GForce
Posts: 553
Joined: 25 Jan 2017, 03:18
Contact:

Re: Using an Array in ControlGetText?

16 Mar 2017, 12:17

MaxAstro wrote:@4GForce I understand classes even less than objects, but I do agree it sounds like what I want.
They are pretty much the same. A class is an object and also a blueprint to create new objects.
MaxAstro wrote: I mostly understand the code you provided (although I'm shaky on the syntax), except for one thing - how does the static array work? I think I understand what it does - it makes it so that, for example, if there are five items I can reference the fifth one with Product.AllProducts[5], right? But I'm not sure I understand how it achieves that.

I think it's also not quite what I need, because it looks like it always places new items at the end and I need to be able to insert an item at a specific point in the array. For example, even if the last item defined was #12, I need the user to be able to say "replace item #5 with this new item". Could I achieve that by just replacing Push with InsertAt and adding a variable to specify where to insert?

Of course its entirely possible what you gave me can already do that and I just don't understand the syntax. :)
As for the array, it doesn't have to be part of the class and like I said it could be an associative array if you prefer referencing your product with their barcode. It's just an example I wrote real quick.
This is just another example with an associative array where the barcode is the key. ( Products.AllProducts["1048739417"].Price for example )
I also added a method to the class so it looks less empty and more usefull.

Code: Select all

loop 16 
{
	ControlGetText, barCode,, ahk_id winHwnd
	ControlGetText, price,, ahk_id winHwnd
	ControlGetText, description,, ahk_id winHwnd
	new Product(barCode, price, description)
}

for key, prod in Product.AllProducts {							; here KEY is the barCode
	msgbox % "Product " . key . " is " . prod.ShortDescription(15)
}

class Product {
	static AllProducts := {}
	__new(barCode, price, description) {
		this.Price := price
		this.Description := description
		Product.AllProducts[barCode] := this
	}
	
	ShortDescription(nbChar) {
		return SubStr(this.Description, 1, nbChar-3) . "..."
	}
}
Anyway it was just a suggestion and it all depends on what you want to achieve in the end.
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: Using an Array in ControlGetText?

16 Mar 2017, 14:05

Okay, that makes sense, thank you! That looks like exactly what I need. How does global-ness work for classes? Are they available to all functions by default or do I need to import them like global variables? Can they be made super-global?
4GForce
Posts: 553
Joined: 25 Jan 2017, 03:18
Contact:

Re: Using an Array in ControlGetText?

16 Mar 2017, 15:05

MaxAstro wrote:How does global-ness work for classes? Are they available to all functions by default or do I need to import them like global variables? Can they be made super-global?
Depending on your AHK version ...
https://autohotkey.com/docs/Objects.htm#Custom_Classes wrote: When the script is loaded, this constructs an object and stores it in the global (or in v1.1.05+, super-global) variable ClassName.
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: Using an Array in ControlGetText?

16 Mar 2017, 17:00

Thanks for your help and patience, this should be a big improvement over what I've been using if I can get it working. :)
lexikos
Posts: 9554
Joined: 30 Sep 2013, 04:07
Contact:

Re: Using an Array in ControlGetText?

16 Mar 2017, 21:07

MaxAstro wrote:However, when I attempt to do JSON.Dump(MyArray[A_Index]), it does not seem to work correctly; it ends up with a blank object in the resulting JSON string. Switching it to JSON.Dump(MyArray%A_Index%), on the other hand, works fine.
I can think of only two rational explanations for that.
  1. You didn't assign an object to MyArray[A_Index].
  2. You didn't assign the same object to MyArray[A_Index] as you assigned to MyArray%A_Index%.
In case you don't already know, they are not the same thing. MyArray[A_Index] refers to an array element of the array in MyArray. MyArray%A_Index% refers to a dynamically named variable, such as MyArray1 or MyArray2.
4GForce
Posts: 553
Joined: 25 Jan 2017, 03:18
Contact:

Re: Using an Array in ControlGetText?

17 Mar 2017, 00:14

MaxAstro wrote:Now I'm trying to store the results of a ControlGetText into a specific variable in one of the objects in the array, but I can't figure out the syntax.
Nerd stuff follow up question regarding the original post: https://autohotkey.com/boards/viewtopic.php?f=5&t=29298

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: jaka1 and 146 guests