Recording the previously selected control

I have been programming with wxWidgets for a few years using C++, but have only just started using Python and wxPython.

I am trying to write a very simple barcode reader / stock-taking app that runs on a Raspberry Pi. I am using Python 2.7 and wxPython from the Raspbian ‘Stretch’ repository.

My app has a single frame with 4 wx.TextCtrl and 12 buttons arranged as a ‘number pad’. 1 of the wx.TextCtrl is read-only and the other 3 should have numbers entered by the user by pressing the buttons on the ‘number pad’ (using a mouse or touch panel).

My approach is to capture a wx.EVT_SET_FOCUS event in each of the wx.TextCtrl and I had planned to record its Python handle/label/pointer using event.GetWindow(). Then when a number button is pressed, I would append the corresponding number to the control using something like focusCtrl.AppendText('1').

However, I am still a bit confused about the Python handle / unmutable object / mutable list concept. In particular, how I can record the whatever_it_is that is returned from event.GetWindow()?

This is what I have tried:

# In def __init__
self.qtyField.Bind(wx.EVT_SET_FOCUS, self.OnFocus)

# Then ...

def OnFocus(self, event):

print (“Got a focus event”)

self.focusWindow = event.GetWindow()

event.Skip()

# And ...

def OnOne(self, event): # wxGlade: MyFrame.<event_handler>

self.focusWindow.AppendText(‘1’)

event.Skip()

``

However, self.focusWindow only gets local scope (I think), so the self.focusWindow in OnOne is not the same as in OnFocus. If I want to create an object with class scope (i.e. focusWindow = wx.TextCtrl()), then it actually instantiates an extra control (as is reasonably expected).

I realise that these are basic Python questions, but I thought to ask here because of the wxPython context.

Separately, but related, I am using wxGlade to create the frame. wxGlade only has some of the events available to a control, specifically the hierarchical wx.Window events are not included. What is the best way to work with this - should I subclass the wxGlade created frame in my own file or edit the wxGlade generated “mainwindow.py”?

Finally, I miss the CodeLite working environment with code completion, debugging etc. I know this is a personal choice but any hints / tips on an IDE are much appreciated. I started with Idle, but now moved to Eric because it promised code completion - which I have failed to get working so far.

Thanks for any help!

Iwbnwif Yiw wrote:

My approach is to capture a wx.EVT_SET_FOCUS event in each of the wx.TextCtrl and I had planned to record its Python handle/label/pointer using event.GetWindow(). Then when a number button is pressed, I would append the corresponding number to the control using something like `focusCtrl.AppendText('1')`.

This approach is really over-complicated. All you need to do is to store the wx.TextCtrl as an attribute of your instance and reference it later.

self.aTextCtrl = wx.TextCtrl(...)

And then later, in an event handler for your keypad buttons:

self.aTextCtrl.AppendText(...)

Regards,

James Scholes
https://twitter.com/JamesScholes

Thank you for your help.

···

On Monday, September 25, 2017 at 4:13:05 PM UTC+1, James Scholes wrote:

This approach is really over-complicated. All you need to do is to
store the wx.TextCtrl as an attribute of your instance and reference it
later.

self.aTextCtrl = wx.TextCtrl(…)

Sorry, but I am still missing something. Won’t the above line create another instance of a wx.TextCtrl rather than something I can access an existing control through?

I have 3 controls, each of which needs to receive additional numbers when it has the focus.

±-------------+

TextCtrl1 |
±-------------+

TextCtrl2 |
±-------------+

TextCtrl3 |
±-------------+

If the user touches TextCtrl2 and then starts pressing number buttons, the .AppendText(number) should add a number to the middle wxTextCtrl.

If they then touch TextCtrl3, any further numbers should be appended to that control.

So how do I know which instance of wx.TextCtrl to call .AppendText on?

