Python 我可以从标准选项卡遍历中排除特定控制器吗?

Python 我可以从标准选项卡遍历中排除特定控制器吗?,python,wxpython,wxwidgets,Python,Wxpython,Wxwidgets,我创建了一个自定义对话框,其中包含一系列文本控件。每个文本控件旁边都有两个按钮,用于更方便地添加特定值。我不希望这些按钮在用户it选项卡遍历对话框时获得焦点,因为在大多数情况下,用户不需要使用这些按钮 P>是否存在从标准选项卡遍历中排除特定控制器的方便方法?< P>如果使用C++,这个问题有一个简单的解决方案,如在这个答案的其余部分中所描述的。在wxPython中,似乎无法专门化wxWidgets类——在我看来,这是一个致命的障碍 您可以创建按钮控件的专门化,通过重写AcceptsFocusF

我创建了一个自定义对话框,其中包含一系列文本控件。每个文本控件旁边都有两个按钮,用于更方便地添加特定值。我不希望这些按钮在用户it选项卡遍历对话框时获得焦点,因为在大多数情况下,用户不需要使用这些按钮


<> P>是否存在从标准选项卡遍历中排除特定控制器的方便方法?

< P>如果使用C++,这个问题有一个简单的解决方案,如在这个答案的其余部分中所描述的。在wxPython中,似乎无法专门化wxWidgets类——在我看来,这是一个致命的障碍

您可以创建按钮控件的专门化,通过重写AcceptsFocusFromKeyboard()以返回FALSE,该控件将被排除在选项卡遍历之外

下面的C++代码工作良好:当TAB按下“

”时,焦点从第一个按钮跳到第三个按钮
class cNoTabButton : public wxButton
{
public:
    cNoTabButton(wxWindow *parent,
             wxWindowID id,
             const wxString& label = wxEmptyString,
             const wxPoint& pos = wxDefaultPosition,
             const wxSize& size = wxDefaultSize,
             long style = 0 )
             : wxButton(parent,id,label,pos,size,style)
    {}
    bool AcceptsFocusFromKeyboard() const { 
        return false;
    }
};

MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
{
    // set the frame icon
    SetIcon(wxICON(sample));

    wxPanel * panel = new wxPanel(this,-1,wxPoint(0,0),wxSize(500,500));

    new wxButton(panel,-1,"TabPlease",wxPoint(20,20));
    new cNoTabButton(panel,-1,"NoTabThanks",wxPoint(100,20));
    new wxButton(panel,-1,"OKWithMe",wxPoint(200,20));


}

防止按钮被键盘聚焦的一个简单方法是从
wx.lib.buttons.GenButton
wx.lib.buttons.GenButton
派生,它们基于支持覆盖
AcceptsFocusFromKeyboard()的
wx.PyControl


对于更复杂的导航规则或控件,您可以处理
wx.EVT\u navigation\u键
,并自行管理导航。要获取要导航的窗口列表,可以使用
self.GetChildren()
。可以通过
.index(mywindow)
获得
wx.WindowList
中当前聚焦窗口的索引。 有了这些信息,您可以在用户按下“导航键”时在列表中导航,并将焦点设置为下一个适用的控件,跳过您不想聚焦的控件

要使在列表中导航更容易,可以创建生成器:

def CycleList(thelist,index,forward):
    for unused in range(len(thelist)): # cycle through the list ONCE
        if forward:
            index = index+1 if index+1 < len(thelist) else 0
        else:
            index = index-1 if index-1 >= 0 else len(thelist)-1
        yield thelist[index]
上面的示例模拟了默认行为:它在可聚焦控件之间循环(跳过静态文本之类的不可聚焦控件)。 您可以展开检查以排除特定控件,或者创建一个自定义按钮类,该类实现
AcceptsFocusFromKeyboard
返回False

注意:
wx.PyWindow
wx.PyPanel
wx.PyControl
实现允许覆盖
AcceptsFocusFromKeyboard
的机制时,标准的wxPython控件
但是,在python端处理
wx.EVT\u NAVIGATION\u键
并检查
AcceptsFocusFromKeyboard
,将访问实际的python对象,该对象将调用重写的方法。

这不是一个完美的解决方案,但其中一种方法实际上是将控件获取焦点的时间延迟半秒

您的主窗口将恢复焦点,按钮仍能工作。我之所以使用它,是因为我希望我的主窗口能够处理所有按键,但仍然包含鼠标使用的按钮

因此,将KILL_FOCUS事件绑定到应该保留焦点的控件中,并创建一个无法从中获取焦点的控件列表

首先使用一个helper函数来获取所有子对象:

def GetAllChildren(control):
    children = []
    for c in control.GetChildren():
        children.append(c)
        children += GetAllChildren(c)
    return children
在我的情况下,我希望窗口中的所有子对象都不要获得焦点

self.not_allowed_focus = GetAllChildren(self)
self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
在我的KILL FOCUS处理程序中,我要求在半秒钟后返回焦点

def OnKillFocus(self,evt):
    print "OnKillFocus"
    win = evt.GetWindow()
    if win in self.not_allowed_focus:
        wx.CallLater(500,self.SetFocus)

这似乎不适用于wxPython。()我不是python专家,所以我不知道为什么你的代码不能工作。您确定这就是专门化控件所需的全部内容吗?你的构造器在哪里?我已经发布了工作C++代码。这在Python中根本不起作用,因为重写函数,例如,这没有效果。C++库从来没有调用这个函数,它不是Python的问题,它与WxPython有关。如果wxPython是用纯Python编写的,那么重写这些类就可以了,但事实并非如此。方法调用从WyWIDGET对象,如Python中的“代码>按钮”/Cuth>执行实际的C++代码,但是来自WxWIDGET的方法调用,例如管理Tabor遍历的代码,不能调用Python方法——因此,试图从Python中重写C++函数没有任何用处。wxPython定义了一些Python版本的类,例如
PyWindow
PyPanel
,它们支持从Python重写方法,但按钮控件不是其中之一。这很有意义+1.我总是超越wxWidgets类来包含特殊行为。我想知道我是否应该学习wxpython——现在我不想麻烦了。谢谢你帮我省去了白费力气。
def GetAllChildren(control):
    children = []
    for c in control.GetChildren():
        children.append(c)
        children += GetAllChildren(c)
    return children
self.not_allowed_focus = GetAllChildren(self)
self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
def OnKillFocus(self,evt):
    print "OnKillFocus"
    win = evt.GetWindow()
    if win in self.not_allowed_focus:
        wx.CallLater(500,self.SetFocus)