Jump to content

OOP UI Frameworks


Recommended Posts

This thought crossed my mind the other day and I pinged AQ on it offline and got a good response. I just thought I'd open it up to the community as well.

 

In more complex UI frameworks, they enhance UI reusability. For instance, with my limited text based experience I realize most frameworks allow you to create a dialog class that inherits from some parent dialog. You then, by default, get the onOK and onCancel methods. If you just have a simple dialog you don't have to do anything for these methods the parent method will just be called. And if you need something more complex, you can override them.

 

After talking to AQ he pointed out that is because of dynamic event registration. I already knew we had the ability to dynamically register with controls but I never put two and two together. He also mentions this "for most UI deisgns, it is more work to pass around refnums and dynamically register than to just statically register. It is only when you start designing and inheriting UI frameworks that the balance of effort shifts in favor of dynamic registration."

 

So, I guess I am just curious if anyone has gone the route of implementing things this way and found it beneficial? This is pretty much just an open ended question; just curious on people's responses. I just have found myself rewriting almost identical event cases in most of my dialogs, and was trying to mitigate the need for having to do this. That is what prompted this whole discussion.

Edited by GregFreeman
Link to comment

I have my own UI Parent Actor that has some useful functionality with methods I found myself needing quite often (some GUI initialization). From that actor, I have a couple basic dialog classes and a subpanel actor class. The subpanel actor has useful methods for inserting itself into a subpanel reference and handles a couple other small tasks (like determining how it looks inside the subpanel).

 

I played around a little bit with dynamic event registration, but only for one specific case: stopping a UI event loop. My parent UI actor core registers a dynamic event, and I register the UI's event loop with that event. Then I have something in the UI parent Stop Core that sends the "stop" event out to the loop.

Link to comment

I do a lot of this, but oddly enough often shy away from it for UI interactions.

 

Architecturally my frameworks are often designed around this. BaseClass is designed to receive SomeMessage which invokes a dynamic dispatch BaseClass:OnSomeMessage for which child classes may override as desired. In the end the underlying transport layer disappears and largely becomes irrelevant to the component designer-- all that matters is picking off the right level in the hierarchy and implementing the right overrides to hook into the larger application. The framework could be event based, home-baked queues, actors, or voodoo, it doesn't matter much at the component level.

 

I don't find myself using this type of framework for handling too much of the controls in a UI though. Dynamic registration is very powerful, but at the end of the day your dynamic event registration is not extensible. What do I mean by this? If your register for events node is set up to work with ten different events, that's all it will ever do. The next level in the hierarchy can't add another set of events, it needs its own registration.

 

Add to that the venerable front panel is filled with statically defined interface elements means I don't see too much use for objects in this context. Yes, my frameworks may have some level of inheritable functionality that implements an OnCancel method or the like, but at the end of the day they're method calls that are made from a single event structure in a single loop, in a single VI.

 

Don't get me wrong, I use a ton of dynamic events, just not in the inheritable OOP context.

  • Like 2
Link to comment

I do a lot of this, but oddly enough often shy away from it for UI interactions.

 

Architecturally my frameworks are often designed around this. BaseClass is designed to receive SomeMessage which invokes a dynamic dispatch BaseClass:OnSomeMessage for which child classes may override as desired. In the end the underlying transport layer disappears and largely becomes irrelevant to the component designer-- all that matters is picking off the right level in the hierarchy and implementing the right overrides to hook into the larger application. The framework could be event based, home-baked queues, actors, or voodoo, it doesn't matter much at the component level.

 

I don't find myself using this type of framework for handling too much of the controls in a UI though. Dynamic registration is very powerful, but at the end of the day your dynamic event registration is not extensible. What do I mean by this? If your register for events node is set up to work with ten different events, that's all it will ever do. The next level in the hierarchy can't add another set of events, it needs its own registration.

 

