子窗口小部件应该处理它自己的事件吗?

时间:2013-06-12 14:46:14

标签: c++ user-interface event-handling

实施GUI时,我经常遇到两难境地。假设我有一个简单的窗口小部件层次结构,主窗口有几个子窗口小部件。子窗口小部件应该自己处理事件(例如,从用户输入产生),还是将处理委托给它们的父窗口小部件?这是一个简单的例子:当单击“关闭”按钮时,窗口应该关闭。谁关上了窗户?窗口是否对按钮事件做出反应并自行关闭?或者按钮是否在窗口上调用Close方法?我正在使用的框架强烈暗示,子窗口小部件首选方法是将事件触发到它们的父窗口小部件,它应该按照它认为合适的方式处理它们,因此窗口将像这样接近(在C ++中 - ish伪代码): / p>

void ChildWidget::OnClick()
{
    GetParentWidget()->OnEvent(CreateClickEvent(*this));
}

void ParentWidget::OnEvent(Event& _event)
{
    if (_event.Type() == EventTypeClick && _event.Id() == "close_button")
    {
        Close();
    }
    else if ...
        ...
}

然而,我担心它违反了单一责任原则,并导致父小部件做了太多工作。我可以为子窗口小部件提供处理事件所需的对象,例如:

class CloseButtonWidget : public Widget
{
public:
    CloseButtonWidget(Widget& widget_to_close)
    : WidgetToClose_(&widget_to_close)
    {}

    void OnClick()
    {
        WidgetToClose->Close();
    }       

private:
    Widget* WidgetToClose_;
};

我可以看到的缺点是,在许多情况下,我将不得不为这样一个自我处理小部件创建一个新类,但是,我经常不得不为子小部件创建新的类,所以这通常不多问题。

我能想到的另一种方法是给子窗口小部件一个回调,比如:

auto close_widget = new Widget();
// Suppose parent_widget is in scope
auto handler = CreateHandler(EventTypeClick, [parent_widget](){ parent_widget->Close(); }); 
close_widget->SetHandler(handler);

所以问题是 - 处理来自儿童小部件的事件的最佳位置是什么?上述方法有哪些优点和缺点?也许有其他更好的方法来做到这一点?我会特别感兴趣听到“父小部件处理一切”场景的任何专业人士,因为我发现很难看到任何。 我想澄清一下,我想要一个以更“哲学”的方式解决问题的答案(比如更好的设计),保持我正在使用的框架的首选方式和怪癖不是很重要的。

1 个答案:

答案 0 :(得分:0)

IMPO第一种方法是瓶颈。操作系统/框架为您提供特定于窗口小部件的事件,以避免您必须执行“提取”过程。你通过一个事件处理程序处理每个事件?听起来像是浪费时间。

如果要以相同的方式处理一组事件(或者从一组窗口小部件引发的同一事件),请使用相同的事件处理程序。

例如,类似战舰的游戏:你有一个按钮网格,你以相同的方式处理网格所有按钮的点击事件(一个按钮和其他按钮之间的唯一区别是它的坐标)。

如果您必须在每个窗口小部件事件中执行不同的操作(或者在同一窗口小部件的不同事件中),请使用自己的处理程序处理特定于窗口小部件的事件。

正如您所注意到的,特定处理程序的问题在于它们的实现。使您过度复制代码。但是想想你不是Java!你有一流的函数(通过原始函数指针或函子),而不是伪函数委托(Aka内部类),它们只适合20行来编写单行操作。你使用C ++,你有模板,lambda,仿函数和其他有用的工具来编写特定的处理程序,只有一行简单明了的代码:)

正如你所看到的,我更喜欢每次可能/简单时使用你的第3种方式。