Validating Data Input

Last week we covered the basics of creating a dialog box that doesn’t block the execution of the application that called it. This time I want to expand on that discussion to look at dialog boxes that allow the user to enter data – which in turn brings up the topic of data validation.

What We’ll Build

To demonstrate the various ideas that I want to cover, I have created a dialog box that shows some typical situations. As you can see from this screen shot of the front panel we will look at two ways of validating numeric data, as well as a couple more techniques for dealing with strings.

Number and String Validation FP

Remember, the one thing that is foundational to this discussion is the concept that the Ok button doesn’t get enabled until all the data is valid.

Building the Infrastructure

As you can see from the screen shot below, the basic infrastructure for determining when to enable the Ok consists of a cluster containing one Boolean value (I call them validation flags) for each item that needs to be validated, and for which the user could make an invalid entry. The second part of that definition is important because it’s perfectly feasible for there to be parameters that have no invalid values. Moreover, a couple of the techniques I will show you can actually prevent the user from entering incorrect data so they don’t require explicit validation.

Validation Flag Cluster

Note also that I always use a cluster to store these validation flags because, in a cluster, you can give each value a meaningful name. Consequently, the validation cluster in our example contains two flags named, “Numeric 1” and “String 1”. The other two values will be the ones where the user won’t be able to enter incorrect data.

The key idea behind this cluster of validation tags is that each value needing validation has its own flag. Consequently, the various tests can’t interfere with each other. All you have to do is wait until all the flags show that their associated values are good and you can enable the Ok button. To be consistent with the error logic that LabVIEW uses, a true value indicates a parameter that is in error, while a false indicates no error. To determine the enabled state of the button I created a polymorphic VI that accepts either a single Boolean or an array of Booleans, and outputs the enumeration that the Disabled control property expects. Any true input results in a Disabled and Grayed Out output value.

Getting Down to Specifics

To see how all this fit together, we’ll start with the two values where users can enter incorrect values.

Validating Numeric 1

We’ll start with this input because it is the easiest case. The technique is basically to take the NewVal value from the event data and compare it to the constraints to which it has to conform. In this case, upper and lower limits.

Numeric 1 Validation

If the new data, is not in the desired range, the code writes a true to the input’s validation flag. If there is in range, it writes a false. Once the flag is updated, the cluster is converted to an array and the result drives the polymorphic VI I discussed earlier to determine the Ok button’s new state.

Validating Numeric 2

This input is the first of the “no error possible” solutions but is, frankly not the way I prefer to deal with simple limits — and you’ll see why in a few moments. Note that in this example, the code implementing this method actually exits outside the event loop in the form of two property nodes.

Numeric 2 - no error

The first of these nodes define the control’s behavior if an out-of-range value is entered. To ban invalid data, we want the control to coerce the value to the closest valid number. The second node defines what the high and low limits are. The API for this functionality also allows you to control the minimum amount a value can change. For example, you could define an input that is settable between 1 and 10 in increments of 0.1.

But why isn’t this one of my preferred techniques? This method can ensure that the input is technically valid, but it can’t guarantee that it is what the user wanted. If this field is one of many on the screen, it is too easy for the user to miss it and fail to enter the number that they want. The result is a value that is valid, but nevertheless incorrect. Allowing the presence of invalid data on the screen forces the user to correct the field’s contents.

The best place to use this approach is with data fields where the default value is correct 90% or more of the time. Also, the ranges can also be set at any time — not just during initialization.

Validating String 1

This field is the other one that needs to be programmatically validated, and as you can see it’s not very different from the Numeric 1 example. The test for this string is that it can’t be empty and it can’t be more than 15 characters long.

String 1 Validation

But even this simple pair of constraints can provide us with some food for thought. For example, you can and should tell your users what the expected criteria are for each input. However, telling a user that the string can’t be more than 15 characters long isn’t going to as helpful as you might think it would be. The problem is that most people can’t look at a string that long and tell how many characters are in it. They have to count the letters — which is a pain.

A better approach is to simply manipulate the input such that it will only accept 15 characters. Now I’m not going to show how to do that. Instead I will leave that (as they say in fancy college textbooks) as an exercise for the reader. But to get “the reader” off on the right foot, let’s look at what I’m doing with the other string input.

Validating String 2

For this example I am drawing on an experience where a customer wanted a numeric input that was blank until the operator typed a number into it. The problem, of course, is that numeric inputs always have a number in them. The solution is to create a string control that operates like a numeric input. And to accomplish that, we need to look at each keystroke as the operator is making it and only allow those keys that are valid. The alchemy that allows such magic is the Key Down? filter event.

