Creating a New Menu Selection Type

 

Here’s our fancy example menu. Well actually, it’s not that fancy…. Yet.

All of our menu items are just that, regular old Menu Items. No selection types, no special properties, nothing. We’re going to be playing with selection types a bit here, so let’s go over what our current options are:

 

  • Checkmark: Toggles a checkmark on mouse click
  • Radio: There is only 1 checkmark at a time in a radio group. Other items are unchecked when the user makes a new selection
  • Toggle Text: Alternates between two Strings on mouse click.

But those don’t quite do what I want them to. Something that I see somewhat frequently in menus is items that are grayed out. The LabVIEW IDE does it in several places, so I should be able to do it right? Well the problem is that there isn’t really a standard way to define when items are grayed or un-grayed. It we look at the picture of the LabVIEW View menu, it seems like the grayed out state depends on the state of lots of other things, like what window I have selected in this case.

So let’s define the conditions for graying out menu items in our fictional little project here. Let’s say that if Selection 1 is clicked, that Items 1 and 2 should be grayed out.  That’s a good start, but we probably also want a way to un-gray things, so we’ll toggle a checkmark next to Selection 1, and then we’ll amend our previous statement to say: Items 1 and 2 should be Grayed out when Selection 1 is checked, and un-grayed when Selection 1 is unchecked. Then we’ll go ahead and apply this same selection scheme to Selection 2, but we’ll be enabling/disabling Items 3 and 4.

So the pseudo code for our new Disable Items selection type is:

Input: Tag List (Str[])
Action: When the MenuItem is clicked, a Checkmark should be toggled.
Code:
If (MenuItem is now checked)
Gray out all sibling MenuItem’s who’s tags appear in Tag List.
Else
Un-gray all sibling MenuItem’s who’s tags appear in Tag List.

Note: I’m doing everything by tag. It’s possible to use other means to identify what items to gray out, but tag works just fine for me in this example.

Here is how we implement this in the Menu Building Framework.

First create a new class. I’ll call it Disable Items.lvclass. I want this class to inherit from the SelectionType.lvclass, so go into the class properties of our Disable Items and change the inheritance as such.

Next I’ll add an array of strings to the private data of my Disable Items Class. This where I’ll store my info about what tags to gray/un-gray.

I like the ideas of constructors. While they aren’t necessary in LabVIEW, I like to use them to ensure that the private data of my class is initialized to a valid state. In our example, the Disable Items Object wouldn’t make much sense if the Tag List was empty, so we’ll use our constructor to require the user to wire in an array of strings, which we’ll save as the tag list. I like to name my constructor VI’s the same as the labview class (concept borrowed from other OO languages), and I have a neat little template for my icon.

OK, now I want to write the actual code for my selection type. If I right click on the class and select New->VI for override, I’ll get the following window:

The asterisk next to ItemSelected.vi means that this is the only vi that I am required to override. This is the VI where all of the logic for my selection type is to be performed. It is called every time a user clicks on a menu item. For my selection type, I don’t need to do anything for the InitSelection.vi, so I won’t override it. See a note at the end for more info about InitSelection.vi.

Click OK and LabVIEW will script the creation of a new VI for you, with the proper inputs and outputs.

The two most important Inputs here are MenuItem in and Siblings. MenuItem in is the current menu item that has been clicked by the user. It is being passed here by value and the value on Menu Item out will be written to the MenuItem reference. Next there are the Siblings. These are passed by reference. Siblings are menu items on the same level of the menu.  In our example, File has no siblings, while Selection 1, Selection 2, Item 1, Item 2, Item 3, Item 4, and Exit are all siblings of each other. This siblings array will not contain the menu item its self. Remember, we already have that from the MenuItem in control.

Based on our pseudo code from above, we want to first, toggle the checked state of the menu item that has been clicked. Use the “Checked” property to get the current checked status.  Next will iterate through the array of siblings and check to see if the sibling’s tag appears in the Tag List. If it does, we need to gray or un-gray the item. To gray and un-gray, you’ll need to set the “Enabled” Property of the MenuItem. After all the enabling/disabling is complete, you’ll need to set the new checked state of menu item. Again, make sure to use the Menuitem’s Set Enabled method. All in all, the VI comes out below.

Whenever you change the “Enable” or “Checked” properties, a  message will user event will be generated on the MenuItemStatusChange event. This will only be broadcast if the property actually changes (for example, if Checked is true, and you wire a true to property node, no Event is generated). The reason I set the “Enabled” of the siblings before I set the “Checked” of the MenuItem is that the messages will be generated in this order. I want the UI to know about them in that order because I think I’ll want to take the appropriate action in that order. I think it’s a bit less important in this example, but the Radio Selection type illustrates this a bit nicer. The Radio Selection type unchecks all siblings before it checks the clicked item. So if our radio buttons are actually controlling a group of plugins. Lets say we want to ensure that none of the plugins are running at the same time. We’ll want to turn off the previously active plugins before we turn on the clicked plugin. So our unchecked status event will be generated before the checked status event message.

I think I’m getting side tracked though…

So lets do a quick test. Here’s how our MenuItems are setup:

  

Looking pretty good to me, and it only took 1 class with 2 methods.