Hi wxPythoneres,
I made this (to me) really slick subclass of wx.Panel that acted like
a wx.Button, but did things that I really needed, specific to my app.
The panel housed several wx.StaticBitmaps that I could show() and hide
() depending on the state of various things, and I bound it to right
and left button clicks, and it worked just dandy.
Then, I decided to add some wx.TextCtrls to the same application,
along with bunches of these buttons. That's when a problem made
itself apparent: if you click in a wx.TextCtrl, and THEN click one of
my buttons, you would expect focus (both plain, and keyboard focus) to
leave the text control. If I use wx.Buttons, it does that, but when I
use my buttons, the focus stays on the text control. It thoroughly
confuses users of my app that type in the text control, enter some
data, and then just want to "click away" from the text control to have
the data "take" (as opposed to hitting <tab>, which works fine).
I've made an as-simple-as-I-could-get-it app that demonstrates this,
and I'll paste it below. You'll have to change 'huh.bmp' to be some
bitmap that you have lying around... sorry about that. Anyway, once
it's running, if you click in the text control, then click on the
"button", you'll notice the I-beam cursor still in the text control.
Keyboard typing still goes to the text control too.
I've tried everything I can think of to salvage this, including
changing my superclass to wx.PyPanel, and overriding the
AcceptsFocusFromKeyboard and AcceptsFocus methods (that's included in
the code below). I also tried changing the wx.StaticBitmap to
wx.BitmapButton and changing wx.Panel to wx.Control. Both of these
attempts made the display look ugly, and they didn't work either.
I really hate to throw away the 700 lines of code I wrote for my
button class, but perhaps I've gone down a rabbit hole that has no
escape.
A second question, if I haven't gone on too long already... When you
run this app below, you may notice (I do) that some clicks on MyButton
don't take. Rapidly clicking on it most of the time calls OnClick,
but not always. Same with my real version of MyButton. Any ideas on
that?
Thanks, and here's the code...
Bill.
import wx
class MyButton(wx.PyPanel):
def __init__(self, parent, id):
wx.PyPanel.__init__(self, parent)
image = wx.Image('huh.bmp') #### <---- PLEASE CHANGE THIS TO
A BITMAP YOU HAVE LYING AROUND
self.defaultBitmap = wx.StaticBitmap(self, -1,
wx.BitmapFromImage(image))
self.defaultBitmap.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
def OnClick(self, evt):
print "Button clicked"
# I had high hopes that subclassing wx.PyPanel instead of
wx.Panel, and including these
# would help, but no go.
def AcceptsFocusFromKeyboard(self):
"""Overridden base class virtual."""
return True
def AcceptsFocus(self):
""" Overridden base class virtual. """
return True
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, 'my bitmap "button"
never takes focus away from wx.TextCtrl')
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
txt = wx.TextCtrl(panel, wx.ID_ANY, "")
txt.Bind(wx.EVT_SET_FOCUS, self.onFocus)
txt.Bind(wx.EVT_KILL_FOCUS, self.onKillFocus)
btn = MyButton(panel, wx.ID_ANY)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(txt, 0, wx.ALL, 5)
sizer.Add(btn, 0, wx.ALL, 5)
panel.SetSizer(sizer)
def onFocus(self, event):
print "text widget received focus!"
def onKillFocus(self, event):
print "text widget lost focus!"
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm().Show()
app.MainLoop()