Add to that the venerable front panel is filled with statically defined interface elements means I don't see too much use for objects in this context. Yes, my frameworks may have some level of inheritable functionality that implements an OnCancel method or the like, but at the end of the day they're method calls that are made from a single event structure in a single loop, in a single VI.

 

Don't get me wrong, I use a ton of dynamic events, just not in the inheritable OOP context.

This is fairly inline with what I have been doing, and your third paragraph with regards to extensibility is what I have found as well. In fact, just yesterday, I tried seeing if a cluster of event registration refnum clusters would wire into the terminals on an event structure. Alas, I got a broken run arrow. Too bad those terminals can't recursively register through clusters of clusters of event registration refnums, or an array of them, or something so I can have a "get events" method that I override in the children, which calls the parent "get events" method and appends events then returns them all. Maybe this is unnecessary but I can think of a couple of places in my code it may prove useful.

Edited by GregFreeman
Link to comment

Yeah. The limiting factor is despite the event *sources* being able to be changed dynamically at run time, when it comes to the linkage between the registration refnum and the event structure proper the linkage is static. You can't drop in a new event type at run time and say when that event fires to call some method or event frame.

Compare that with an object approach where dynamic dispatching allows complete abstraction, the lower level loop and transport mechanism doesn't need to know anything about what it is ultimately routing.

Link to comment
  • 2 weeks later...

Personally I like coupling the dynamic dispatch behavior of the implementation with a static definition of the API for such an extensible UI.

 

I feel the dynamic aspect of LVOOP is great for determining HOW something is done but I still much prefer the static datatypes of Events to determine WHAT should be done.  This is a reason why I don't really like the Actor Framework because there's no way to effectively implement a limited API.

 

I have recently started a discussion with AQ on almost exactly this topic regarding the ability to manage such "extensible" static datatypes (registered user event refnums) within LVOOP frameworks.  It seems I may not be the only one running into this wall.


By the way: As long as the UI interaction is handled BY THE CLASS, there is no problem with extensibility, even with events.  Each class knows which events it can and cannot register for and control.  It's only when you need to interface to the world outside of the class boundary that the dynamic - static problem rears its head.


BTW, the Discussion took place HERE.

Link to comment

So last week I started working on a new UI. The layout of the UI is highly variable depending on what the user is doing. Certain controls are hidden or shown depending on what task is being performed, and may move around.

 

I've moved each little UI module into its own subpanel actor. When events fire on the subpanel actor, each actor decides if it needs to pass a message up to the Controller for handling. The Controller decides what actors should be loaded into which subpanels, and also handles arranging the subpanels in different layouts.

 

This isn't quite what most of us here might envision and doesn't really have to do with dynamic event registration. Also, the amount of effort involved is such that you wouldn't want to design an entire actor for such trivial interface elements. But it is a way to have user events trigger methods in a Controller, from a variety of sources that can be decided at run-time.

Edited by Mike Le
Link to comment

James, that has indeed piqued my interest.

 

I've actually never used an event callback VI but the idea of dynamically assigning functionality to events seems very useful.  Is this the missing link I have been looking for?

 

I have to try something out......

Link to comment

I just looked at the code.

 

Interesting.  Unusual thing is realising the work being done invisibly by the callback VIs.  This seems really weird.  I'm used to seeing the work being done in the BD I'm looking at but I suppose if the scope of that kind of work is strictly limited it'd be OK.

 

Still, I find the code very interesting.  Nice use of a variant tree for storage.

Link to comment

It is possible to get around that by using event callbacks. It is intended for activeX and .net support but seems to work with internal LabVIEW events without issue. I used it to be able to set up dynamic binding for an MVC framework - http://www.wiresmithtech.com/mvc-in-labview-library/

 

In my case I'm not using OO to change the response but you could make the callback method a static parent method and then have a dynamic dispatch core VI inside (I don't think you could use dynamic dispatch directly).

Nice, I never even thought to try this. Ironically, I have often said to people, "I wish LabVIEW had callbacks support" (other than .NET and ActiveX like you noted). Well, whaddaya know...

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
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.