I have a problem with a task in LabView that I thought would be simple and pretty standard, but I am failing to acomplish it nonetheless.
The task: I have a measurement VI that aquires data in a loop. This may take a while, so I want to show the incomplete dataset to the user "as it grows". This should be done in an extra window so I want (need?) to use a SubVI. I want this SubVI's front panel to open at the beginning of the measurement and close at the end.
I put it in the measurement loop, so it gets called after each new datapoint is taken and can display the updated dataset. I set it to "show front panel when called", so it opens at the beginning of the measurement (first iteration of the loop), just as I want it to. But it doesn't close. If I check "Close afterwards if originally closed" it closes after each iteration of the loop, which is very annoying.
Also I tried calling FP.Open, FP.Run and FP.Close with an Invoke node but then I have no idea how to actually call the SubVI in the measurement loop and feed data to it.
Is there a general misconception in my approach? Or is there an obvious solution I failed to spot?
It sounds as if you have the SubVI displaying the data you want and it's just closing the front panel at the right time that you're stuck on. In that case the simplest way to do it is to keep the VI in the measurement loop, with the Show Front Panel When Called setting checked, and just use the FP.Close method to close the front panel when the loop is finished:
This implies that you're passing all of your acquired data to the subVI every time round the loop; that's not a problem if the size of the data is small, but a more scalable approach would be a producer/consumer pattern using a queue as Joe suggests. To do this:
Create the queue in your top level VI and pass the reference in to your measurement loop
Also pass the queue reference to your subVI, which sits outside your measurement loop
Your subVI contains the consumer loop which waits for data on the queue and updates the subVI's display with it
Don't set the subVI to show its front panel when called; use the FP.Open and FP.Close methods on it in your top level VI to open and close its front panel when needed.
You'll need to give the subVI some way of knowing when to exit when your top level VI is finished; a convenient way of doing this is to force-destroy the queue in the top level VI which will cause the Dequeue Element in the subVI to exit with an error.
Another option would be to keep your subVI in the measurement loop, pass it only the new data each time round the loop, but give it a 'memory' using an uninitialized shift register in which it accumulates the acquired data for display. Search the LabVIEW help for functional global variable for more detail on this approach. Again, use the open/close methods from your top level VI to show or hide the front panel.
Both approaches are workable, good for small project, not ideal for a larger/complicated setup where more precise control over what displayed data is required.
With the first approach you would have to find a reference to the open VI somehow, to manipulate with its front panel state by reference. Say, global variable of VI reference type will work.
With the second approach, what you are missing to call the vi with all the parameters is Call by reference node
For a more controllable approach, I would start the subVI on the start of the program (FP closed) and then communicate panel open/close and data update by firing custom user events to the subVI events structure.
If you use the Producer/Consumer pattern, you can use a queue to send the data as it arrives to another VI.
Related
I have two VIs. The first VI (AsynchronousCall.vi) performs an "asynchronous call." (see in the following picture)
The following VI (Test.vi) is started by the asynchronous call. (see in the following picture)
The first VI only iterates over an array and starts the Test.vi. An element from the array is passed. This element should then be used in Test.vi. However, the first entry from the array is not passed correctly after the first call.
It follows that my asynchronous program does not receive the correct input data.
Important: In order to recreate the Senario, the front panel of Test.vi can be opened first after the asynchronous call. Because when it's open, it works as intended!
The target/actual comparison is in the following list:
Target value
Asynchronous program should have "Test_0" as input parameter.
Asynchronous program should have "Test_1" as input parameter.
Asynchronous program should have "Test_2" as input parameter.
Asynchronous program should have "Test_3" as input parameter.
Actual value
Asynchronous program is "" (empty string) as input parameter.
Asynchronous program is "Test_1" as input parameter.
Asynchronous program is "Test_2" as input parameter.
Asynchronous program is "Test_3" as input parameter.
How can it be avoided that the string is empty the first time it is called?
The 32-bit version of LabView 2015 is used, but this Senerio also occurs with newer versions (32-Bit LabVIEW 2019)
When you call a VI asynchronously with the Front Panel closed, LabVIEW does not appear to update the values displayed in the controls - this makes sense from a resource perspective as why paint an update to a control that no one can see?
If you were to perform an operation on the passed value in your test VI - such as writing it to a file or some shared queue you should be able to verify that the correct value is indeed passed, just not displayed in control on the front panel. The one button dialog can also be used for debugging this but it might block the open VI reference call in the launcher VI and thus cause your launcher loop to stall. See this discussion on LAVA forums about the root loop and the built-in dialog windows.
I am currently working on a LabVIEW project and have found myself stuck on how to make a while loop exit when I press the abort (stop) button. For a simple while loop I understand how to do this - but the problem is that this while loop is nested inside of an event structure and I'm guessing that the button cannot be pressed while the loop is executing. Attached here is a picture of part of my code (that contains this specific event case which is causing me problems): To spend a little more time explaining what the problem is - I think the code is doing what I want it to do (namely output a set of commands in a repeated cycle with a wait timer) but I cannot stop the code mid cycle (pressing the abort button with my mouse does nothing - as in the button doesn't show it being pressed and the indicator shows no change, I also can't use any other functionality of my program during the cycle which I'm assuming is related). And I do not want to stop the LabVIEW program from running entirely - just the code inside the while loop pictured above. This is what the front panel is configured too for completeness:
Essentially what I want to happen is the while loop to execute when I press DWG and in the middle of the cycle be able to abort it. Sorry if my code seems a little messy. Additionally, I've tried the same code with a for loop originally (via a conditional terminal so it could stop early) and that didn't work either. Thanks for any help I appreciate it!
Your problem is that inside the event structure, by default the UI is frozen so no UI actions (keyboard/mouse/etc) are processed until you exit that frame.
Option 1. You can right click the Event Structure and select "Edit events handled by this case" dialog and then uncheck the "Lock panel" checkbox -- that will allow the UI to be live while you are in that frame. I do not recommend this solution generally unless you have an extremely simple user interface because it leads to the user being able to change controls without the events behind those controls being processed (not a good UI experience for users). But if the UI is simple enough, that works.
Option 2. You can create a user event that is the code you want inside your While Loop. When the Deg Wait Go button is pressed, use the "Generate User Event" node to trigger that event. Do the same thing in the user event case so that the event re-triggers itself if and only if the Abort button has not been pressed.
Option 3. Create a separate loop OUTSIDE your UI loop that does your processing with some sort of command queue running between the UI loop and that other loop. The other loop moves into various states at the request of the UI loop... it's the one that does nothing until it receives a "go" message and then keeps looping until it receives a "stop" message. You can Google "queued message handler" for extensive details of this solution. This is the most common solution for complex UI requirements, especially useful for separating concerns of the UI code from the execution code.
I had an problem regarding design of EVM machine.
Once the button is pressed a vote must be counted. So for that a counter is needed how to create that?
Without knowing more about your project, I'd use a WHILE loop with an EVENT Structure. The Event Structure waits for a Value Change event on the button. On a change of a button, the corresponding value in the shift register is increased by 1 and displayed.
The snippet is missing the initialization of the indicators, since they are updated on the first click, only.
I'm in the process of developing a new .NET system. It has 24 form screens and multiple record sets for the SQL D/B. I'm looking for specific ways of controlling the screens (I've numbered them and one calls the next) but I'm not sure if just opening a screen over the last one is the right way to do it. Should I be hiding the old ones or just leaving them under the new ones? I want to go back to the prior screen when complete with the screen open.
Secondly, with all the record sets needed to populate the screens I have a single connection to the database and multiple record sets. Not sure how to be sure if a record set is already opened by a prior screen or not. Or should I close every record set when I leave a screen and reopen if necessary?
These are basic control questions as to how to navigate through the screens and the record sets.
Finally, should I have the one connection opened at the beginning and then only closed at the end?
I know these are probably basic question to the experienced but I'm just a beginner with event driven code.
All help would be appreciated. Also, I'm not an Object Oriented Programmer but a Procedure programmer so making classes, objects, etc., is not my thing.
Thanks again for all assistance.
Jim R
I'm looking for specific ways of controlling the screens (I've numbered them and one calls the next) but I'm not sure if just opening a screen over the last one is the right way to do it. Should I be hiding the old ones or just leaving them under the new ones? I want to go back to the prior screen when complete with the screen open.
You should in my opinion create the form and dispose of it when done. Creating a screen over another one can get a little disgusting and isn't a good practice. For example: what if you instantiate a screen and on load you are populating data? The issue with this is, you would have to call another function or method to refresh this data OR close this form out and create it again; it's better to close it out and open it when needed as the data may have changed.
Secondly, with all the record sets needed to populate the screens I have a single connection to the database and multiple record sets. Not sure how to be sure if a record set is already opened by a prior screen or not. Or should I close every record set when I leave a screen and reopen if necessary?
You should have your classes populated by now and know which one's are. These would determine what record sets are in fact populated. When you close/dispose a form (screen) the record set's should be disposed with that class unless you are doing this in another class.
Should I have the one connection opened at the beginning and then only closed at the end?
As my comment from above, it's a great practice to close the connection at all times, never leave it open. You should open the connection, perform your query and immediately close this connection. I'm not sure if you have a class or not to handle your connections, but I would advise to create one that can handle your connections; opening and closing the connections.
I need to know what the event loop in the ios life cycle does?.
Can any one suggest me regarding this??
The best answer is probably the one provided by Apple in the "Main event loop" section of the Cocoa Application Competencies for iOS document.
In the main event loop, an application continuously routes incoming events to objects for handling and, as a result of that handling, updates its appearance and state. An event loop is simply a run loop: an event-processing loop for scheduling work and coordinating the receipt of events from various input sources attached to the run loop. Every thread has access to a run loop. In all but the main thread, the run loop must be configured and run manually by your code. In Cocoa applications, the run loop for the main thread—the main event loop—is run automatically by the application object. What distinguishes the main event loop is that its primary input source receives events from the operating system that are generated by user actions—for example, tapping a view or entering text using a keyboard.
Incidentally, if you're relatively new to iOS development, I'd really recommend a read of this document, as it'll answer a lot of questions you probably have.