Formatted Text Field Input

For my project, each tank has several different levels represented by a string with three integers separated by dashes. The first number (feet) can be any integer greater than or equal to 0. The second (inches) can be any number between 0 and 11. The third (16ths of an inch) can be any number between 0 and 15. (Example: 346-10-3)

On the tank configuration screen, the tank level boxes allow the user to

I have three questions:

  1. What is the correct regular expression for the tank level? How can it accept an infinite number of feet?

  2. How can I check against input errors such as entering 13 inches?

  3. How can change the committed value to a string before sending it to the database? The “toString” method doesn’t seem to work.

Thank you again!

Edit: I was able to change the committed value to a string in the update query by using single quotation marks (i. e. ‘{this}’). I didn’t see this in the documentaion.

Hello,

First of all, what are you wanting the regular expression to do, and where are you trying to use it? I assume that you’re using it in a regular expression-formatted text box. While you could do this, if I were you, I would present the data to the user as three separate numeric spinners for display and editing. This way, you can set the spinners min/max values to do the input error checking for you. To do this, you need to do 2 things:

  1. Break the string (xxx-yyy-zzz) apart into the three pieces, and bind the spinner values to the three pieces

  2. Combine the spinner values back together again to write to the database.

There are many ways to approach this with various combinations of binding and scripting. Here is a suggestion:

Part 1
Bring the value from the database into a dynamic string property. Lets say its a property on the Root Container called TankLevel.

You would bind your 3 spinners’ Integer Value property to expressions like this
for feet:

toInt(split({Root Container.TankLevel},"-")[0,0])

for inches:

toInt(split({Root Container.TankLevel},"-")[1,0])

for sixteenths:

toInt(split({Root Container.TankLevel},"-")[2,0])

Part 2
Now we need to combine the values back together, and write the combined value back to the database when the user changes any of the parts.

Create another dynamic property, lets call it UserLevel. Bind in to an expression like this:

{Root Container.TankFeet.intValue} + "-" + {Root Container.TankInches.intValue} + "-" + {Root Container.TankSixteenths.intValue}

Now write a propertyChange script on the component that has this string variable on it (in this example, the root container) that looks something like this:

if event.propertyName == 'UserLevel': fpmi.db.runUpdateQuery("UPDATE MyTable SET TankLevel='%s' WHERE ...(something?)..." % event.newValue)

Ok, that might be a lot to absorb, but let me know if anything is confusing you.

Again, you can use a regular expression formatted text box, I just think this will be nicer for your users. Also - the putting the quotes around the value thing is part of the SQL language, not really part of FactoryPMI, which is why it might be absent from our user manual. You always need to quote string values in SQL.

Hope this helps,

This may not be the best case for a regular expression since they match patterns and don’t understand numbers, but here goes:

The regular expression would be: ^([\d]*)-([0-9]|1[0-1])-([0-9]|1[0-5])$

Make sure you don’t have any spaces before or after the string.

the carat and dollar sign represent the start and end of the string, specifying an exact match as opposed to substrings.

[\d] means any single digit, same as [0-9], the * allows repetition

b[/b] means 0 through 9 or 1 + 0 through 5, 10-15

The data property of a formatted text field is already be a string and not need to be cast. This regular expression will allow the user to type in whatever number they want at the beginning and constrain the next 2 as specified.

Just to clarify Nathan’s post, you’d probably want to use a + (plus) rather than a * (asterisk), which specifies one or more, rather than zero or more characters.

I asked my supervisor about using spinners. He pointed out that since operators will set these levels only a few times for each tank, using text fields would be best. (I’d prefer to using spinners; it seems a bit easier to implement. However, the users come first, right? :slight_smile:)

Anyhow, I figured out how to check the text input when focus is lost in the formatted text field.

However, I get an error every now and then when binding the maximum level (shell height) to dynamic variables. I used the following expressions for the shell height’s feet, inches, and sixteenths of an inch:

toInt(split({Root Container.Shell Height.text},"-")[0,0])
toInt(split({Root Container.Shell Height.text},"-")[1,0])
toInt(split({Root Container.Shell Height.text},"-")[2,0])

The shell height string is “2-11-7”.

The feet variable is all right, but I get an out of range error for inches and sixteenths of an inch.

Thanks again!

I wouldn’t use the formatted text field. If you use a numeric text field then you can set the input range (min and max values as component properties). A spinner is a text field with up and down arrows - it also supports this feature. You shouldn’t need to worry about using Jython to validate input in this case.

Could you post more detail about the out of range error?

Nathan, I took your advice and used numeric text fields instead. My supervisor thinks this will be all right, and it’s much easier to do error checking this way. Thank you!

As for the out of range error: I think I may have split the word incorrectly. In any case, I’m not getting that error anymore.