Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

Self Enqueued Messages vs. Dedicated Value Change Event

Solved!
Go to solution

Hi everyone,

 

So I'm very new to AF, but not so new to LabVIEW and OOP. I have this rather large application that I now own but didn't design and a large portion of the application is AF based. So there are some plugin screens that are launched and have various degrees of UI. One in particular that is pretty UI heavy was designed such that every event structure case in Actor Core has a Send Message subVI rather than taking any direct action on the UI elements itself. What I'm wondering is how necessary is that? It seems a bit confusing and more overhead if I really just want to, say, change another UI element's value based on the new user input to the UI element that triggered the event. Does that make sense?

0 Kudos
Message 1 of 8
(2,295 Views)
Solution
Accepted by topic author bartelma

There are a couple reasons to move all the logic out of the VI and into messages.

 

1) If you do it consistently, then your Actor's private data knows the full state of the GUI. Like if you have a toggle button that hides a bunch of controls, your Actor can remember whether things are "hidden?". Otherwise if you just hide the controls in your Event Case, it's harder to know for the Actor to know whether they're displayed. Using the Event Case quickly gets complicated if you have compound logic like "hide the controls if disconnected, OR if hidden? is toggled"

 

2) If you need to call the same actions from outside the Actor. You can either "Connect" by pushing a button on the GUI, or you can "Connect" by the Caller Actor sending a message in. Using a message gives you a single point of entry into the Actor.

 

3) Version control. You'll get history of each action this way, rather than only knowing that your panel.vi or Actor Core.vi changed and hoping the comments are descriptive enough.

 

Yes, it is more confusing and more overhead. I think it's a limitation of the AF because you need a separate Event Structure in a helper loop that runs in parallel with the AF messaging core (Actor.lvclass:Actor Core.vi). Since they're parallel, you need to write code synchronizing them. Otherwise you might as well not use AF and just use a separate panel.

 

I dream of an inheritable Actor that automatically registers for events if a method is defined, like "MyButton - Value Changed.vi", and automatically translates Events into Messages. But I haven't seen anything like that, and I'm not smart enough to do it myself.

Message 2 of 8
(2,289 Views)
Solution
Accepted by topic author bartelma

Yes, you can use both methods to do what you need to. However, using messages is generally (but not always) the best way to go, for at least 3 reasons:

 

1- Your UI helper loop has no way to communicate with or change the state of the main Actor other than with self-addressed messages. You may have some extremely trivial UI stuff that can operate without knowing what the current state is and that doesn't change the current state, and in those cases you can just handle things in the helper loop. For example, if you had a string value change event that ensured the entered string matched an IP address regex (but triggered nothing else) then you could handle it in the loop just fine. However, if the requirement changes later on that the IP entry box must both match a string format AND have the same subnet as defined when you launch the actor, well now you have to make it a message since the helper loop can't get the actor's internal data any other way. Might as well just make it a message at the beginning.

 

2- Using messages lets you control your UI from anywhere in your code. For example, say your IP address entry box that used to only work with direct entry was now being populated from reading a JSON or ini file. This means it's being populated with a message, not with user entry, so you'll need to duplicate your verification code to make sure the JSON file had a valid IP address that matched subnets, etc. Not a huge deal, but you could see how more complicated actions could benefit from this.

 

3- Using messages lets child actors update the parents FP. If the parent's Update GUI messages are dynamic dispatch, then the child can override the update message entirely or add additional functionality and using Call Parent Method. If the UI element can ONLY be updated from the event loop, then ONLY the event loop can update it (see #1). This is useful for separating "business logic" from "display logic". Child actors could implement their own Actor Core to have their own display, not showing the parent's.

 

All in all, I've done it both ways, and almost always wind up converting my actions into messages. I have very frequently found that UI elements nearly always need access to the actor's state (either reading or writing), so 90% of the time I have to put the function in a message. I say "nearly always" because there are certainly some times that yes, this action is VERY trivial, so just keep it in the helper loop. I bet you'll find that many (most?) of the methods that operate on the UI do some other stuff in addition to just changing something on the screen.

 

IMHO, operating directly in the helper loop isn't "wrong", it's just that it severely limits your ability to interact with the UI.

 

Edit: Dangit, OneOfTheDans beat me to it 🙂

