Can't get a field to Select Contents Properly

I have a wx.Panel class with a number of data entry fields that have a tab order assigned at the end of the init method:

    # set tab order
    self.taborder = (self.idField, self.dateField, self.runFromField, self.runToField,self.recoveredField,
                self.lithologyField, self.alterationField, self.strengthField,
                self.fracturesField, self.jcrField, self.solidField, self.rubbleField,
                self.gougeField, self.rqdField, self.runCommentField, self.featuregrid)
    **for** i **in** xrange(len(self.taborder)-1):
        self.taborder[i+1].MoveAfterInTabOrder(self.taborder[i])

That portion works as advertised.

However, two of the fields are dependent on the values of one or two others – if the value equals some given number, then the other fields are zero’d out and the cursor jumps to the “rqd” field:

**def** ZeroFaultFields(self, event):
    """Zeros out the rubble and gouge fields if the solid field equals the total recovery"""
    recovered = float(self.recoveredField.GetValue())
    solid = float(self.solidField.GetValue())
    rubble = float(self.rubbleField.GetValue())
    gouge = float(self.gougeField.GetValue())
    **if** solid == recovered:
        self.rubbleField.SetValue("0.0")
        self.gougeField.SetValue("0.0")
        self.rqdField.SetFocus()
        self.rqdField.SelectAll()
        self.taborder[13].MoveAfterInTabOrder(self.taborder[10])
    **elif** solid + rubble == recovered:
        self.gougeField.SetValue("0.0")
        self.rqdField.SetFocus()
        self.rqdField.SetSelection(0,3)
    **elif** solid and rubble:
        gouge = recovered - (solid + rubble)
        **if** gouge > 0:
            self.gougeField.SetValue(str(gouge))

As you can see, I’ve tried several commands to have the contents of the rqd field (initialized to ‘0.0’) be selected:
self.rqdField.SetFocus()
self.rqdField.SelectAll()
self.rqdField.SetSelection(0,3)
self.taborder[13].MoveAfterInTabOrder(self.taborder[10])
I also tried self.rqdField.SetSelection(-1,-1)

I’ve tried them individually and in combination, as shown above. None of them have any effect. The cursor will jump to the proper field, but the selection remains with the next field in the initial tab order, until the user manually selects the rqd field. This leads to data entry errors, since the “0.0” string ends up in front of any number entered unless the user is paying more attention to the screen than her keypad. And it’s disconcerting to see the selection and the cursor in different fields.

How do I set the selection to the chosen field?

Hi,

I usually just create the widgets in their specific tab order. I think this is more straight-forward than using a loop. As for your question, SetFocus has always worked for me. Perhaps you could create a small runnable example that demonstrates the issue? You might be able to use the Widget Inspection Tool to figure out what’s going on as well.

  • Mike

Use wx.CallAfter to call the SetSelection the next time the event queue becomes empty. On some platforms the SetFocus doesn't actually happen immediately and so when it does it will reset the selection to whatever is normal for the platform, undoing your SetSelection that you had done before. Delaying your call to SetSelection until after the native focus change has happened should take care of it for you.

Also, if you have your own EVT_SET_FOCUS or EVT_KILL_FOCUS event handlers be sure to call event.Skip so the native code can still be run for those events.

Finally, you may want to look at using Validators with your fields. They can help you simplify your validation of entered data. There are some examples in the demo and in the book.

···

On 11/23/12 7:10 PM, llanitedave wrote:

As you can see, I've tried several commands to have the contents of the
rqd field (initialized to '0.0') be selected:
             self.rqdField.SetFocus()
             self.rqdField.SelectAll()
             self.rqdField.SetSelection(0,3)
             self.taborder[13].MoveAfterInTabOrder(self.taborder[10])
I also tried self.rqdField.SetSelection(-1,-1)

--
Robin Dunn
Software Craftsman

Great ideas, Robin. I had just implemented Mike’s suggestion and put together a minimal app that illustrated the behavior I was mentioning, now I’ll be able to use it to test the fixes. The Widget Inspection tool wasn’t much help, maybe more due to my lack of skill at interpreting it as anything. I do have simple validators in the production code, but I had removed them for the sample.

I’ feeling a lot more optimistic now! Thanks!

Dave

···

On Monday, November 26, 2012 12:43:08 PM UTC-8, Robin Dunn wrote:

On 11/23/12 7:10 PM, llanitedave wrote:

As you can see, I’ve tried several commands to have the contents of the

