I have a flex repeater that contains instances of a view that displays a certain type of entry field depending on some JSON that it's reading. For instance, if an object has Item["Input"] == "Number", then a NumericEntryField is displayed. If Item["Input"] == "Text", then a TextField is displayed.
I have a property change script on the value property of each kind of input component:
if (currentValue > 0) and (len(str(currentValue)) > 0):
if self.view.params.Index == self.view.params.dataLength:
newIndex = 0
else:
newIndex = self.view.params.Index + 1
system.perspective.sendMessage("InputElementFocus", {"index": newIndex})
self.view.params.MeasuredValue = self.props.value
self.props.style.backgroundColor = "#555555"
This change script sends a message to the parent Flex Repeater which tells it to focus on the next instance. This works for all components (TextField, Dropdown) except for the NumericEntryField. Here's the message handler that I have on the parent view:
When the focus is set to an instance with a NumericEntryField, the NumericEntryField is focused on for a fraction of a second. The spinner displays, and then goes away. After this, there is no longer focus on any of the elements. The user has to click on the NumericEntryField before entering data.
Here's how the components / views are arranged in the Project Browser:
The issue happens when self.getSibling("NumericEntryField").focus() is being called while the focus is on a TextField component. My issue, specifically, is when the focus is set by a message handler that's called by a property change script on the TextField's "text" property. I had a call with Joshua following his post above and we weren't able to get it working. Here's a gif of the issue - you can see that the property change script works when focusing from the NumericEntryField to the TextField, but not vise-versa.
The Text Field piece is the key. The Message Handler route works as expected from other components, but something about the way the Text Field handles a commit of the value causes the issue. I'll open a new ticket to get it looked at.
As a workaround, introducing any sort of sleep before trying to apply focus to the Numeric Entry Field results in it working as expected.
def valueChanged(self, previousValue, currentValue, origin, missedEvents):
from time import sleep
sleep(.25)
self.getSibling("NumericEntryField").focus()
Nick, did you use a change script on both input boxes?
I just setup a numeric box and text box, placed a change script to set the focus on the other box, and after I type in one box, click outside, the focus moves to the other. This works both ways without a message handler.
Clicking outside of a field didn't always result in the issue being seen. Pressing Enter resulted in the issue 100% of the time. Even Tab was hit-and-miss depending on if the Numeric Entry Field was before or after the Text Field.
Yes, I have a change script on both boxes. The end-user of my application is given a repeater of input field instances - some of which are Numeric Entry Fields, and some of which are TextFields. These each have their own index, and are supposed to receive focus via a message handler when the value change script runs upon the "Enter" key press. I wanted to avoid them having to using a mouse to change focus, and was requested to make this work without the end-user having to press the Tab key.
Sleeping is necessary in some corner cases, but writing "perfect" for that import implies it is widely applicable. In many places in Ignition, it is like a hand grenade. (All kinds of related discussions on this forum.)
When somebody states that they are going to optimize some code, there can be some ambiguity in what they actually mean. Are they optimizing for performance? ...for memory usage? ...for power consumption?
...but that said: you can take for granted that they aren't talking about implementing sleep.