Jump to content

An attempt to reduce the number of event structure cases in my UIs


Recommended Posts

Hi all,

 

as the complexity of some of the systems I have worked on grew, I found that I could have dozens of user controls in my diagrams, handled by an event structure. Almost all of the case structure cases handled "value change" events and simply enqueue the new value and a "X changed" type command to the appropriate module or remote target.

 

Having 80 cases in an event structure, all doing more or less the same thing seems like it's crying out for refactoring.

 

I came up with attached class in order to capture UI command-value pairs and write them to a network stream, using just one case of a case of the event structure. It leads to a lot less code repetition (at the expense of some more BD real estate on the left hand side) but I am more or less happy with it because it's less wiring overall.

 

I made an example (attached) to demonstrate it. What do you all think of this way of structuring my UI code? What improvements could be made?

 

 

 

 

 

 

 

Link to comment

I too have done different things to better handle this kind of scenario.

 

Recently my interest has beek piqued by the possibility of using callback VIs for registering the Events rather than using the Event structure itself.  The advantage of this?  You can split the handling of the events among different levels of an object inheritance chain.  This method couples well with the command pattern for the receiving end.

 

Advantages: Essentially allows us to split up individual frames of the Event structure into individual (boiler-plate) VIs.

Disadvantages: Knowing somehow that the events are being handled somewhere and that the callback VIs themselves run int he root thread.

Link to comment

I too have done different things to better handle this kind of scenario.

 

Recently my interest has beek piqued by the possibility of using callback VIs for registering the Events rather than using the Event structure itself.  The advantage of this?  You can split the handling of the events among different levels of an object inheritance chain.  This method couples well with the command pattern for the receiving end.

 

Advantages: Essentially allows us to split up individual frames of the Event structure into individual (boiler-plate) VIs.

Disadvantages: Knowing somehow that the events are being handled somewhere and that the callback VIs themselves run int he root thread.

 

I can see the benefit to this, but callback VIs seem to obfuscate the code greatly to me, as you mention in your disadvantages list.

Link to comment

The code obfuscation is really an annoying (and very serious and real) part of the implementation.  It is enough to stop me applying the idea in a widespread manner because the cost of debugging can be large.

 

The only other thing I could think of woule to implement the callback VIs with LVOOP and have the parent optionally include some debugging information which cen be centrally logged / viewed / sorted.  I believe it could be solvable but my 24 hour days don't give me enough time to come close to doing such an idea justice.

Link to comment

I tried having call-backs that called methods on a LVOOP object inside a DVR.  It worked, except that occasionally two events happening at about the same time caused the UI to freeze, possibly due to some kind of lock-up involving the DVR and the UI thread in which the callbacks run.  This was near impossible to debug, and I abandoned callbacks in favor of an asynchronous VI that handled events with an Event Structure (calling the same LVOOP object held in a shift register).

Link to comment

Reminds me of another method I've used in the past where I group lots of functionally similar events and place each group in it's own event structure, blatantly disregarding the general idea to not have move than one event structure in your code....  :thumbup1:  At least that way I could remove and add new functional groups without having to touch other event structures.

Link to comment

Your code was not attached, but I often use variants, dynamic registration of arrays of control references, and control labels that encode the message that needs to be sent, as illustrated in this old post.  I also done similar things connecting multiple controls with Camera Attributes or DAQmx channels.

 

Yep this is pretty much what it is, as shown in that thread. I just made the message name independent of the control name. I also found that sometimes I wanted to associate a particular message name to a particular value of the control.

 

For example: Log button becoming true sends "Start Logging" command, Log button becoming false send "Stop Logging" command.

 

The thing I like about this is that I can handle fiddly "stateful" control logic inside XControls. The Xcontrol has an enum value and I can register a particular enum value to a command specific command message.

 

For example, a "tape deck " type control with play, pause, resume and stop / abort buttons. Three button, four messages "Play" "Pause" "Resume" and "Stop". The X control logic wraps the "button logic" up nicely without having to smear it over 4 cases of you main UI's event structure.  

 