rqd field (initialized to ‘0.0’) be selected:

         self.rqdField.SetFocus()
         self.rqdField.SelectAll()
         self.rqdField.SetSelection(0,3)
         self.taborder[13].MoveAfterInTabOrder(self.taborder[10])

I also tried self.rqdField.SetSelection(-1,-1)

Use wx.CallAfter to call the SetSelection the next time the event queue
becomes empty. On some platforms the SetFocus doesn’t actually happen
immediately and so when it does it will reset the selection to whatever
is normal for the platform, undoing your SetSelection that you had done
before. Delaying your call to SetSelection until after the native focus
change has happened should take care of it for you.

Also, if you have your own EVT_SET_FOCUS or EVT_KILL_FOCUS event
handlers be sure to call event.Skip so the native code can still be run
for those events.

Finally, you may want to look at using Validators with your fields.
They can help you simplify your validation of entered data. There are
some examples in the demo and in the book.


Robin Dunn

Software Craftsman

http://wxPython.org

Well, I must be doing something wrong, or maybe I just need a little more hand-holding. The code does work on Windows 7 without modification, and that’s where the app is designed to be used, so I shouldn’t complain, but on my Xubuntu it behaves as I described in the OP. Adding wx.CallAfter() merely invoked a Type Error: ‘NoneType’ object is not callable.

I’ve attached the minimal app that’s giving me fits. I only put the wx.CallAfter() in one of the branches, I left the others without it to show that it still doesn’t select the field properly either way.

wxSetSelectionTest.py (7.28 KB)

···

On Monday, November 26, 2012 12:43:08 PM UTC-8, Robin Dunn wrote:

On 11/23/12 7:10 PM, llanitedave wrote:

As you can see, I’ve tried several commands to have the contents of the

rqd field (initialized to ‘0.0’) be selected:

         self.rqdField.SetFocus()
         self.rqdField.SelectAll()
         self.rqdField.SetSelection(0,3)
         self.taborder[13].MoveAfterInTabOrder(self.taborder[10])

I also tried self.rqdField.SetSelection(-1,-1)

Use wx.CallAfter to call the SetSelection the next time the event queue
becomes empty. On some platforms the SetFocus doesn’t actually happen
immediately and so when it does it will reset the selection to whatever
is normal for the platform, undoing your SetSelection that you had done
before. Delaying your call to SetSelection until after the native focus
change has happened should take care of it for you.

Also, if you have your own EVT_SET_FOCUS or EVT_KILL_FOCUS event
handlers be sure to call event.Skip so the native code can still be run
for those events.

Finally, you may want to look at using Validators with your fields.
They can help you simplify your validation of entered data. There are
some examples in the demo and in the book.


Robin Dunn

Software Craftsman

http://wxPython.org

wx.CallAfter(self.rqdField.SetSelection(-1,-1))

The error is because you are calling SetSelection and passing its return value (None) to CallAfter. Instead you should pass the SetSelection method itself and its parameters to CallAfter so it can call it later. Like this:

             wx.CallAfter(self.rqdField.SetSelection, -1,-1)

···

On 11/28/12 6:00 PM, llanitedave wrote:

Well, I must be doing something wrong, or maybe I just need a little
more hand-holding. The code does work on Windows 7 without
modification, and that's where the app is designed to be used, so I
shouldn't complain, but on my Xubuntu it behaves as I described in the
OP. Adding wx.CallAfter() merely invoked a Type Error: 'NoneType'
object is not callable.

--
Robin Dunn
Software Craftsman

And the light comes on!

Thanks, Robin, for your patience. It’s working now, and I think I’m starting to understand the principle behind it.

Dave

···

On Friday, November 30, 2012 10:33:49 AM UTC-8, Robin Dunn wrote:

On 11/28/12 6:00 PM, llanitedave wrote:

Well, I must be doing something wrong, or maybe I just need a little

more hand-holding. The code does work on Windows 7 without

modification, and that’s where the app is designed to be used, so I

shouldn’t complain, but on my Xubuntu it behaves as I described in the

OP. Adding wx.CallAfter() merely invoked a Type Error: ‘NoneType’

object is not callable.

         wx.CallAfter(self.rqdField.SetSelection(-1,-1))

The error is because you are calling SetSelection and passing its return
value (None) to CallAfter. Instead you should pass the SetSelection
method itself and its parameters to CallAfter so it can call it later.
Like this:

         wx.CallAfter(self.rqdField.SetSelection, -1,-1)


Robin Dunn

Software Craftsman

http://wxPython.org