子部件是不是应该处理自己的事件?

Posted

技术标签:

【中文标题】子部件是不是应该处理自己的事件?【英文标题】:Should a child widget handle its' own events?子部件是否应该处理自己的事件? 【发布时间】:2013-06-12 14:46:13 【问题描述】:

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

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】:

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

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

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

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

正如您所注意到的,特定处理程序的问题在于它们的实现。让你重复代码。但是认为你不是在 Java 中!您拥有一流的函数(通过原始函数指针或函子),而不是适合 20 行的伪函数委托(也称为内部类)来仅编写单行操作。你在 C++ 中,你有模板、lambda、仿函数和其他有用的工具来编写特定的处理程序,只需要一行简单而清晰的代码:)

如您所见,我更喜欢每次尽可能/简单地使用您的第三种方式。

【讨论】:

以上是关于子部件是不是应该处理自己的事件?的主要内容,如果未能解决你的问题,请参考以下文章

我应该处理 WSASend() 可能不会发送所有数据的事实吗?

服务器或客户端在发送/接收日期时应该处理时区吗?

我应该处理超过 MAX_PATH 的文件吗?

我应该处理 X509Certificate2 吗?

Solidity 应该处理 Dapp 中的分页吗?

REST API 的验收测试 - 我应该处理所有情况吗?