But you also need to know a bit about how a PC keyboard works. Some of the keys have ASCII values associated with them, like 0x35 for the character “5” or 0x2E for the period. LabVIEW returns the ASCII value of keys in the Char ;event data node. However, some keystrokes return an ASCII code of 0. These are control keys that do things and don’t represent printable characters. Here I’m talking about things like the delete or arrow keys. When you see an ASCII value of 0, the VKey event data value, which is an enumeration, will tell you what key was pressed.

Our event handler will need to manage both. So let’s first consider the ASCII codes we need to handle. Clearly, the 10 digits will need to be accepted (0x30 through 0x39) so when any of those values are returned we will set the Discard? node to false.

ASCI Digit Enables

Likewise if we are to accept floating point numbers we need to be able to type a period as well — but we can only have one so we need a tiny bit more logic.

ASCI Period Enable

So we’re done right? Not really, no. To begin with, you’ll notice that there are two other ASCII codes in the same case as the numeric digits: tab and backspace. They are there because while your users are entering information, they still need to be able to navigate the screen, so these two codes are also needed — and several more besides that fall in the area of control keys. Check out the code in the repository…

Summing up…

So that’s all I have for now. I do however want to point out that the last technique I showed you is very powerful and I have used it many time to “synthesize” custom inputs that don’t natively exist in LabVIEW, like an IP address entry field. The modified code is in SVN at:

http://svn.notatamelion.com/blogProject/testbed application/Tags/Release 5

and

http://svn.notatamelion.com/blogProject/toolbox/Tags/Release 2

Check it out and if you have any questions, post ’em.

Until next time…

Mike…

Adding a Non-Blocking Dialog Box

Key to using event structures effectively is to keep things moving. This maxim applies with any sort of event-driven structure — even (especially!) XControls. So if you don’t want to ever stop an event loop, you can see how you are going to have problems with dialog boxes. However, the last time we were together I alluded to approaches that provide the functionality of dialog boxes, but without the execution blocking that normally occurs. This post will start the discussion of how to implement this functionality by creating a simple “Are you sure?” -type dialog; in a later post we will expand on this idea to include dialog boxes that support the entering of setup or configuration data.

The Basics

The first idea you need to get your head wrapped around is that a dialog box is just another LabVIEW program, not unlike any other program you write. The only significant difference is that when this program runs, it looks like a dialog box. So what makes a good “dialog box” program? In addition to the usual traits of a good program, there are a few that are unique — or at least have a special significance for dialog boxes:

Uncomplicated

No program should be inherently complicated, but with a dialog box this point is particularly important. Your users should be able to look at the dialog and easily determine what information the system expects and/or wants from them. To aide your users in making that determination, don’t be afraid to state on the front panel exactly what you expect from them, but no bloviating: keep it pithy. If you feel there are aspects of the operation that need long-form explanations, considering having a pop-up help screen that provides all the gory details.

You might, however, also consider whether the task at hand is too large for a dialog box. You don’t want to try to do too much in a single dialog box — or at least on a single dialog box screen. A very effective technique for dealing with complexity can be to create a “wizard” interface, where the user is logically stepped through a large task. Just be careful how many screens you give the wizard, more than 3 or 4 and the user can lose track of where they are in process.

Finally, I have seen applications where the program’s basic user interface was one (very large) dialog box. While I understand that the goal of such a misguided effort is often to prevent the user from gaining access computer desktop, this sort of structure is very bad form. To begin with, the goal itself is problematic in that it complicates working with the code, but more importantly it never really works very well anyway.

Instills Confidence

One of the things that many people don’t think about is that sometimes the very presence of a dialog box can cause uncertainty — like what happens if I inadvertently select the wrong thing and a dialog box I wasn’t expecting opens. I might press the wrong button, and then what?

There are a couple of ways of preventing this sort of stress. First, given that the dialog is really needed (sometimes a static configuration setting is just as good — or even better!) write the code such that nothing changes in the application’s state until the “OK” button is pressed. I know, this sounds like a small, common-sense thing, but users can get worried if they see things starting to change in anticipation of a button selection that they haven’t yet made. However, it can complicate life for the developer as well. What happens if the user doesn’t click “OK” but “Cancel” instead? Now you have to change everything back to the way it was — assuming of course that it is possible to get the system back to where it was before. I have seen troubles caused when an external input change caused the device under test (DUT) to change it’s internal state in a way that couldn’t be easily reversed.

The second way of instilling confidence is to have a robust “Cancel” button. By that I mean that pressing “Cancel” should undo any modifications that are pending so no change is made in the application’s state. “But,” you might ask, “what about applications where changes have to be made along the way?” That is a valid point. I have written dialog boxes that served as an interface for editing system setups that, for various reasons, had to be saved as the user went along. The correct solution in those cases is not to have a “Cancel” button. Instead have one labelled, “Done”. The logical implication now goes from, “I am abandoning all my changes” to, “I am finished making changes”.

