VBA Passing Class Arrays to Functions - arrays

Apologies if I am making some amateur mistakes, but I am new to VBA.
I'm trying to populate an array declared inside of a class as a property, but something's going wrong. After much searching I have two questions that I can't seem to find anywhere else:
1 - Is there a simpler way to accomplish saving data to an array-like structure that I can pass to functions from a sub? The array-like structure needs to be resizable because I will not know how many components I will add until each iteration of a loop checks those conditions.
2 - How do I correctly accomplish the passing of the array property in my class correctly to another function? It's frustrated me enough that I would like to know how it can be done if only to understand what I was doing wrong or, perhaps, what misunderstanding I had of the way VBA works.
Code structure follows:
I have declared a Segments property inside of a CTask class like this:
Private pSegments() As CSegment
Public Property Get Segments() As CSegment()
Segments = pSegments()
End Property
Public Property Get segment(index As Integer) As CSegment
segment = pSegments(index)
End Property
Public Property Let Segments(Value() As CSegment)
pSegments() = Value()
End Property
I pass the CTask from a Sub, where it is defined to populateTasks using this code:
Dim tasks() As CTask
ReDim tasks(1 To 10)
Call populateTasks(tasks)
When I do this, the populateTasks code receives it using the following code:
Function populateTasks(ByRef tasks() As CTask)
I then try to call another function from populateTasks called populateSegments like this:
Call populateSegments(tasks(icount).Segments)
I receive segments array inside populateSegments like this:
Function populateSegments(ByRef Segments() As CSegment)
The last two code snippets are where the problem resides. The segments array is populating correctly inside the populateSegments function, but when I check the array to see if it is empty just below the call to populateSegments there isn't anything in the tasks(icount).segments array. Thanks in advance for any help, and please let me know if more information is required.

Couldn't you make populatesegments a method of cTask? That avoids the problem and is a better design

Related

How to create an array of actions?

I am writing a VB.NET Class, and I have run into the issue of needing to create an array of actions. How does one do that in VB.NET?
UPDATE: I am trying to write a collision detection class that stores objects to collide with, and functions to execute when the collision happens with indexes that line up the object to the function.
So like:
Class CDE
Private Collidables As Windows.Forms.Control()
Private Actions As 'Action Array
There's not enough info to provide a specific answer here, but you would create this array the same as you would create any other array in VB.NET.
Dim actionsArr = New MyAction() {action1, action2, action3, action4}
On a side note, I've always been more fond of using Lists over arrays. It's much easier to add and modify items in a list.
https://msdn.microsoft.com/en-us/library/bb385204.aspx

VBA excel passing an array to sub fired by button

As in title I would like to pass an array to the sub which is executed by a button (That's why I don't know ho to pass it to the sub). Array is calculated in the Sheet before you can exectue sub with the button.
I've tried using:
Option Explicit On
Public My_array(1 to 10)
But I have received an error that I can not do that command with array, const etc.
What is the correct way to do it?
I think there is some terminology we can try to clear up: you're not actually passing the variable to the button's procedure. A publicly scoped variable is going to be available within that procedure and does not need to be "passed".
Note: I'm not sure what you mean by "Array is calculated in the Sheet". Unless you are using some event procedure to calculate an array in memory (probably you are not, because you don't have the array scoped or declared properly to do this...), this statement can't possibly be true.
Your declaration should be like:
Public myArray(1 To 10) As Variant 'or As String, As Double, etc.
You can omit the As ... part and it will be type Variant. if you need more strongly-typed array, then you will need to specify.
Also, On is not a legal keyword after the Option Explict statement. So, remove that. But keep Option Explicit in all of your modules.
The error message you receive hints at the solution: You can't put public declarations in object modules. An object module is a Worksheet, Workbook, UserForm, or Class module in the VBE.
You can only put these declarations in a normal code module.
Solution: Move the declaration of myArray to a normal code module.

How to access a main document class array from a movieclip?

I have an array in my main
public var graphArray:Array = [1,2,3,4,5,6];
And I'm trying to access it from within a MovieClip that I've put on my timeline using:
var graph1scale:Number = MovieClip(root).graphArray[0]
It looks like it would make sense to me but when I try to run it I get this error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
Am I wrong to be using MovieClip(root) to try and access it? I've only just started using external classes (this is my first project doing so) and usually I just do everything on the timeline. So MovieClip(root) is familiar to me but I guess it's not the right thing to do here.
Is there a way I can access vars from Main.as?
-----SOLVED-----
I realised MovieClip(root) did work all along but I was just calling on the array before the array was being defined in Main.as. I put a delay on calling graphArray and it worked.
Not sure how that makes sense though because the graphArray is the first thing I've defined in the whole main.as class
Try using this instead
MovieClip(this.root)
This works for me on a test that you can see here:
http://marksost.com/test/as3arrayaccess/
And the source files here:
http://marksost.com/test/as3arrayaccess/test.zip

matlab initialize array of objects

