处理 ftxui 菜单示例中的输入

问题描述 投票:0回答:3

我正在尝试修改 ftxui 库示例,其中有一个交互式菜单。我想处理输入键,以便通过此输入进行选择,然后我可以转到其他屏幕。该示例很好地捕获了选择,但我无法捕获输入。我对这个工具不是很了解,所以我尝试尽可能少地修改他们的示例。

示例来自此链接: 示例/组件/menu_entries_animated.cpp

下面是我的修改版本,为了简单起见,使用“x”键:

auto renderer = Renderer(menu, [&] {
        if (menu->OnEvent(ftxui::Event::Character('x')))
        {
            std::cout << "x\n";
        }
        return vbox({
                   hbox(text("selected = "), text(std::to_string(selected))),
                   separator(),
                   menu->Render() | frame,
            }) |
            border | bgcolor(Color::Black);
        });

根据我的理解,它应该有效,但它不起作用。有人可以告诉我我缺少什么吗?

OBS:该示例工作正常,我只是无法处理按键事件。

menu console-application
3个回答
0
投票

据我所知,你应该使用

Event::Special(Event::Return))

但是我对lib不熟悉

参考: https://arthursonzogni.github.io/FTXUI/event_8cpp_source.html


0
投票

经过几次尝试和研究,我感谢卢卡斯的帮助,我能够看到它是如何工作的。

我们应该在菜单声明之后添加一个事件处理程序:

m_menu = Container::Vertical(
    m_json_menu_entries,
    &m_selected);

m_menu |= CatchEvent([&](Event event) {
    bool ret = (ftxui::Event::Character('\n') == event);
    return ret;
    });

这应该被调用一次,事件将由 lambda 每次处理。


0
投票

Montes 的答案完全正确,但我并不清楚如何应用它,所以我将添加一个额外的示例。 ChatGPT/CoPilot 非常坚持以下错误语法的变体。它不知道如何应用

Event
OnEvent()
,并且很难为 FTXUI 演示编写正确的
main(){}

// Don't Do this:
Component App(bool& is_right_column_collapsed) {
  return Renderer([&] { return App(is_right_column_collapsed); })
    .OnEvent(& {           // <-- Wrong 
      if (event == Event::Custom) {
        is_right_column_collapsed = !is_right_column_collapsed;
      }
    });
}

正确答案是使用

CatchEvent()
。理解 Montes 答案的关键是阅读 FTXUI 文档:

“CatchEvent() - 返回一个组件,使用 |on_event| 捕获事件。 当事件被处理时,这个函数must返回true, 否则为假。” https://arthursonzogni.github.io/FTXUI/namespaceftxui.html#ad2948235799c010c76c6de861c050c59

我们看到正确的

CatchEvent()
示例:

auto screen = ScreenInteractive::TerminalOutput();
auto renderer = Renderer([] { return text("Hello world"); });
renderer |= CatchEvent([&](Event event) {
  if (event == Event::Character('q')) {
    screen.ExitLoopClosure()();
    return true;
  }
  return false;
});
screen.Loop(renderer);

下一段将

Maybe()
描述为“也许显示”,这是我也需要的组件。

为了在不同的上下文中展示

CatchEvent()
并演示各个部分如何组合在一起,我的解决方案如下所示。我的目标是创建三个框架列,其中反勾号键 ( ` ) 显示/隐藏右列。请注意使用
Maybe()
来“可能显示”组件。有两个活动

  • 反勾` - 显示/隐藏右栏

  • “q”键 - 退出程序

    元素LeftColumn() { 返回 vbox({ text(L"左栏"), }) |边框|大小(宽度,小于,60); }

    Element MiddleColumn() { ... } 元素 RightColumn() { ... }

    组件应用程序(bool& is_right_column_collapsed) { // 创建一个可以使用“Maybe()”打开/关闭的组件 auto rightColumnComponent = Renderer([&] { return RightColumn(); }); 自动 MaybeShown = Maybe(rightColumnComponent, &is_right_column_collapsed);

      // Define the main-layout Component
      auto myapp = Container::Horizontal({
          Renderer([&] { return LeftColumn(); }),
          Renderer([&] { return MiddleColumn(); }),
          maybeShown,
        });
    
      // Decorate main Component with events.
      myapp = myapp | CatchEvent( [&] (Event event) {
            if (event == Event::Character('`')) {
                is_right_column_collapsed = !is_right_column_collapsed;
                return true;               // CatchEvent() MUST return true if event was handled,
            }
            return false;                  // or false if it wasn't!
        } );
    
      return myapp;
    

    }

    int main(int argc, const char* argv[]) { 布尔 is_right_column_collapsed = false;

      auto app = App(is_right_column_collapsed);
      auto screen = ScreenInteractive::FitComponent();
    
      // Decorate app component with 'quit' event.
      app |=  CatchEvent( [&](Event event) {
          if (event == Event::Character('q')) {
              screen.ExitLoopClosure()();
              return true;
          }
          return false;
      });
    
      screen.Loop(app);
      return 0;
    

    }

© www.soinside.com 2019 - 2024. All rights reserved.