Before we move on, consider that this point brings up a larger issue: Always make sure the buttons are labelled for what they do. In many cases, buttons relate to verbs, things you want to do. However, in others, they may answer a question, like, “Are you sure you want to quit?” In that situation, Buttons labelled “Yes” and “No” are appropriate, “OK” and “Cancel” are not.

Provides Validated Output

A common use of dialog boxes is to enter configuration data. However, this sort of usage means that it is possible for the user to enter something that is incorrect. There are a number of ways to address this issue, many of which are just good user interface design; but some do involve the logic of the dialog box itself. For example, you should always design data-entry dialog boxes such that they don’t let the user click the “OK” button until all the data they have input has been validated.

Sometimes this validation procedure is simple, other times it will be complex with many interactions between various input values. Regardless of how simple or complex, this validation is worth the effort because working proactively to prevent an error is always easier than dealing with the error after the fact.

Our First Dialog

So with these points in mind, let’s get back to the issue that we ended with last time: How can we verify the user’s desire to shut down the application without blocking the execution of the code?

Well, the first thing we need to do is make a decision. To wit: Should the dialog box be a reusable VI that could be used anywhere a two-button dialog box is needed? Or should it be a custom design that is only used in this specific place in the code? To tell the truth, there are good arguments to be made on both sides. One line of reasoning says that using a common dialog simplifies the process of creating a professional, standardized interface. Plus, the code is reusable. The other school of thought asserts that quitting the application is a major operation and that, while you want the verification dialog to be of a similar style, you do want it to be different enough to reduce the likelihood that the user will inadvertently hit the wrong button and quit the application.

I typically prefer the second approach, so that is the one that we will take – to start with, at least. Here is the block diagram of the dialog box VI itself.

Simple 'are your sure' Block Diagram

You’ll first note that the diagram is missing one thing that you typically see wrapped around an event structure: a While loop. If you think about it, however, this omission makes sense. When you get right down to it, the whole purpose of this code is to determine whether to fire the Stop Application UDE to shut down the application, or bypass the event and let execution continue. For this reason the VI’s front panel only has two buttons (one for each potential outcome) and clicking either one will stop the execution of the VI and close its front panel. The event handler shown deals with the case where the user affirms their choice to quit, it contains the event generator for the Stop Application UDE. A second event handler (which is empty) is for bypassing the shutdown.

However, before the event structure is reached, the code first registers to receive the Stop Application event. The justification for this added code is that there is actually a third situation that the VI needs to handle. What if while this dialog box is open, Windows starts to shut down? Many devices like uninterruptible power supplies have the ability to shut down Windows automatically when needed. You don’t want the shutdown process to hang-up while the user contemplates the dialog box. By registering to receive the Stop Application event, the application will shutdown even if the dialog is open. The event handler for the UDE is empty like the one for the “No” button.

The front panel for the dialog box is as uncomplicated as the block diagram:

Simple 'are your sure' Front panel

The only non-visible settings are in the VI Properties where I used the predefined Dialog setting for the VI appearance, and used the Run-time Position properties to center the VI’s front panel in the primary monitor.

Launching the Dialog

Now that we have a dialog box that will happily run as a separate process, we need a way to get the VI loaded into memory and launched. There are two basic techniques, each with their own pros and cons. In a future post, we’ll compare and contrast the two options, but for now we’ll just use asynchronous call-and-forget, since it is very easy.

Simple Dialog Box Launcher

The code starts with a static reference to the dialog box VI. This reference node loads the VI into memory, but does not reserve it for execution. The subsequent property node uses the reference to get the VI’s name, and the name drives the Open VI Reference node. The input to which the name is attached normally expects a complete path to the VI but if the VI is already in memory, the name is all that it needs — and the static reference holds the VI in memory. The 0x80 option input value tells LabVIEW that the asynchronous run will be using the call-and-forget method so it doesn’t have to wait for execution to finish before going on. Finally, the Start Asynchronous Call starts the dialog box running. One last screen shot shows the display process modified to use the non-blocking dialog box. You will note that I also modified the logic for handling the Stop button event in the same manner.

Fixed Panel Close Event

When you run this version of the code, you’ll notice that when the dialog box opens, the display continues updating. The modified project is available at:

http://svn.notatamelion.com/blogProject/testbed application/Tags/Release 4

That’s enough for now. When we again get together, I’ll expand on this basic dialog box structure to show how to qualify input in a more complex dialog.

Until next time…

Mike…