how to use JSON object as a global lookup table? - autohotkey

I want to preload a json file to build a global JSON object (by JSON.ahk) as a lookup table and use it in several functions. However its content is empty when accessed from function body. It seems that AutoHotKey's global variables are weird. Anyone could help me out?
The code is as below:
#Include JSON.ahk
global appJsonObj := JSON.Load(FileOpen("ahk_app.json", "r").Read())
_ShowOrMinimize(app)
{
; static appJsonObj := JSON.Load(FileOpen("ahk_app.json", "r").Read()) ; static variable is ok
; minimize if active
WinGet, A_proc, ProcessName, A
proc := appJsonObj[app].process . ".exe" ; why appJsonObj[app].process is null
}

Related

What are the semantics of input variables passed by reference?

Beckhoff's TwinCat-3, as well as Codesys 3 it's based on, adds references as an extension to IEC-61131-3 languages. I'm wondering what is the exact grammar and semantics of this non-standard addition (that's the problem with them: nobody bothers documenting them as well as a standard would).
It the following F_IsNonEmpty function valid and doing what one would expect, when invoked from the F_Test test function below?
FUNCTION F_IsNonEmpty : BOOL
VAR_INPUT
text : REFERENCE TO STRING;
END_VAR
F_IsNonEmpty := LEN(text) > 0;
END_FUNCTION
FUNCTION F_Test1
VAR
testMessage : STRING := '123';
END_VAR
IF F_IsNonEmpty(text := testMessage) THEN
{...}
END_IF
END_FUNCTION
Given that the target of the reference must be initialized using the REF= operator (v.s. e.g. C++ where reference targets are immutable), I'd have expected that the following invoking code would be correct instead - but it doesn't even compile:
FUNCTION F_Test2
VAR
testMessage : STRING := '123';
END_VAR
IF F_IsNonEmpty(text REF= testMessage) THEN
{...}
END_IF
END_FUNCTION
It seems that F_Test1 works correctly, but I'd like someone who actually uses Codesys 3 or TwinCat-3 REFERENCE TO feature to confirm.
When you use a REFERENCE in a VAR_INPUT, it's as if you were using a VAR_IN_OUT variable.
Otherwise if you declare your REFERENCE in the VAR section, you need to use REF= when assigning another variable to it (or get an exception).
In essence, REFERENCE (like a VAR_IN_OUT var) is a more convenient and "safe" pointer because the dereference operator ^ is not needed and because the type is checked at compile time.

Save a Matlab Property to a mat file

I have a class with a struct property called myStruct:
properties
myStruct;
end
I would like to save the struct to a .mat file. I tried:
save -append registers.mat myStruct;
But it gives the error:
Variable 'myStruct' not found.
I have different functions for updating the struct, like:
function configureChannel( obj, Channel )
myStruct.Channel = Channel;
save -append registers.mat myStruct;
end
function updateConfiguration( obj, dataPath )
myStruct.EN = 1;
save -append registers.mat myStruct;
end
These are all functions of the same class.
I think that the main problem in this code is how you access myStruct from your functions. Take a look at the following piece of code:
function configureChannel( obj, Channel )
myStruct.Channel = Channel;
...
end
What you intended for it to do was to assign Channel into the Channel field of the current object's myStruct's Channel property. What it actually does is equivalent to calling:
myStruct = struct('Channel', Channel);
That is, you create a new local variable in the current workspace/scope of configureChannel, without actually updating the property of the object, obj.
So the first correction you need to make is how you access myStruct in your setter:
obj.myStruct.Channel = Channel;
Next is the issue of saving.
When dumping a copy of an object's field to a file, I would expect save to treat your arbitrary object as a struct, and so struct saving conventions should apply:
'-struct',structName | Store the fields of the scalar structure specified by structName as individual variables in the file. For example, save('filename.mat','-struct','S') saves the scalar structure, S.
Thus, I would expect the following to work disclaimer: I didn't test it:
save('filename.mat','-struct','obj.myStruct');
Other alternatives in case the above fails:
save('filename.mat','obj.myStruct'); % Alternative #1
tmp = obj.myStruct; save('filename.mat','tmp'); % Alternative #2
One last thing - as you may have noticed, I'm using the function form of save, because I consider it to be more maintainable/readable/fool-proof:
save(filename,variables,'-append');

Delphi, find form by name

