wxWidgets经典问题——主窗体收不到按键事件的最终解决

GUI经典名库wxWidgets对于按键事件的处理,和同类产品相比,有个小的、但很折磨人的不同之处:如果焦点位于某个控件(子窗体)之上,那么当时发生的wxKeyEvent事件只发给那个子窗体,而主窗体拦截不到,也无法处理,这在一些时候带来了很大麻烦。我坚信这个功能决不是因为没有必要而被wxWidgets刻意取消的,这不是“你应该修改程序逻辑”的问题,因为从前用过的VB和Delphi都提供了这种功能,就是主窗体有一个KeyPreview属性,设置为真之后,主窗体本身就可以先一步得到任何控件上的按键事件,进行处理。

现在我的程序必须用这个功能,被迫上网搜索解决方案,除了得到此处等线索外无甚收获。按其做法,就是给子控件的事件也截下来,在其中特意调用一下主窗体的处理函数。这确实是第一反应的思路,但怎么看怎么觉得丑陋了点,何况子控件多点的话需要一一写接力函数,不厌其烦,要是为了处理子控件的事件而一一建立他们的派生类则更是郁闷。另外的方法也尝试了,调用主窗体的GetChildren方法得到子窗体列表,将所有子窗体的wxKeyEvent事件用Connect连接到同一个处理函数,结果运行时程序怎么都崩溃,原因不明,尚待进一步考察wxWidgets内部阴险的实现。

失望之余打算绕开这个问题,又尝试用快捷键列表wxAcceleratorTable来代替这个功能,停留在想法阶段就放弃了,因为我需要分别处理KeyDown和KeyUp事件,而快捷键根本区分不开这个(不需要区分的应用倒是可以试试这个方法),另外如果需要对大量按键都响应的话,则不可避免巨大无比的快捷键列表,更是丑陋。

当我绝望地随手浏览快翻烂了的wxWidgets文档时,那个希望终于出现了:wxEvtHandler::SetNextHandler方法。这是指定事件处理链中的下一个处理者的方法。感谢这个比所有窗口的基类wxWindow还祖宗的类所提供的这个设施,让那些子窗体接受到事件后直接串联到主窗体上就行了。遍历主窗体的所有子窗体(用GetChildren方法获得),对每个都调用->SetNextHandler(this),将主窗体串入其事件处理链:

MainFrame::MainFrame() {
//……

wxWindowList children = GetChildren();
for (wxWindowListNode *i=children.GetFirst(); i; i=i->GetNext()) {
i->GetData()->SetNextHandler(this);
}
}

实测,问题解决,逻辑正确,不用额外定义函数,不用派生类。另外对于“子又有子”这样的窗体对象结构,这个过程应该改为递归的。

也许同样的或更好的解决方案网上早已有了,只是本人太笨而没搜索到,那么下面把我尝试过的关键词尽可能都列出来,以便搜索引擎索引,方便他人:wxWidgets,wxWindow,窗口,窗体,控件,焦点,按键,键盘,事件,拦截,KeyPreview,wxFrame,wxDialog,wxTopLevelWindow,wxKeyEvent,EVT_KEY_DOWN,EVT_KEY_UP,OnKeyUp,OnKeyDown

你可能感兴趣的:(搜索引擎,文档,UP,vb,Delphi,产品)