Non-trivial applications require complex user interfaces. The goal is to keep them as simple as possible but the fact is that if the software needs to do a lot of stuff then there are going to be a lot of controls and indicators. User interfaces can always be split up conceptually (these controls are for loading while those controls are for previewing data, for example) but splitting them up in LabVIEW can often be daunting. We must make compromises. Here are some of the normal approaches:
|Mega UI||Easy to get started.
If implemented correctly can be a good user experience.
|Code gets complex very quickly.
Very coupled code.
|Subpanels||Modular UIs that are easy to test and maintain.
Good user experience.
Components can be reused
|Increased code complexity.|
|Dialogs||Modular UIs that are easy to test and maintain.||Bad user experience (pop-ups that have their own pop-ups)|
Good User experience
Components can be reused
|Steep learning curve
None of these are clear winners!
Abstracting the Panel
The Front Panel is the smallest complete user interface. Using subpanels, a front panel can consist of any number of other front panels. This can be nested indefinitely. This means that a front panel can be a fully complete, concrete implementation of a UI, or it can just be a partial implementation with subpanels where other VIs will fill in the missing functionality. This can be used to split up our user interface into encapsulated chunks to create extremely modular UIs. What’s the difference between a VI that’s being shown as a window, and one being put into a subpanel? Not much! One will be shown as a Window, and one will be inserted into a subpanel. Once they’re running, the business logic will be almost identical. This is the core of what the MGI Panel Manager does. The MGI Panel Manager abstracts away the question: “Where is this front panel going to be displayed?”
This means that a developer writes a user interface that implements the “Panel” interface. Then the user of that interface specifies the concrete type of panel to use. This makes it trivially easy to do things like:
- Insert a VI into a subpanel.
- Create a unit test VI that displays a panel as a window for testing, but insert the same VI into a subpanel in the real application.
- Dock and Un-dock a panel from subpanel as needed.
While the first bullet may seem insignificant, it ends up being the most important. It makes it so it is just as easy to implement a subpanel based UI as it is to implement a dialog based UI. It also lets us reuse UI VIs as common UI components. This basically merges all the “Pros” of all the UI types without any of the “Cons”.
The Panel Interface
Panel.lvclass is the generic type for all panels. If you want a VI to use the Panel Manager Framework, all you have do is use the Panel class. Typically, there are only two methods of the Panel class that your UI will call – Init, and Close. What Init and Close mean depend on the type of panel. For a Window type, Init will pop up the new window and Close will close it. For a Subpanel type, Init will insert the panel into the subpanel, and Close will remove it. Notice how the implementer of the UI doesn’t write code specific to the panel type. They just write their UI, and implement the interface. The Panel Manager Framework does the rest.
So far, we’ve been mostly talking about two different type of panels: Window and Subpanel. The Framework is extendable though. If you come up with a new type of panel, you can just override the Panel class appropriately, and now all your old UI code can be displayed as the new panel type. Here are a few panel types that we’ve already implemented:
|Window||This is the most basic type of panel. The front panel will be displayed as a new window. See the article on the Window Panels for more info.||Base|
|Dialog||This is a special type of Window Panel. This means that anything that applies to the window panel also applies to the Dialog Panel. The only difference is a dialog panel will also be set to modal.||Base|
|Subpanel||These panels will be inserted into a subpanel.||Base|
|Tab Panel||This is a panel that will be inserted into a tab control. This uses the .NET framework to create and manage the tab control. The .NET TabControl allows the framework to create and remove tabs during runtime and it works better when creating resizable user interfaces.||.NET Panels|
|MDI Panel||This is a panel that will be inserted in a Multiple Document Interface (MDI). This finally allows LabVIEW developers to quickly and easily create an MDI interface.||.NET Panels|
Using the Panel Manager in your framework
The core of the MGI Panel Manager is just a few classes. It is designed to be used by any arbitrary framework. If you’re using a custom framework you should be able to take Panel.lvclass and implement it as needed. This means that all you have to do is implement the
Panel.lvclass interface once and your framework will now support all of the different types of panel! MGI has already written the Panel Manager implementation for some popular frameworks.
This is included with the base “MGI Panel Manager” package We are big fans of the Actor Framework (AF). We kept AF in mind when designing the Panel class to make sure everything played nicely. This is the best way to use the MGI Panel Manager so we included it in the base Panel Manager Package. To create a new User Interface Panel, all you have to do is override the Panel Actor Class. Then when launching use “Launch Root Panel” or “Launch Nested Panel” to launch it with a specific panel type. Your actor’s “Actor core.vi” will be displayed as the Panel. See our separate article on Panel Actors for more info.
This requires the “MGI Panel Manager - DQMH Panels” package
Another popular framework is written and maintained by Delacor, Inc. (See the DQMH on the NI tools Network for more information). Installing the “MGI Panel Manager - DQMH Panels” package will add two new templates when creating modules. These templates implement the Panel interface.