I am playing around with OOP in MATLAB, and I have the following constructor:
function obj = Squadron(num_fighters, num_targets, time_steps)
if nargin == 0
num_targets = 100;
time_steps = 100;
num_fighters = 10;
end
obj.num_shooters = num_fighters;
for iShooter = 1:obj.num_shooters
a(iShooter) = Shooter(num_targets, time_steps);
end
obj.ShooterArray = a;
obj.current_detections = zeros(num_fighters, num_targets);
end
That temporary variable 'a' smells terrible. Is there a better way to initialize an array of objects, I wish there was a push/pop method. I am sure there is a better way to do this.
Looks like you are trying to create an array of handle objects (Shooters) and store it inside the property of another handle object (a Squardron). I have had a very similar problem discussion that might help you.
In short: What you are doing might not be pretty - but might be pretty good already.
When creating an array in Matlab it is usually a good Idea to do some pre-allocation to reserve memory which speeds up performance significantly.
In a normal case something like this:
a=zeros(1,1000);
for n=1:1000
a(n)=n;
end
(here a=1:1000; would be even better)
For objects the pre-allocation works by assigning one of the objects to the very last field in the array. Matlab then fills the other fields before that with objects (handles) that it creates by calling the constructor of that object with no arguments (see Matlab help). Hence a pre-allocation for objects could look like this:
a(1,1000)=ObjectConstructor();
for n=1:1000
a(n)=ObjectConstructor();
end
or simply
for n=1000:-1:1
a(n)=ObjectConstructor();
end
Making sure Shooter can be called with no arguments you should be able to do something like:
for iShooter = obj.num_shooters:-1:1
obj.ShooterArray(iShooter) = Shooter(num_targets, time_steps);
end
However, it turns out that for some reason this direct storing of an array of objects in another object's property creates very bad performance. (Probably the array pre-allocation does not work well in this case). Hence using an auxiliary variable and allocating the full array at once to the property is in this case is a good idea to increase performance.
I would try:
for iShooter = obj.num_shooters:-1:1
a(iShooter) = Shooter(num_targets, time_steps);
end
obj.ShooterArray = a;
Again - for more detail see this discussion
There are a couple of ways to handle this situation...
Building object arrays in the constructor:
You could modify your Shooter class such that when you pass arrays of values it creates an array of objects. Then you could initialize ShooterArray like so:
obj.ShooterArray = Shooter(repmat(num_targets,1,num_fighters),...
repmat(time_steps,1,num_fighters));
Replicating instances of a value class:
If Shooter is a value class, and each object is going to be exactly the same (i.e. you don't initialize any of its default properties to random values), then you can create just one object and replicate it using REPMAT:
obj.ShooterArray = repmat(Shooter(num_targets,time_steps),1,num_fighters);
Unfortunately, if Shooter is a subclass of the handle class, you can't just replicate it as you can with a value class. You would actually be replicating references to just one object, when you really need a number of separate objects each with their own unique reference. In such a case, your current code is likely the best solution.

Accessing variable from other class returns null

I did a separate levelData class to be able to flexibly add levels. I was happy with it until my supervisor ordered me to convert my levelData into XML. I did an XML version of the levelData's data (question, answers, correct answer...). I used the old class and converted it so that it fetches the XML.
All seems well, I did traces of my answers array and it printed nicely...
But the headache started when I tried this.
// This code appears in a different class with
// currentLvl:LevelData initialized in the constructor.
quizHolder.ansA.ansHud.text = currentLvl.choices[1];
quizHolder.ansB.ansHud.text = currentLvl.choices[2];
quizHolder.ansC.ansHud.text = currentLvl.choices[3];
quizHolder.ansD.ansHud.text = currentLvl.choices[4];
// BTW, I can't make a for loop to do the same function as above. So wierd.
I tried to run it. it returned:
TypeError: Error #2007: Parameter text must be non-null.
at flash.text::TextField/set text()
at QuestionPane/setQuiz()
at QuestionPane/setQuestion()
at QuestionPane()
at LearningModule()
Where did I go wrong? I tried making a custom get function for it, only to get the same error. Thanks in advance. If I need to post more of the code, I will gladly do so =)
LevelData Class in PasteBin: http://pastebin.com/aTKC1sBC
Without seeing more of the code it's hard to diagnose, but did you correctly initialize the choices Array before using it? Failing that I think you'll need to post more code.
Another possible issue is the delay in loading the XML data. Make sure your data is set before QuestionPane tries to access it.
When did you call
quizHolder.ansA.ansHud.text = currentLvl.choices[1];
quizHolder.ansB.ansHud.text = currentLvl.choices[2];
quizHolder.ansC.ansHud.text = currentLvl.choices[3];
quizHolder.ansD.ansHud.text = currentLvl.choices[4];
these? You load the XML and on complete you fill the array, what is correct. but is the XML loaded and parsed to the time when you access (fill the TextFields) the choices array already?

Resources