how can I find form by name? On this form I have Edit (TEdit) and i would like to write something in this TEdit (its name e.g.: adress) but I have only form name.
Can you help me?
There is a simpler way of finding a form by name. Since all of auto-created form objects become owned by Application object and TApplication inherits from TComponent, you can either iterate thru Application.Components array property or use Application.FindComponent method.
var
Form: TForm;
begin
Form := Application.FindComponent('LostForm1') as TForm;
if Assigned(Form) then
Form.Show
else
{ error, can't find it }
Note that FindComponent is case-insensitive.
This answer assumes you are making a VCL application. I don't know if FireMonkey has a similar solution.
All forms are added to the global Screen (declared in Vcl.Forms) object when they are created. Thus you can make a little helper function like this
function FindFormByName(const AName: string): TForm;
var
i: Integer;
begin
for i := 0 to Screen.FormCount - 1 do
begin
Result := Screen.Forms[i];
if (Result.Name = AName) then
Exit;
end;
Result := nil;
end;
You can use the FindWindow function if you know the form title or the class name of the form.

Error When Editing Member Variable in Class

I'm trying to use a class in my program.
TStack = Class
Public
constructor Create; Overload;
Procedure Add(Frm:TForm);
Procedure Remove();
Procedure Do_Close;
Private
List : Array[1..Max_Forms] of Rec;
Count : Byte;
End;
Constructor:
constructor TStack.Create;
begin
Self.Count := 0;
end;
Procedure TStack.Add(Frm:TForm);
begin
Inc(Self.Count);
List[Count].Form := #Frm;
List[Count].Width := Frm.Width;
List[Count].Height := Frm.Height;
List[Count].left := Frm.Left;
List[Count].Top := Frm.Top;
end;
I can't change value of Count variable! It cause Run-Time error : Access violation....Write of address 000001E4
What's the problem?!
FOR MORE INFORMATION:
I'm trying to store a pointer to each form in a structure like this :
Rec = Record
Form : ^TForm;
Maximized : Boolean;
Width,
Height,
left,
Top : Integer;
End;
And then
Procedure TStack.Do_Close;
var
i : integer;
MyForm : TForm;
begin
i := .....some code here.......;
MyForm := #List[i].Form;
ShowMessage('I will close '+MyForm.Caption);
MyForm.Close;
end;
AND call constructor like this to initialize 'Count':
Stack.Create;
As described in comments you are attempting to create the object like this:
var
Stack: TStack;
....
Stack.Create;
This is a classic mistake, and one that we've all made. You are calling a method on an uninitialized instance variable.
In order to instantiate a class you need to write this:
Stack := TStack.Create;
On top of that I have the following comments:
Use zero-based indexing for arrays. That's the convention everywhere in Delphi apart from anachronistic strings. And even that is changing in newer versions.
Don't use static arrays for a stack unless you have a good reason for doing so. You'll just run the risk of running out of space. Or allocating more memory than you need. Use a dynamic array.
Rather than a dynamic array, you could use TList<T>.
Even so, one wonders why you are making your own stack class when there is the perfectly good TStack<T>.
You store the address of a local variable in your stack. In TStack.Add you add #Frm into the container. As soon as TStack.Add returns, #Frm is meaningless. That's because Frm is a local variable whose life ends when the function that owns it returns. I think you want to take a copy of Frm.
Picking up item 5 in more detail, your record is declared like this:
Rec = Record
Form : ^TForm;
Maximized : Boolean;
Width,
Height,
left,
Top : Integer;
End;
It is a mistake to use ^TForm. That is a pointer to a variable holding a pointer to an object. That's two levels of indirection, one too many. You must declare the Form field to be of type TForm. I suggest you revise the way Delphi object reference variables work. Delphi classes are what is known as reference types. A variable of type TMyClass where TMyClass is class(...) is already a pointer. The language automatically de-references the pointer when you use the . operator to access members.

Delphi dynamic form array and data array management

I have to solve next problem:
Form23:
public
{ Public declarations }
FormsArray : array of TForm24;
end;
Procedure Create_form;
begin
SetLength(FormsArray, Length(FormsArray)+1);
FormsArray[Length(FormsArray)-1] := TForm24.Create(Self);
end;
Form24:
public
end;
var
UniqueValue : Array of ShortString;
Procedure Fill_Unique;
var
tmp1 : Longint;
begin
SetLength(UniqueValue, 256);
for tmp1 := 0 to Length(UniqueValue)-1 do
begin
UniqueValue[tmp1] := IntToStr(tmp1);
end;
end;
Procedure OnButtonClick(Sender);
begin
Fill_Unique;
end;
When i have one form Form24 and i fill with some values, then it is ok.
When i have two forms Form24 (FormsArray[0] and FormsArray[1]) and i change UniqueValue in one form, then i have that values in two forms.
i.e.
I create FormsArray[0] and FormsArray[1]
When I click button on FormsArray[0]:
FormsArray[0] - UniqueValue[...] = '1,2,3,4,5,6,7,8,9...';
FormsArray[1] - UniqueValue[...] = '1,2,3,4,5,6,7,8,9...';
When I click button on FormsArray[1]:
FormsArray[0] - UniqueValue[...] = '1,2,3,4,5,6,7,8,9...';
FormsArray[1] - UniqueValue[...] = '1,2,3,4,5,6,7,8,9...';
When i change code to:
Form24:
public
UniqueValue : Array of ShortString;
end;
and I click button on FormsArray[1] then i have:
FormsArray[0] - UniqueValue[...] = '';
FormsArray[1] - UniqueValue[...] = '';
UniqueValue is empty.
I need to have independent arrays in every forms Form24 i have created (different UniqueValue in every forms i create).
How to do this? What i do wrong?
Thanks for any help.
SOLVED !
I got -1 for solution what i write here. Then will be no solution. Search for yourself.
It sounds like you've already solved it. Make UniqueValue be a member of the form class. Put it in the public section of the class declaration, for example.
type
TForm24 = class(TForm)
public
UniqueValue: array of string;
end;
The first code you showed has the array as a global variable, which is of course shared by all instances of your form class, as well as everything else in your program. You're probably confused thinking that anything declared in the same file as the form class somehow "belongs to" that class, but if you think that, you're mistaken. To make something belong to a class, it should be declared inside that class, not just somewhere in the same unit file.
It looks like you'll probably want to make Fill_Unique and OnButtonClick be members of the form class, too. In the code you showed, they're standalone procedures, so they have no reference to whatever form they're supposed to work on. That means they can't refer to UniqueValue because they won't know which TForm24 instance's field to operate on.
Your UniqueValue array is declared globally, so multiple form instances are going to access the same array in memory. Moving the array into the public section of your Form class allows each instance of that Form to have its own array that is independant of other Form instances. Just make sure you remove the global array.