LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How to implement a Callback VI when a LV control has it's value changed via ActiveX?

We have a 3rd party application that can talk to any control on a LabVIEW VI's front panel using the LabVIEW ActiveX server (or ticking the Enable ActiveX Server box if using a LabVIEW EXE).

 

I've just realized that if any of the controls on the VI's front panel are registered for a value-change event, that event will NOT fire if the value is changed over ActiveX -- it only fires if you physically click on the button in the LabVIEW UI.   Note that the value *does* change, but the event structure doesn't fire.

 

I'm hoping there is a way for me to get the event structure to fire without having to change the 3rd party software.  Is there a way for a VI to be introspective about one of its control's values being changed over ActiveX? If so I'd like to create a modular VI that I can throw down in any VI's block diagram that is looking for value changes over ActiveX to one of it's FP controls to then launch a callback VI with the affected control's reference and issue a 'value (signaling)' property to fire off the event structure.

 

Is this doable?


0 Kudos
Message 1 of 9
(3,549 Views)

I don't know anything about the AX server, so I can't comment on that, but this is not restrictred to that - most methods of setting the value don't invoke the value change event (locals, Set Value method, etc.). That's why VI server has the Value(signaling) property, which does.

 

The first thing to do would be to check whether the AX API has a similar method. If it doesn't, I think you're stuck with workarounds.

 

The proper way to do this is to decouple the UI from the logic, and then you can simply use another channel to send the same information to your logic from the external app.

 

The other options are more ugly.

You could simulate mouse clicks, but that's error prone.

You could set up a separate loop or subVI which would monitor the events for all controls, as well as their values, and if it recognizes a value change without an event, it calls the val(sgnl) property for that control to generate the event. This can be made generic (although you can set the value on latched booleans), but it's still ugly.


___________________
Try to take over the world!
Message 2 of 9
(3,518 Views)

@tst wrote:

 

 

The proper way to do this is to decouple the UI from the logic, and then you can simply use another channel to send the same information to your logic from the external app.

 


This is something we have on the books for when we have time to go back and refactor a lot of our existing code.  It is definitley the right way to do it and we just started using this decouple & messaging approach for one of our newer projects.  I was hoping for a quick-and-dirty work around for the existing code until we get funding to go back and change it.

@tst wrote:

 

You could set up a separate loop or subVI which would monitor the events for all controls, as well as their values, and if it recognizes a value change without an event, it calls the val(sgnl) property for that control to generate the event. This can be made generic (although you can set the value on latched booleans), but it's still ugly.


I actually implemented something similar already but I've hit a very annoying issue which made me hope there were other avenues.  I created a generic stand-alone VI that you can throw down into any existing VI that will grab a reference to the parent and enumerate all the parent's control references.  It will then poll on those controls to determine if 'Last Iteration Value != Current Iteration Value' and if true, call the Value (signaling) property.  This works flawlessly as long as the values are *always* changed from the 3rd party tool.  Unfortunately, we cannot guarantee this to be the case as the VI's frontpanel is still visible (a requirement) and if somebody clicks on a control registered for value-change via the LabVIEW FP then I get two events firing -- one from my polling loop and one from the standard LV UI thread.

 

Since I am polling there is no deterministic way to tell which of the two events gets fired first nor does there appear to be a way to know if an event was fired via a "value (signaling)" property or through an actual mouse click.  Because of these two facts I am stuck trying to figure out how to supress the 2nd event.

 

It sounds like your solution is similar in concept but different in execution.  Could you further elaborate on this idea?  

 

Thanks for your help 


@tst wrote:

This can be made generic (although you can set the value on latched booleans), but it's still ugly.


Just wan't to make sure you meant "you can't set the value on latched booleans" because this was something I found to be a limiting factor causing a broken run arrow.  If I was able to get past the 2-event firing problem we could live with the mandate to only have switched booleans until the more reasonable approach could be implemented.

 

Thank you for the help!

 

EDIT: Added Snippits of what I've already done for clarity

 

Monitor Value Changes

 

Event AE


0 Kudos
Message 3 of 9
(3,496 Views)

 


@SeanDonner wrote:

Just wan't to make sure you meant "you can't set the value on latched booleans"


Yes. Can't, not can.

 


@SeanDonner wrote:

It sounds like your solution is similar in concept but different in execution.  Could you further elaborate on this idea?  

