我正在尝试修改 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:该示例工作正常,我只是无法处理按键事件。
据我所知,你应该使用
Event::Special(Event::Return))
但是我对lib不熟悉
参考: https://arthursonzogni.github.io/FTXUI/event_8cpp_source.html
经过几次尝试和研究,我感谢卢卡斯的帮助,我能够看到它是如何工作的。
我们应该在菜单声明之后添加一个事件处理程序:
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 每次处理。
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;
}