Erratic behavior setting focus in perspective

I have a perspective app where I am setting focus on objects using sendMessage. I have also tried directly setting focus(). I get the same results using both methods. Sometimes it works, sometimes it doesn’t. I have used logging to see that the message is sent and also that the message is processed at the new object but focus just seems to go into the ether. I don’t see it on any object. I have been researching way to create a delay but invokeLater can’t be used in perspective and invokeAsynchronous doesn’t work since the message doesn’t seem to be able the message instruction (error: no perspective session attached to this thread). Is this something that is being addressed or is there already a standard practice to make this reliable.

Could we see the code you’re using to send the message, as well as the code you’re using to set the focus for a component. What component are you setting focus on?

First let me give an example of what I am setting focus on. The project has several entry fields and I wanted to keep them all looking the same so I created a view with a label and a text field which I can use as a template. In the main view, I have embedded views with the path set to the labeled text field template view. I created a parameter of setFocus on the template view and the embedded view. (it is a bidirectional parameter on the template)
The message handler is on the embedded view. When triggered, it sets its setFocus parameter true. There is a change script on the setFocus parameter on the template so that when it becomes true it sets focus on the text field and then sets itself to false.
On the ACCEPT button I have this code:

myds.Log('Sending focus to SN from ACCEPT')
system.perspective.sendMessage("Reset",{'level':1},'session')	
system.perspective.sendMessage('newFocus',{'who':'SN'},'session')

Notes, 1. I am logging when the message is sent and always get the log entry.
2. the ‘reset’ message works in a similar fashion and always clears the session prop bound to the field but if the focus works the text generally remains in the box with the cursor at the end. (which is why I am asking for a way to delay the focus message) 3. I have tried setting the scope to session / page / view with no change in behavior

At the embedded view I have:

who = payload['who']
if who == 'SN':
    myds.Log('Sending focus to SN from ACCEPT')
    self.props.params.setFocus = True

On the template view’s setFocus parameter’s change script I have

if currentValue.value == True:
    myds.Log('setting focus in template')
    self.getChild("root").getChild("TextField").focus()
    self.params.setFocus = False

I believe I am always getting all three messages but now that I am trying to verify it is not being erratic at the moment. This behavior seems to change by location. It seems to be worse when I am working remotely or when the client is on a slow wifi connection. I have seen other erratic behavior in that case. In particular when I have a session prop with bidirectional binding to an embedded view parameter which also has a bidirectional (input/ output) tie to the view parameter. If I change the value of a dropdown for instance it will change momentarily and then sometimes change back, requiring several tries for the change to ‘stick.’ It appears that time stamps are not used to ensure the change propagates properly down the line in one direction and the two ends fight each other.

Another note on the text in the field remaining even though the associated prop is an empty string. If you take focus back away from the field to anyplace else, the text disappears.

What is your goal in setting focus on the Text Field(s). As you're attempting to set focus in MULTIPLE places but can only ever have focus in one place, AND there is no guarantee as to the order your Embedded Views will receive the Message, this is inherently unstable.

This is how the rejectUpdatesWhileFocused property of Text Fields is supposed to behave. If you don't want to prevent changes while you have focus, toggle this property to false. This is ALSO why when you remove focus while the field has text that has been changed behind-the-scenes the text disappears.

Everything you've discussed seems to be working as intended, and this seems like it might be an issue with how the logic is applied to the components.

You could try including a sleep in the script after sending the reset, but before sending the focus message OR you could sleep after receiving the message, but before applying the focus.

I’m not sure I communicated properly. I am not trying to set focus on multiple objects at the same time. I was trying to indicate that I use this in multiple instances. I send the focus message with a payload and only the embedded view that matches that payload will act to set focus on itself. In no case to I expect more than one object to act on the message and my logging does not indicate this ever occurs.
I was under the impression that you never put a sleep directly into the perspective scripts as these all happen on the gui thread. I just tried that and it did change the behavior. Now the session prop isn’t even being cleared which is causing bigger problems. This is why I have asked about the asynchronous options.
The rejectUpdatesWhileFocused suggestion did solve the issue with text remaining but I don’t think that will prevent the behavior form changing again when I change locations to a slower or faster wifi connection. I will post again if it continues. Thank you for your assistance.

You could also modify the Reset message to

system.perspective.sendMessage("Reset",{'level':1, 'who': 'SN'},'session')	

then remove the newFocus message entirely.

Have the EmbeddedView listen for the Reset message, wait one second, and then set focus:

from time import sleep

who = payload['who']
if who == 'SN':
    sleep(1)
    myds.Log('Sending focus to SN from ACCEPT')
    self.props.params.setFocus = True

This will leave your other implementation/usage of this Reset message unaffected, while removing the need for a second message/handler implementation, and while still delaying based off of the original “broadcast”.

1 Like

I hadn’t considered combining the messages as they do different things and generally come from different objects, just not in the example I provided. Every entry object listens for the reset and acts according to level. 4 is for the app opening, 3 for the business unit being changed, 2 is for the shipment being finalized or closed and 1 is for a shipment item being added or canceled to prepare for the next item. The focus is only needed in an object if it is the next entry expected. In my example, the code came from the cancel button which clears all the item specific fields and sends focus to the serial number field as it is the first bar code scanned for an item. I can try combining messages but I think it will make things less clear for the next person.
As for the second suggestion I think this is providing a code example of your previous suggestion which I already tried. As stated, this made things worse as it pauses the entire thread, not just this script so it does not provide time for the operation to complete like we think it would. I’ve been trying to find where I read this so that I can link to it for you but now I can’t. In any event, your code example is almost exactly what I tried and the results where as I stated previously. I have been making little tweaks to the code and the last tried. It was all behaving itself. We will see.

1 Like