It is, with one addition - the "if it recognizes a value change without an event, it calls the val(sgnl) property for that control to generate the event" part, which I didn't elaborate on. Basically, you can set up an array of ms values in the monitoring VI which is parallel to the references array. When you get a value change event, you do a search 1D array on the CtlRef terminal to find the place in the array and update it with the time of the event (or with a timestamp, if you think your app could be running for more than 50 days, which is the rollover time for the tick count).

 

When you see that a value has changed, you check the array for the last time that control had an event, and if it's less than X, you don't generate the event.

 

This still has some potential issues, such as what happens if the event arrives when you're already scanning the controls for the value change, but it should probably work.

 

As for the latched booleans, it might be possible to do something with simulating mouse down events or sending the relevant window a mouse down message, but I would avoid those if possible, particularly if the user is interacting with another program at the same time.


___________________
Try to take over the world!
0 Kudos
Message 4 of 9
(3,469 Views)

@tst wrote:

When you see that a value has changed, you check the array for the last time that control had an event, and if it's less than X, you don't generate the event.


I don't recall the specifics because it was a few months ago and i'm just now revisiting this issue, but I did do something similar with timestamps messing with the top-level event structure to set control flags but I still observed the race condition you described.  Also, I didn't particularly like having to mess with the top-level VI, ideally I could find a solution that only requires me to drag in a stand-alone sub-vi.

 

How about this.  Can I have both the top-level VI *AND* the polling sub-vi both registered for the same value-change events?  i.e is there a way for a sub-vi that contains an event structure to fire based on a value-change event from a control in the top-level VI without having to programatically generate one? 

 

If so then I think I can solve the race condition by doing the following:

 

1) Every iteration the polling VI does an equality check on value followed by blocking on its own event structure registered for value-change events for all controls in the top-level vi.  The Event structure has a reasonable timeout set 

 

2a) If the equality check shows a change in value, I set a defer counter flag to '2' and set the disable property on the control to prevent possible further firing. 

 

2b) If when blocking on the polling VI's event structure I get a fire, I set an 'event fired' flag associated with the control ref that fired

 

3a) On subsequent iteration I decrement the flag by 1 and check it's value 

if counter < 0 : No value-changes seen, set counter back to 0

If counter > 0 : Value change seen for 1 iteration.  Inhibit any changes other then possibly setting an 'event fired' flag and go to next iteration.

if counter == 0: Value change seen for 2 iterations.  Check the control ref's 'event fire' flag to see if it is set.

    If set:  Value-change was via LabVIEW and an event was triggered on top-level, no further action needed.  Unset 'event fired' flag and set 'Enabled' property on control

    If unset: Value-change was via ActiveX so we need to call the 'value (signaling)' property.  Unset 'event fired' flag and set 'Enabled' property on control.

 

Other than having the control be disabled for two iterations of the polling loop, I think this has eliminated most race conditons* and doesn't require me to mess with the top-level VI at all other than throwing down the monitor stand-alone VI.  Of course this all hinges that a sub-vi can register for and have events fired from value-changes from top-level controls.  If that's possible, how do I do it?

 

Thanks

 

*Note: The race condition still exists when more than one event fires from LabVIEW before a single iteration of the polling happens

 


0 Kudos
Message 5 of 9
(3,440 Views)

@SeanDonner wrote:
i.e is there a way for a sub-vi that contains an event structure to fire based on a value-change event from a control in the top-level VI without having to programatically generate one? 

Absolutely. I didn't read your whole reply thoroughly, but here's the basic idea:

 

Example_VI.png

 

I think the time check is enough and there's no need for your flags and disabling, but I didn't analyze it fully.


___________________
Try to take over the world!
0 Kudos
Message 6 of 9
(3,430 Views)

A simpler method, that I believe would be race-free would be:

 

1) Poll for changed values (but just record the changed ones)

2) Handle all Value-Changed events in the event queue. 

3) Fire Value(signalling) for any changes from (1) not seen at (2)

0 Kudos
Message 7 of 9
(3,427 Views)

Can who implemented  either of the bridge VIs share the same?


I am new to LabView and I need to fire some events but can't do so with ActiveX.

 

0 Kudos
Message 8 of 9
(2,981 Views)

@gyani95 wrote:

Can who implemented  either of the bridge VIs share the same?


I am new to LabView and I need to fire some events but can't do so with ActiveX. 


The images in above posts are snippets. You can download them to your computer and then drag them from your computer into an empty VI diagram et voilà, you get the code.

Rolf Kalbermatter
My Blog
0 Kudos
Message 9 of 9
(2,964 Views)