Mass Compilers

cancel
Showing results for 
Search instead for 
Did you mean: 

MJE Subpanel Config Dialog LV2013.zip

In anticipation of the upcoming meeting, here's the code I will be discussing.

It's a config dialog where you specify an array of VIs to use as configuration categories modeled after the LabVIEW configuration dialog. Each VI runs asynchronously and is hosted in the main window's subpanel when you click on the category name corresponding to the VI. The code can be run by executing Config\Example.vi in the supplied zip file.

The pattern I used here is one I have moved to in recent years: object encapsulation with a high level non-object oriented interface. This allows a high level single VI interface which can be used by anyone even if they don't know object oriented design, the Show.vi is an example of this. It wraps the more advanced object oriented interface. For this simple example, the Config.lvclass doesn't expose anything the higher level Show.vi method doesn't already handle, but imagine enough advanced configurability being added to the class to the point where the connector pane on Show.vi would become overwhelming, never mind the possibility of inheritance.

Getting back to the topic at hand, there are a few subtleties here which demonstrate how I often work with subpanels: Generally speaking I rarely have the host insert a running VI into a subpanel, rather I pass the subpanel refnum into a running process and allow it to take appropriate action. One reason I do this is to allow the hosted panel time to initialize. Rather than inserting a VI which may not be ready to be shown and having the screen flicker as things are updated, the hosted VI can do what it needs to do behind the scenes, and show itself only when its ready. Another reason is when considering more complex architectures the host may not have any idea of what needs inserting into the subpanel. By passing the subpanel refnum to the other task, the decision about when and what to dump into the subpanel can be delegated to a context which likely has more relevant data to make the decision.


Another caveat about asynchronous tasks that comes into play is event registration and race conditions. Generally speaking I'm skeptical of blindly adhering to the adage of registering for events on the same diagram that uses the registration. If I pass a user event to a task and I'm going to control that task via that user event, I need to make sure that the task has registered the event before I send any data through the event. If I leave registering the event as the responsibility of the task I'm spawning, I then need another layer of hand shaking so I can be sure the registration is complete before I send any data through the event. I generally find it much cleaner to instead perform registration of mission critical user events in the host that spawns the task. This pattern can be seen in Start Categories.vi, which pre-registers a pair of events for each category VI it spawns (the events used to tell the VI to exit and to insert itself into a subpanel).

Finally note I'm using the call and collect option for running the asynchronous VIs. Even though the category VIs in this example don't return anything I'm still interested in waiting for them to return such that I can be sure they've recorded any changes before the hosting VI moves on. It's also conceivable that the example could be re-worked such that the individual category VIs return data by value, but this detail is really something that's application specific.

Message 1 of 18
(12,304 Views)

I rarely have the host insert a running VI into a subpanel, rather I pass the subpanel refnum into a running process and allow it to take appropriate action.

I also usually do this, but I have encontered problems sometimes, if the VIs can potentially be delayed longer than the timescale of UI actions.  If the User selects A, then quickly B, it is posibly for A to place itself in the subpanel after B, leaving A showing but B selected.  Solving this race condition requires a central component to be the only one handling the subpanel.

Message 2 of 18
(10,871 Views)

Very good catch. I missed that detail when simplifying.

I've also dealt with it by tracking an ID with each request. If something tries to insert and it has a stale ID the request may be ignored or error out depending on context.

0 Kudos
Message 3 of 18
(10,873 Views)

kegghead wrote:

I've also dealt with it by tracking an ID with each request. If something tries to insert and it has a stale ID the request may be ignored or error out depending on context.

One can also use a destroyable reference, such as sending a subpanel-in-a-DVR, rather than a bare subpanel reference.   Then the sender can destroy the DVR sent to A before creating a new DVR to send to B.  Thus A can never insert into the subpanel after B has been selected by the User.

0 Kudos
Message 4 of 18
(10,873 Views)

drjdpowell wrote:


One can also use a destroyable reference, such as sending a subpanel-in-a-DVR, rather than a bare subpanel reference.

I like that idea even better because it's simpler. I shall update the code in the next few days to do as much.

Probably add a few things to the class API to demonstrate the point of having two interfaces. Last night when going over the code at the user group I also noticed I forgot to typedef the strict VI refnums.

0 Kudos
Message 5 of 18
(10,873 Views)

I've modified the file to include appropriate typedefs and JDP's DVR recommendation. However I've run short on time to expand the class API to include any additional features.

0 Kudos
Message 6 of 18
(10,873 Views)

This is really nifty code. Thanks for sharing it and for the thorough writeup.

I'm skeptical of blindly adhering to the adage of registering for events on the same diagram that uses the registration.

I tried the approach of registering events not on the block diagram of an Actor Core.vi--it doesn't work. I'll just be lazy and ask: what is the condition that causes this "remote" registration to sometimes work and other times not? Reentrancy? Otherwise, your statement sounds perfectly reasonable to me.

0 Kudos
Message 7 of 18
(10,873 Views)

Interesting, I can't think of any reason it wouldn't work. The only issues I've had with event registration have been related to race conditions, hence the mechanism to ensure registration has happened before the event is used.

Do you have an example that shows the behavior?

0 Kudos
Message 8 of 18
(10,873 Views)

I should note that 10 years ago I tried branching the 'event registration refnum' that comes out of the Register For Events node, in order to connect to Event structures in different loops that I wanted to listen for the same events. It almost functioned properly but I got really weird behavior, like missed events and incorrect event order. I asked a Labview developer at NI and he told me to NEVER BRANCH the event registration refnum, that it was never intended nor tested and 'bad things will happen.' So ever since then I only branch the event refnum (such as outputs from Create User Event) and always keep the Register For Events node close to the single Event structure it goes to.

-Joe

------------
Joe Czapski, Sonos, Boston, Mass.
0 Kudos
Message 9 of 18
(10,873 Views)

there is definitely issues with parallelism and events that tie back to one of Jon's favorite topics 'the Root Loop' since events, strictly speaking, come into LV on 1 pipe from the windows event messaging system, and flow through a single message stack at the application layer into the 'currently active window' for handling.

.

by branching the event registration reference you're basically trying to parallelize something that is not terribly comfortable being parallel so races/misfires are possible.  After trial and error over the years with subpanels, I find usually it is the mouse focus that dictates which event handler gets what.

.

Just for fun, try 'catching' an event that is application specific, or VI window specific at both the subPanel Level, & at frame level and you'll often find that it is the Frame vi's event structure that will catch these non-control-specific alerts  (my classic frustration here is Hotkey events for subframe actions are almost always 'caught' by the the frame, who then may need to broadcast the 'i was asked to tell you to do x' style message via conventional framework down the pipe to the window who actually can do something about it.  Again, active mouse focus would solve it, but with hot keys especially, users don't want to be told 'first click on the thing you want to hot key, then Ctrl-S'  as it just feels unnatural.

.

Branching / creating multiple references can work, and i've done it,  it's just a matter of being aware of the thread-unsafe 'fight' that is happening.  General rule of thumb is don't ever try to put the same event in both event structures, and 9-times-out-of-10 things will run as expected. the minute they both try to handle timeout events, or a particular mouse action, all bets are off. 😞

0 Kudos
Message 10 of 18
(10,873 Views)