01-08-2013 05:44 PM
I'm writing an application, where several loops are running in parallel (e. g. read sensor data, receive UDP packets, send UDP packets, wait for input). Except for some configuration data, the loops are completely independent from each other (occasional communication is done via queues). Each of the loops will run indefinitely until told to stop by commands to a queue and is in its own subVI (otherwise the main blockdiagramm just containing the overall state machine would start to grow outside the screen, which is even worse than having to scroll in a text based language). Each of the subVIs also shows some information (status, sensor data, graphs, debugging).
So the big question is: how can I show all these subVIs information in a single window?
Using the "subpanel"-container is pretty much out of question. It adds almost as much clutter to the blockdiagram than the loops would do themselves (with "create vi reference", "insert vi", "run vi", "remove vi"; and that for every parallel subVI) and makes the code harder to maintain. Even worse, Labview is no longer able to tell me if one of the subVIs is currently broken (e. g. because there was a change in a typedef that requires changes in a subVI) until I run the complete program (or open each of the subVIs individually). Getting parameters into and out of the VIs isn't easy either that way (no more simple terminals).
I thought about making the subVIs' appearance titlebar-/menu-/borderless and floating and hardcoding a pixel position for all of them. But I can't really control what resolution the PCs running this program will have. So I fear they will be all over the place with no possibility for the user to move them around. This would also mean the main windows would always have to stick to the top left, which in itself would annoy users.
I remember having this problem already. My solution at this time was to make a copy of every frontpanelobject of the subVIs on the main VI (thereby cluttering the blockdiagram with heaps of unconnected terminals), creating a reference to that object, bundling them all together and writing it in a global variable. Then every subVI would pick out the references it needed and change the value with the value property node. Globals and changing the value per reference both being pretty bad Labview practice, it was still more manageable than dynamic calls to subVIs (which the subpanels comes to, although it shouldn't be needed). What making this approach not very practical this time, is, that some of the subVIs (and what they show) may be developed by other developers. This would mean for every frontpanel object they add/change/remove a reference needs to be added/changed/removed. While the reference list will be it's own cluster typedef, still all other subVIs will have to be updated, too.
Maybe I missed something. But is there really no simple option like "show frontpanel when loaded at this position within parent frontpanel"? Would make things soo much easier and way easier to maintain.
01-08-2013 08:55 PM
You can use WinAPI functions to set child windows, but it is a hassle. LabVIEW doesn't officially support it and there is an issue with minimizing and restoring the windows. The function calls are fairly straight forward. The issue is that it appears that LabVIEW assumes the desktop is the parent. When restoring the window, it restores the position relative to the desktop instead of the parent. So, whatever offset you have vetween your parent window and the desktop origin is added to the child windows restoration, so it jumps when restored.
Although I have never done it, I believe you can capture the restore as an event, and fix it, but you will still see a jump, then anothe rjump to get back to where it was. Since LabVIEW doesn't support this, they won't change the restore issue. It should be a simple fix, I think.
But you would still have to write code to handle all that. If you think using subPanels are cumbersome, I don't see any easy solution for you. Frankly subPanels are quite easy to use, and that is the route I would go. Although it is not as simple as dropping a subVI, you can use asynchronous calls and pass input and output terminals.
01-08-2013 09:27 PM
01-09-2013 01:12 AM
@cober wrote:
...But is there really no simple option like "show frontpanel when loaded at this position within parent frontpanel"?
Other than the reparenting functions suggested, subpanels are your best bet and the others are correct that they're not that hard to use.
Specifically, they can do exactly what you want if your subVIs aren't reentrant. Just drop the VIs in the BD as you normally would and then drop a Static VI Reference from the Application Control palette and drag the subVI into it. Now you have a reference to the VI which you can use to put it into SP.
The only caveat with this is the resolution issue. You could obviously set the SPs to resize automatically the way you want, but I'm not sure how that would affect the VIs they're displaying.
01-09-2013 03:56 AM
@cober wrote:
Using the "subpanel"-container is pretty much out of question. It adds almost as much clutter to the blockdiagram than the loops would do themselves (with "create vi reference", "insert vi", "run vi", "remove vi"; and that for every parallel subVI) and makes the code harder to maintain. Even worse, Labview is no longer able to tell me if one of the subVIs is currently broken (e. g. because there was a change in a typedef that requires changes in a subVI) until I run the complete program (or open each of the subVIs individually). Getting parameters into and out of the VIs isn't easy either that way (no more simple terminals).
I think you're confusing the code for dynamically loading and running a VI via VI Server, with the code for just a subpanel (which is just insert/remove). A common use case of subVIs, but as others have said above, you can use a subpanel to show the front panel of a regular subVI, or one called by static reference. These are less "cluttered" and don't have the problem of broken subVIs.
-- James
01-09-2013 10:22 AM
If your subVIs aren't doing updates very quickly, one way I've done this is to use User Events to send the updated information to my main VI (which has the event structure) and then update the front panel with the event data.
01-09-2013 11:46 AM - edited 01-09-2013 11:56 AM
@mikeporter wrote:
I'm sorry I'm not aware of any "cumbersome" subpanels - unless of course you don't know what you're doing. There is this wonderful invention called a "subVI" that can be used to organize and simplify your code, or are they too "cumbersome" as well? You should really learn a bit about what you are pontificating over before you start running off at the mouth.
Mike...
I didn't want to step on your toes. No need to get personal.
Subpanels make some additional code necessary that hasn't got to do anything with the actual program. And I AM using subIVs as I wrote in my first post, which is exactly the root of the problem.
Nevertheless I now solved it in a way that comes close to what I wanted. I don't know if some of you meant your suggestions to be understood that way (at least I didn't 😉 ). The subVIs will now "insert" themselves (via invoke node) into a subpanel on the main vi, which they are given a reference of at call. This adds minimal aditional code, especially on the main VI which I want to keep as clean as possible. By clustering the panel reference into the parameters the subVIs are already given (not used in the example I attached below), there isn't even a change on the terminals of the subVIs.
I got to check now if this works well with event structures within the subVIs or if it can create the same problems like multiple event structures within a single VI.
So no global variables anymore and no writing values by property node. I don't know if this just wasn't possible in previous Labview versions I had a try at that (I guess it was 8.6 and/or 2009) or I just didn't come up with the idea back then.
And if the text wasn't that helpful, here are two screens:
Parent VI:
SubVI:
01-10-2013 03:50 AM
Your method certainly works and is a legitimate architecture, but it's important to also be aware of its pitfalls:
The method I suggested looks like this:
01-10-2013 07:19 AM
@tst wrote:
Your method certainly works and is a legitimate architecture, but it's important to also be aware of its pitfalls:
- You're tying the VI so that it has to be displayed in a subpanel (i.e. it expects to be in a subpanel).
- You're distributing the responsibility for the subpanel (at least in principle). That means that different components could fight for the same subpanel. In practice this won't happen if the reference is only given to one subVI.
You're right especially with point 2. Since the subVIs may be developed by different people, even if they get a reference to only a single subpanel, there's no guarantee they're doing it right. The way I'm currently developing my application the references would have been part of a "config"-cluster, that all subVIs get at startup, so in principle they could pick the wrong reference out of it. Not a huge thing to check, but still.
With my solution if they decide that it's not the front panel of the subVI they want to show but a subVI of the subVI, it's very easy to achieve. On the other hand, if there wasn't the reference to the parent VI's subpanel, they could add their own subpanel within the subVI an achieve the same for a sub-subVI.
Just one thing I've seen while testing events: if the subVI doesn't remove itself immediately when finished, the frontpanel stays visible and the user can still trigger events, which won't be handled anywhere anymore. This blocks the event handling of all the other subVIs and locks the whole UI (so it has the same caveats as using multiple event structures in a single VI). If the subVIs got the reference of the subpanel they are in, they can remove themselves as last action. But point 2 again: then there's a need to check if it's implemented correctly within the subVIs. (btw. I don't expect all the subVIs having event structures with dozens of cases, if at all, it'll rather be a few events of buttons/sliders to change the way data are displayed)
01-10-2013 07:23 AM
Personally I prefer having the sub panel insertion in the Sub-VI itself.
I simply check when the VI is started if the sub panel reference is valid and if not, then I don't try to insert. The nice thing about this is that this also works with LVOOP because it doesn't violate encapsulation of private data (Reference of dynamic dispatch VIs).
The only positive thing is that the other way around the VI can be inserted at any point. To do this with my option would require some signalling (notifier, event) to support insertion during execution.
Shane.