I am trying to add order to a large VI with a large number of controls. The large number of controls is due to a number of different specialized tasks the main vi organizes.
To better organize the front panel, I was hoping to make use of subpanels with vertical scroll bars that display only the relevant controls. The idea is that there is a class that contains all possible variables required in any of the tasks. For each task the class has a unique setter function.
However, there is a problem. When I try to load a setter function into the subpanel, the program fails with "LabVIEW: The VI is not in a state compatible with this operation.". I attached a minimal working example to this post, that shows this behavior (LV 2017). It contains a class with 3 variables, their individual setter functions and a getter function for a cluster of all variables. Both non-member VIs in the project call the getter VIs via static and dynamic loading, but it fails both times. I also changed the inputs of the member functions to "required" and not "dynamic dispatch".
Could it be that I need a main class and create child classes for each task? Since I am new to this, I would appreciate an example of the correct usage.
Googling the error message leads to: http://digital.ni.com/public.nsf/allkb/DE45BD35AFE818E2862565FB00592B31. However, the Subpanel example in the example finder uses the Open VI Reference successfully to place subvis in subpanels, so I am a bit confused by the information given there.
Previously I used a tab control that contains different clusters on different tabs. The inputs in these clusters were copied by references to a main cluster by exploiting that they have identical names.
I would also be interested in knowing if there is an alternative way of achieving what I described at the top. If possible I would like to use LVOOP for it, since I would like to work with it more and it sounds promising.
I'm not on 2017 yet (still on 2015) so I can't check this solution to see if it works for you, but I had a problem similar to this a while back that I was able to fix by changing the VIs giving me errors from ".vi" files to ".vit" (template) files. Unless you open ".vit" files in a very special way, opening one of them always opens a new copy of the version on disk, meaning you don't run into some of the issues where VIs are in some way locked/reserved/etc.
You can give that a shot...
I just realized I did not attach the class file in the archive and since I can not edit my previous post anymore, the files are attached to this post. They come for LV 2015 and 2017.
OK, I see the problem. You're calling a class VI with a "required" input but you're not giving it the required input in the first loop there.
You need to run the VIs using their connection pane each time, like you're doing in the "value change" event. The "Run VI" invoke node doesn't work with any VI that has a required input like that.
I looked at the first loop, but I can not find the unconnected connector you mentioned.
The error is generated in the loop, where the member VI gets called the first time.
Also I still get the same error, even after I changed all inputs to recommended.
Below I attach snapshots of the block diagram and the error message.
Instead of the Run VI invoke node, use the Start Asynchronous Call. Then you can supply the needed inputs for the VI.
Ok, the first part works: Load member VIs into subpanels.
What does not work is: Using the controls of the member VIs (loaded in the subpanel), to change the values of the class variables, as read out by the "get all" member VI.
Also the program produces a time out at the "wait on async call subvi", when I change "value" the second time.
Do I need to adapt the event structure to watch for changes in the loaded subvis or wire the class wire differently - isn't it bad, that it branches, or is it ok due to the wait on async call subvi?
It appears that you're missing one of the fundamental properties about classes in LabVIEW, in that they're all value-based. Not reference-based. Unlike many other languages, you can't manipulate a class in two separate locations just by copying a pointer, which is what I think your program's structure is based on.
In the first loop, where you run it 3 times, you're creating 3 separate instances in memory of the container class. The "set" VIs all run once, (presumably doing nothing but setting their respective value to the default of zero one time) and then all of the subpanel VIs terminate, and then you can get the output values back one time and only one time per "set" VI, as the "collect" node you're calling in your event case gets the values, and when you try to get the values a second time, the VI didn't run to begin with, so it times out.
If I'm correct, you need to change your overall design to one of two things:
Option one: Convert your class object so that its data is internally stored by reference, so when you copy it you copy the reference. You could consider using either a data value reference or a single element queue (see the "Reference Object" example in your "labview\examples\lvoop\ReferenceObject\ReferenceObject.lvproj" directory, assuming it still ships with 2017. If it's not there, just google "Single-element queue" to find out more).
Option two: Set up all of your sub-panel VIs to run continuously (i.e. they all have a "While" loop in them) in parallel with your main VI. Then arrange for them to pass information back and forth by some means. You could use a Queue, or user events, or a functional global variable/action engine. The exact method is up to you but the main way it would work is that you keep the one true copy of the data in one location, and you have a method of either sharing access to that location that is restricted to only one VI at a time, or have one location that does all of the reading and processing and the other locations are restricted to messages either instructing it to perform operations or to send information back to a requester.