Advantages: Essentially allows us to split up individual frames of the Event structure into individual (boiler-plate) VIs.

Disadvantages: Knowing somehow that the events are being handled somewhere and that the callback VIs themselves run int he root thread.

 

So now would you have 80 boilerplate VIs instead of 80 event structure cases?

Link to comment

For example: Log button becoming true sends "Start Logging" command, Log button becoming false send "Stop Logging" command.

 

The thing I like about this is that I can handle fiddly "stateful" control logic inside XControls. The Xcontrol has an enum value and I can register a particular enum value to a command specific command message.

 

For example, a "tape deck " type control with play, pause, resume and stop / abort buttons. Three button, four messages "Play" "Pause" "Resume" and "Stop". The X control logic wraps the "button logic" up nicely without having to smear it over 4 cases of you main UI's event structure.  

 

I solve this issue a different way, by making my messages all "control-likeâ€: a label and a value.   So I would have messages:

 

“Set Loggingâ€, a boolean that is True or False

“Set Play Stateâ€, a string (or possibly enum) with values "Play" "Pause" "Resume" or "Stop"

Link to comment

Mark, does this mean you have 80 controls on your FP?

 

If this is the case for me, the controls ussually correspond to each other or not, so you put them into clusters, then you just register the value change for cluster.

Once the event happens,

the left Event nodes will give you Old + New value, so compare, this gives you the index of the control changed,

get the control reference out of the cluster, read it's name and wire it to the case structure.

 

Now you have 8 event cases where each has case struct with 10 cases named by the controls. Works fine for me and makes the BD more readable.

Event.vi

Link to comment

After re-reading your problem, I guess this approach is better.

 

Make an array that translates the control names and possible values into messages (or whatever data you use to control your program further).

 

I use this approach as well, cool thing is that all translations are LabVIEW data, so you can make your own code to add new dictionary entries, so change to FP means you will just need to run some VI that will populate/change the array and you can script your own code to do that.

Event.vi

Translator.vi

Link to comment

So now would you have 80 boilerplate VIs instead of 80 event structure cases?

 

No, of course not.  You would need one single VI per datatype you are registering events for.  If not everything is a typedef, this tends to not be too many VIs.  Of course there would be 80 VIs in memory (callback VIs), but not 80 VIs on disk.

Link to comment

Mark, does this mean you have 80 controls on your FP?

 

If this is the case for me, the controls ussually correspond to each other or not, so you put them into clusters, then you just register the value change for cluster.

Once the event happens,

the left Event nodes will give you Old + New value, so compare, this gives you the index of the control changed,

get the control reference out of the cluster, read it's name and wire it to the case structure.

 

Now you have 8 event cases where each has case struct with 10 cases named by the controls. Works fine for me and makes the BD more readable.

 

Hi bublina yes I definitely use clusters for parameters that are related. I just look for a cluster change event and send the whole cluster if just one element has changed though, I typically don't care which one has changed. So if I had a cluster of PID loop gains on the front panel, I would just send a message called "PID loop gain changed" whenever the proportional, integral, or derivative gains where twiddled.

 

 

After re-reading your problem, I guess this approach is better.

 

Make an array that translates the control names and possible values into messages (or whatever data you use to control your program further).

 

I use this approach as well, cool thing is that all translations are LabVIEW data, so you can make your own code to add new dictionary entries, so change to FP means you will just need to run some VI that will populate/change the array and you can script your own code to do that.

 

good to see I'm not the only one thinking this way! Yes I chose to implement he dictionary is a variant hash, I just like being able to look up any kind of data with a string instead of iterating through an array. Probably is a wash performance wise.

 

 

No, of course not.  You would need one single VI per datatype you are registering events for.  If not everything is a typedef, this tends to not be too many VIs.  Of course there would be 80 VIs in memory (callback VIs), but not 80 VIs on disk

 

ah ok makes sense.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.