If you have any C# background, the object concept in Python is
closer to C# than it is to C++.
Here’s the way I think about it. You have objects, and you have
namespaces. The world of objects is just a big cloud of “things”
that have a type and a value, but they have no names.
Then, you have namespaces. The names in the namespaces refer to
“things’, but they don’t really have any content themselves. So,
when I say:
i = “abc”
j = i
k = j
I have created exactly one object in the big nameless cloud. It is
a string object with three characters. I happen to have three local
names that refer to that object. When I say:
k = 3
that releases one of the references, so there are only two
remaining. The “k” name now has a reference to the integer 3 object
in the big nameless cloud. If I happen to say:
i = 1
j = 2
then there are NO remaining references, although there is still a
string object in the nameless cloud. During the next garbage
collection cycle, it will notice that the “abc” literal string has
no references, and it will delete the object.
The names aren’t so important. What’s important is the objects. If
you have a button on your window, there is only one button object,
although you might have many names that refer to that object. So”
def init( … ):
self.okButton = wx.Button( self, “OK”, … )
self.okButton.Bind( wx.EVT_CLICK, self.onClick )
def onClick( self, evt ):
self.what = evt.GetWindow()
btn = evt.GetWindow()
There is only one wx.Button object in this example, but it is
referred to by many names. By the time I get through that onClick
handler, self.okButton, self.what, and the local variable “btn” all
refer to that same button object. Any actions I take through any of
those names affects the object, so the changes can be seen through
all of those names. In addition, the parent object also keeps a
reference, to make sure it isn’t deleted.
That’s not true. self.focusWindow is a member variable, just like
member variables in C++. All the events for this window will get
passed the same “self” object (just like “this” in C++), so
self.focusWindow will refer to whatever object tucked in there last.
James’s suggestion was to skip using the focusWindow hack, and
instead just refer to self.qtyField in your OnOne handler. If you
know which window fired the event, then just use your local
reference. He just happened to use a different variable name in his
description.

···

Iwbnwif Yiw wrote:

      However, I am still a bit confused about the Python handle

/ unmutable object / mutable list concept. In particular, how
I can record the whatever_it_is that is returned from
event.GetWindow()?

This is what I have tried:

In def init

                    self.qtyField.Bind(wx.EVT_SET_FOCUS, self.OnFocus)



                  # Then ...
                def OnFocus(self,

event):

                print ("Got a

focus event")

                self.focusWindow =

event.GetWindow()

event.Skip()

                    # And ...
                  def OnOne(self,

event): # wxGlade: MyFrame.<event_handler>

self.focusWindow.AppendText(‘1’)

event.Skip()

``

      However, self.focusWindow only gets local scope (I think), so

the self.focusWindow in OnOne is not the same as in OnFocus.

-- Tim Roberts, Providenza & Boekelheide, Inc.

timr@probo.com

This demo may be helpful:

https://github.com/PythonCHB/wxPythonDemos/blob/master/CalculatorDemo.py

Also, this discussion on the wiki:

https://wiki.wxpython.org/Passing%20Arguments%20to%20Callbacks?highlight=%28Lambda%29

Might be helpful.

-CHB

Here's the way I think about it.  You have objects, and you have

namespaces. The world of objects is just a big cloud of “things”
that have a type and a value, but they have no names.

Thanks, this description was very useful.

      However, self.focusWindow only gets local scope (I think), so

the self.focusWindow in OnOne is not the same as in OnFocus.

That's not true.  self.focusWindow is a member variable, just like

member variables in C++. All the events for this window will get
passed the same “self” object (just like “this” in C++), so
self.focusWindow will refer to whatever object tucked in there last.

Sorry, yes I have got this now. I was getting a “None does not have a AppendText() attribute” type error. In fact this was caused by event.GetWindow() returning None, if I replace it with event.GetEventObject(), then it works as I wanted.

James's suggestion was to skip using the focusWindow hack, and

instead just refer to self.qtyField in your OnOne handler. If you
know which window fired the event, then just use your local
reference. He just happened to use a different variable name in his
description.

The thing is the OnOne button event will always be fired by the button, it is the window focus event that will have one of the 3 TextCtrl as an object (could be qtyField, costField or sellField) - but in the OnOne event I need to remember which window previously had focus so I know which of the 3 controls I need to append text to.

So now, I can do exactly what I want to do with the following code:

def OnNumber(self, event):

if self.focusWindow is not None:

self.focusWindow.AppendText(event.GetEventObject().GetLabel())

event.Skip()

def OnClear(self, event):

if self.focusWindow is not None:

self.focusWindow.Clear()

event.Skip()

def OnFocus(self, event):

print (“Got a focus event”)

if event.GetEventObject() == self.nameField:

self.focusWindow = None

else:

self.focusWindow = event.GetEventObject()

event.Skip()

``

Edit: I should probably change if self.focusWindow is not None: to self.focusWindow is wx.TextCtrl.

···

On Monday, September 25, 2017 at 5:26:27 PM UTC+1, Tim Roberts wrote:

Thank you, yes it is! I was planning to do something like this because the wxGlade generated code was so cumbersome to work with.

···

On Monday, September 25, 2017 at 7:21:38 PM UTC+1, Chris Barker - NOAA Federal wrote:

This demo may be helpful:

https://github.com/PythonCHB/wxPythonDemos/blob/master/CalculatorDemo.py

Actually, I’d be inclined to use a list of valid focus objects, as I created them, such as:

focusableWindows = [self.xvalue,self.yvalue,self.zvalue]

Then later, you can say:

if event.GetEventObject() in focusableWindows:

	self.focusWindow = event.GetEventObject()

So you can always be pointing to a valid focus window, unless you really want to de-focus the pointer.

···

On Sep 25, 2017, at 3:30 PM, Iwbnwif Yiw iwbnwif@gmail.com wrote:

On Monday, September 25, 2017 at 5:26:27 PM UTC+1, Tim Roberts wrote:

Here's the way I think about it.  You have objects, and you have

namespaces. The world of objects is just a big cloud of “things”
that have a type and a value, but they have no names.

Thanks, this description was very useful.

      However, self.focusWindow only gets local scope (I think), so

the self.focusWindow in OnOne is not the same as in OnFocus.

That's not true.  self.focusWindow is a member variable, just like

member variables in C++. All the events for this window will get
passed the same “self” object (just like “this” in C++), so
self.focusWindow will refer to whatever object tucked in there last.

Sorry, yes I have got this now. I was getting a “None does not have a AppendText() attribute” type error. In fact this was caused by event.GetWindow() returning None, if I replace it with event.GetEventObject(), then it works as I wanted.

James's suggestion was to skip using the focusWindow hack, and

instead just refer to self.qtyField in your OnOne handler. If you
know which window fired the event, then just use your local
reference. He just happened to use a different variable name in his
description.

The thing is the OnOne button event will always be fired by the button, it is the window focus event that will have one of the 3 TextCtrl as an object (could be qtyField, costField or sellField) - but in the OnOne event I need to remember which window previously had focus so I know which of the 3 controls I need to append text to.

So now, I can do exactly what I want to do with the following code:

def OnNumber(self, event):

if self.focusWindow is not None:

self.focusWindow.AppendText(event.GetEventObject().GetLabel())

event.Skip()

def OnClear(self, event):

if self.focusWindow is not None:

self.focusWindow.Clear()

event.Skip()

def OnFocus(self, event):

print (“Got a focus event”)

if event.GetEventObject() == self.nameField:

self.focusWindow = None

else:

self.focusWindow = event.GetEventObject()

event.Skip()

``

Edit: I should probably change if self.focusWindow is not None: to self.focusWindow is wx.TextCtrl.

Yes, that is a good idea. I can extend it to have an ‘else’ clause that disables the keys if a non-input window receives the focus.

···

On Monday, September 25, 2017 at 8:52:19 PM UTC+1, Rufus wrote:

Actually, I’d be inclined to use a list of valid focus objects, as I created them, such as:

focusableWindows = [self.xvalue,self.yvalue,self.zvalue]

Then later, you can say:

if event.GetEventObject() in focusableWindows:

  self.focusWindow = event.GetEventObject()

So you can always be pointing to a valid focus window, unless you really want to de-focus the pointer.

I'm on a phone, so can't really play with this, but I think you are
making this too complicated by thinking about focus, rather than which
events are being fired from where.

Perhaps a high-level description of the UI you are trying to build
would help us guide you.

But in general you want to bind event handlers to the widget they are
coming from. If a user types into an textCtrl, then that's where you
handle that event.

Focus events are a fairly rare use case -- users can switch focus
around kind of arbitrarily-- if they need to say " I'm now going to
edit this particular data" -- better to have an explicit way for them
to select that object -- check box, or???

I'm also wary of keeping collections around and searching for which
item is relevant-- generally, you can have your widgets named:

self.data1_input = something....

Or, if you have a bunch of similar ones, put them in a dict with
meaningful names.

-CHB

The GUI the OP has built has its own "Virtual Keyboard" (calculator style) and he wants to direct
the keyed input to selected fields. A different approach may be to simply have the virtual keyboard
act like a regular keyboard, so either can be used for the data input in any field, using the built in
mechanism, rather than the way he's doing it now.

Simulating standard keyboard input from GUI events could have many benefits.

(I too, questioned using focus to do this, but instead rather highlighting the changing field with color or
a check-box as you suggest, but there'd still be the selection process, which focus seems to already
to do.)

···

On Sep 26, 2017, at 11:46 AM, Chris Barker - NOAA Federal <chris.barker@noaa.gov> wrote:

I'm on a phone, so can't really play with this, but I think you are
making this too complicated by thinking about focus, rather than which
events are being fired from where.

Perhaps a high-level description of the UI you are trying to build
would help us guide you.

But in general you want to bind event handlers to the widget they are
coming from. If a user types into an textCtrl, then that's where you
handle that event.

Focus events are a fairly rare use case -- users can switch focus
around kind of arbitrarily-- if they need to say " I'm now going to
edit this particular data" -- better to have an explicit way for them
to select that object -- check box, or???

I'm also wary of keeping collections around and searching for which
item is relevant-- generally, you can have your widgets named:

self.data1_input = something....

Or, if you have a bunch of similar ones, put them in a dict with
meaningful names.

-CHB

The GUI the OP has built has its own “Virtual Keyboard” (calculator style) and he wants to direct

the keyed input to selected fields.

Yes, that is exactly it.

A different approach may be to simply have the virtual keyboard

act like a regular keyboard, so either can be used for the data input in any field, using the built in

mechanism, rather than the way he’s doing it now.

Simulating standard keyboard input from GUI events could have many benefits.

Hmm, yes that is certainly a neat way of tackling the problem. I haven’t tried this yet, but in wxWidgets C++, events propagate upwards so I am not sure whether you can wx.PostEvent to a form and have the text appear in a child window. If not, I still need to know which wx.TextCtrl has the focus so I can post the event to it?

One other slight problem… I didn’t mention this, but I also have a clear button which clears all the text in the currently selected field. Again, I need to know which wx.TextCtrl to call Clear() on.

(I too, questioned using focus to do this, but instead rather highlighting the changing field with color or

a check-box as you suggest, but there’d still be the selection process, which focus seems to already

to do.)

I am not sure what is wrong with using focus? When a wx.TextCtrl has focus it flashes a cursor at the edit point - which to me seems a reasonable indication that that control will receive user input.

···

On Tuesday, September 26, 2017 at 8:16:12 PM UTC+1, Rufus wrote:

sure, but:

Can the user type instead?

either way, as soon as the user clicks on a button on the "number pad" --
that ctr will lose focus.

I suspect it will be a bit confusing for the user for the input to go to
the last item that happened to have focus, if, in fact, it was one of the
controls that can receive input.

On the other hand, I'm not seeing it in action, maybe it's more obvious
than it sounds.

But if you keep "the last control with focus" approach, you might want to
have a stronger visual indicator of what the active control is -- so once
someone clicks on it, it receives focus, it also get highlighted or
something, and then as they go and click on the number pad the highlight
remains.

-CHB

···

On Tue, Sep 26, 2017 at 1:05 PM, Iwbnwif Yiw <iwbnwif@gmail.com> wrote:

I am not sure what is wrong with using focus? When a wx.TextCtrl has focus
it flashes a cursor at the edit point - which to me seems a reasonable
indication that that control will receive user input.

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

No. Only Command events propagate, and _KEY and _CHAR events are not command events. Even if they did propagate it would not work for two reasons. First, sending the events to the parent will not forward the event to the child as events propagate upwards not downwards, and if the child doesn’t get the event then it will not be able to do anything with it. Second, sending a wx event will not be the same thing as a native widget getting a native message that it acts upon by adding a character to the control or whatever. wx events are only sent to the wx layers of the software stack, it is only when wx is translating a native message to an event that it can affect things, and that is only to the point of telling the native control whether the event has been handled in the wx layers or not.

Something I haven’t seen mentioned yet is the wx.UIActionSimulator. It’s not perfect but it might be enough for what you need. You will still need to ensure the focus is in the right place however before the simulator will be able to stuff keystrokes into the message queue, so you’ll still need to keep track of the last focused editable widget, because as Chris said, clicking on the buttons for your simulated keyboard will move the focus to the button.

···

On Tuesday, September 26, 2017 at 1:05:31 PM UTC-7, Iwbnwif Yiw wrote:

On Tuesday, September 26, 2017 at 8:16:12 PM UTC+1, Rufus wrote:

The GUI the OP has built has its own “Virtual Keyboard” (calculator style) and he wants to direct

the keyed input to selected fields.

Yes, that is exactly it.

A different approach may be to simply have the virtual keyboard

act like a regular keyboard, so either can be used for the data input in any field, using the built in

mechanism, rather than the way he’s doing it now.

Simulating standard keyboard input from GUI events could have many benefits.

Hmm, yes that is certainly a neat way of tackling the problem. I haven’t tried this yet, but in wxWidgets C++, events propagate upwards so I am not sure whether you can wx.PostEvent to a form and have the text appear in a child window.

Robin Dunn

Software Craftsman

Fair point, although in practice it is not as bad as it sounds. I am using it on a 7" touch screen (the Raspberry Pi official one) and it works quite nicely - I gave it to my wife to try and she had no problems without any instruction! I could perhaps change the border colour to make it even more obvious.

···

On Tuesday, September 26, 2017 at 10:40:57 PM UTC+1, Chris Barker wrote:

either way, as soon as the user clicks on a button on the “number pad” – that ctr will lose focus.

I suspect it will be a bit confusing for the user for the input to go to the last item that happened to have focus, if, in fact, it was one of the controls that can receive input.

On the other hand, I’m not seeing it in action, maybe it’s more obvious than it sounds.

But if you keep “the last control with focus” approach, you might want to have a stronger visual indicator of what the active control is – so once someone clicks on it, it receives focus, it also get highlighted or something, and then as they go and click on the number pad the highlight remains.

Second, sending a wx event will not be the same thing as a native widget getting a native message that it acts upon by adding a character to the control or whatever. wx events are only sent to the wx layers of the software stack, it is only when wx is translating a native message to an event that it can affect things, and that is only to the point of telling the native control whether the event has been handled in the wx layers or not.

Ah, yes I should have known that.

Something I haven’t seen mentioned yet is the wx.UIActionSimulator. It’s not perfect but it might be enough for what you need.

Interesting idea, I always considered that to be part of the test framework, but actually it could be perfect for this task too.

You will still need to ensure the focus is in the right place however before the simulator will be able to stuff keystrokes into the message queue, so you’ll still need to keep track of the last focused editable widget, because as Chris said, clicking on the buttons for your simulated keyboard will move the focus to the button.

It might be better if I can find a way of preventing the focus changing to the virtual keypad button. I can’t test this just now, but isn’t it possible to override wx.Button and sink the focus event, or perhaps return false from wx.Window.AcceptsFocus()?

···

On Wednesday, September 27, 2017 at 12:12:47 AM UTC+1, Robin Dunn wrote:

Another approach, which I am using for a touch screen application, is to have a calculator keyboard with

its own display/text area. All keypresses affect that display area, and I added the buttons [set x] [set y], etc

to copy that data into the selected field positions, after the data entry was complete.

Just a thought.

···

On Sep 27, 2017, at 4:33 AM, Iwbnwif Yiw iwbnwif@gmail.com wrote:

On Tuesday, September 26, 2017 at 10:40:57 PM UTC+1, Chris Barker wrote:

either way, as soon as the user clicks on a button on the “number pad” – that ctr will lose focus.

I suspect it will be a bit confusing for the user for the input to go to the last item that happened to have focus, if, in fact, it was one of the controls that can receive input.

On the other hand, I’m not seeing it in action, maybe it’s more obvious than it sounds.

But if you keep “the last control with focus” approach, you might want to have a stronger visual indicator of what the active control is – so once someone clicks on it, it receives focus, it also get highlighted or something, and then as they go and click on the number pad the highlight remains.

Fair point, although in practice it is not as bad as it sounds. I am using it on a 7" touch screen (the Raspberry Pi official one) and it works quite nicely - I gave it to my wife to try and she had no problems without any instruction! I could perhaps change the border colour to make it even more obvious.

Thanks, yes I think that would be a good way, but unfortunately the screen space is rather small on this device so the display would have to float somewhere when it was active.

···

On Wednesday, September 27, 2017 at 5:15:28 PM UTC+1, Rufus wrote:

Another approach, which I am using for a touch screen application, is to have a calculator keyboard with

its own display/text area. All keypresses affect that display area, and I added the buttons [set x] [set y], etc

to copy that data into the selected field positions, after the data entry was complete.