【问题标题】:Disadvantages of using a function pointer as an UI-Button callback使用函数指针作为 UI-Button 回调的缺点
【发布时间】:2021-05-08 20:47:16
【问题描述】:

我目前正在创建自己的基于 SFML 的 GUI-Library。 目前我正在研究一个按钮。因此,在创建按钮时,您还必须指定一个回调,它是一个函数,在按钮单击时执行。

现在,我要回答我只使用指向函数的指针作为按钮回调的缺点是什么,因为我不知道任何流行的 GUI 库也可以这么简单地做到这一点。 如果回调函数是一个很长的过程,我会在一个新线程中执行它,但我现在不确定。

那么,不使用这种简单解决方案的原因是什么,尤其是更好的方法是什么?

【问题讨论】:

  • 正如您所指出的,如果该函数执行任何重要的工作,它将导致用户界面冻结,用户讨厌。这就是为什么大多数 GUI 库都有一个专门的 UI 线程,并且不允许在该线程中做任何“繁重”的事情。我认为大多数现代 GUI 库都使用某种事件队列系统(最终可以使其他功能更易于实现,例如撤消/重做)。
  • 我建议使用 lambda 闭包指定回调。这样,由于捕获,闭包可以与初始环境中的任何内容进行交互,而无需转发void *,也无需依赖诸如继承之类的OO东西,这些东西会在应用程序的各个部分之间引入大量耦合。当然,如果你非常小心,闭包可以启动(或与之交互)线程......
  • @0x5453 是的,我会通过在另一个线程中执行回调来解决这个问题,但它仍然是指向函数的指针
  • 我所知道的所有 GUI 库 do 在 GUI 线程上执行回调,其中大部分是同步的,但其中一些来自事件队列。如果你想在回调中做繁重的工作,你应该编写一个回调,将工作委托给另一个线程并快速返回。

标签: c++ user-interface pointers sfml


【解决方案1】:

仅使用指向函数的指针作为按钮回调有什么缺点

将一些上下文参数传递给该函数会很方便。 我的意思是,UI 可能有很多按钮对各种对象执行相同的操作。不妨想想朋友列表中每个昵称旁边的“发送消息”按钮。

因此,您可能希望您的按钮将一些上下文参数传递给调用。 但既然我们在谈论 C++,最好将其抽象为

struct IButtonAction
{
    virtual void OnAttached() = 0;
    virtual void OnDetached() = 0;
    virtual void OnClick() = 0;
};

并让客户端代码实现这个接口,在每个实例对象中存储Arg1Arg2等。

按钮类在使用指向此回调接口实例的指针开始/结束时将调用OnAttached/OnDetached。这些呼叫必须配对。如果需要,这些方法的客户端实现可以执行生命周期管理和与OnClick 同步。

OnClick 方法执行操作。

我认为按钮不应该打扰线程。客户端代码负责决定是否为长时间操作生成线程。

【讨论】:

    【解决方案2】:

    这是一个棘手的问题!

    函数指针在发送方很容易实现,但在接收方很难使用,因为它们没有任何上下文。

    一个问题是函数指针不能指向成员函数。这就是为什么您经常看到(C 风格)框架将任意void *userData 传递给它们的回调,因此您可以转换您的this 指针并以这种方式检索它。这仍然需要您编写一个静态包装函数来将指针转换回并调用成员函数。

    更现代的解决方案是使用std::function。这可以包含常规函数指针、成员函数指针,还可以包含 lambda 或仿函数。

    但是,当您像这样(或以其他方式)添加上下文时,您很快就会遇到生命周期的困难。当接收类在发送者之前被销毁时,应该发生什么?如果您什么都不做,这种情况将导致未定义的行为。一种解决方案是在接收方跟踪接收方订阅了哪些事件,并在接收方被销毁之前解除绑定。而这需要双向进行:当发送者被销毁时,它还需要通知接收者它应该忘记发送者,否则接收者稍后会尝试解除绑定不再存在的事件。

    而且我什至还没有开始考虑多线程......

    有库以各种方式解决这些问题,例如eventpp(只是通过网络搜索找到的,这不是背书)。

    另一个值得一提的是 Qt 工具包,它甚至为 C++ 语言编写了自己的小型 signals and slots 扩展(实现为代码生成器和一堆宏)以非常简单的方式解决这个问题符合人体工程学的方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-25
      • 1970-01-01
      • 1970-01-01
      • 2018-03-07
      • 1970-01-01
      • 2013-03-31
      相关资源
      最近更新 更多