Message 3 of 8
(2,285 Views)

Wow, that totally makes sense now Bert and OneOfTheDans! It just took me a second to realize that what I was thinking of doing was totally disregarding the fact that I could and should store another piece of information in the Actor Class Data for later use rather than storing that data in some other method like an FGV. So if I store the data in the class data, the helper loop can never get it! In this case, that's the biggest reason for keeping the action I have in mind as a message rather than just doing it in the event case. 

 

Thanks for chiming in so quickly guys!

0 Kudos
Message 4 of 8
(2,232 Views)

No prob 🙂

 

Couple quick tips- first, the MGI Panel Manager toolkit is great and includes out of the box support for actors, and it's very useful for GUI's. Second, add a cluster to your actor's private data called "UI Refs" or similar and just make it a habit of bundling a reference to your UI elements and adding it to the actor's private data as one of (if not the) first thing you do in Actor Core.vi. There are some scripting tools out there whose name escapes me at the moment but it adds right click menus that let you right click a control or indicator and it'll automatically add the type to the actor's private data, create a reference, and bundle it up for you.

0 Kudos
Message 5 of 8
(2,191 Views)

@BertMcMahan wrote:

No prob 🙂

 

Couple quick tips- first, the MGI Panel Manager toolkit is great and includes out of the box support for actors, and it's very useful for GUI's. Second, add a cluster to your actor's private data called "UI Refs" or similar and just make it a habit of bundling a reference to your UI elements and adding it to the actor's private data as one of (if not the) first thing you do in Actor Core.vi. There are some scripting tools out there whose name escapes me at the moment but it adds right click menus that let you right click a control or indicator and it'll automatically add the type to the actor's private data, create a reference, and bundle it up for you.


I think this is what you are referring to:


https://forums.ni.com/t5/Actor-Framework-Documents/Events-for-UI-Actor-Indicators/ta-p/3869260

Sam Taggart
CLA, CPI, CTD, LabVIEW Champion
DQMH Trusted Advisor
Read about my thoughts on Software Development at sasworkshops.com/blog
GCentral
Message 6 of 8
(2,185 Views)

No but you got me to look, and it's this one (it's a QD plugin): http://www.labviewcraftsmen.com/blog/merry-script-mas

 

It had some glitches though and didn't work 100% with how I needed it to, so I had it on my list to modify a bit actually. Thanks for linking yours- I think it'll integrate with my workflow better, so kudos!

0 Kudos
Message 7 of 8
(2,174 Views)

Great points above! Just informing on what I do for a couple of things:

 


@OneOfTheDans wrote:

2) If you need to call the same actions from outside the Actor. You can either "Connect" by pushing a button on the GUI, or you can "Connect" by the Caller Actor sending a message in. Using a message gives you a single point of entry into the Actor.

If I do not need to call the self-messages from outside the Actor, I put such messages in a virtual folder marked Private within the 'Messages for this Actor' virtual folder of the Actor library. The corresponding methods of the Actor would ideally be marked for community access. (I'm too lazy to do that. Instead, I just create a virtual folder called 'Community' in the Actor's class, and dump these methods there.)

 

@BertMcMahan wrote:

Second, add a cluster to your actor's private data called "UI Refs" or similar and just make it a habit of bundling a reference to your UI elements and adding it to the actor's private data as one of (if not the) first thing you do in Actor Core.vi. There are some scripting tools out there whose name escapes me at the moment but it adds right click menus that let you right click a control or indicator and it'll automatically add the type to the actor's private data, create a reference, and bundle it up for you.


For this, I created a 'UiActor'. This actor has a protected method that accepts a sub-classed GUI Actor's 'Actor Core.vi' reference and its corresponding menu refnum. Using the VI reference, the UiActor builds a dictionary data member of all controls and indicators in the GUI based on their labels, including those within tabs and clusters. I use this dictionary to then set various common properties via wrapper (protected) methods, e.g. showFpItems, enableFpItems, disableMenuItems, etc. Certain GUI events like showing or hiding panels or userLogged[In/Out] have AF messages defined in the UiActor itself.

 

With this approach, I was able to have my GUI panels focus on responding to domain-specific events, e.g. eStop[Triggered/Reset], engine[Started/Stopped].

 

Message 8 of 8
(2,123 Views)