FTXUI
関数型・宣言的なスタイルでTUIを構築するモダンなC++ライブラリ。Reactに似たコンポーネントベースの設計で、ヘッダーオンリーで依存関係なし。
GitHub概要
ArthurSonzogni/FTXUI
:computer: C++ Functional Terminal User Interface. :heart:
スター8,531
ウォッチ81
フォーク490
作成日:2019年1月27日
言語:C++
ライセンス:MIT License
トピックス
arthursonzogniasciiascii-artcppcursesimpleterminalterminal-basedtuiuiuser-interfacexterm
スター履歴
データ取得日時: 2025/7/25 11:08
FTXUI
FTXUIは、関数型かつ宣言的なスタイルでターミナルユーザーインターフェース(TUI)を構築するためのモダンなC++ライブラリです。Reactのようなコンポーネントベースの設計を採用し、ヘッダーオンリーで外部依存なしという特徴を持ちます。美しく、インタラクティブなターミナルアプリケーションを効率的に開発できます。
特徴
関数型・リアクティブプログラミング
- 宣言的UI: Reactライクな宣言的アプローチ
- コンポーネントベース: 再利用可能なUIコンポーネント
- 状態管理: 自動的なUI更新とイベント処理
- 関数型パラダイム: 純粋関数とイミュータブルなデータ
アーキテクチャ
- screen: ターミナルへの最終レンダリング
- dom: UI構造を定義するElementツリー
- component: インタラクティブ要素とイベント処理
- animation: スムーズなアニメーション機能
豊富なコンポーネント
- 入力: Input、Checkbox、Radiobox、Slider
- 選択: Menu、Dropdown、Toggle
- レイアウト: Container、Scroller、Collapsible
- 表示: Gauge、Spinner、Table
モダンな機能
- ヘッダーオンリー: 簡単な統合、依存関係なし
- C++17対応: モダンC++の機能を活用
- Unicode対応: 絵文字と国際化サポート
- マウス対応: クリック、ドラッグ、ホイールイベント
基本的な使用方法
インストール
# CMakeを使用
git clone https://github.com/ArthurSonzogni/FTXUI
mkdir build && cd build
cmake ..
make -j
# vcpkgを使用
vcpkg install ftxui
# コンパイル例
g++ -std=c++17 main.cpp -lftxui-screen -lftxui-dom -lftxui-component
Hello World
#include <ftxui/dom/elements.hpp>
#include <ftxui/screen/screen.hpp>
#include <iostream>
using namespace ftxui;
int main() {
// DOM要素の作成
auto document = hbox({
text("Hello"),
text(" "),
text("World!") | color(Color::Cyan) | bold,
}) | border;
// スクリーンへのレンダリング
auto screen = Screen::Create(
Dimension::Fixed(20),
Dimension::Fixed(5)
);
Render(screen, document);
screen.Print();
return 0;
}
インタラクティブなアプリケーション
#include <ftxui/component/captured_mouse.hpp>
#include <ftxui/component/component.hpp>
#include <ftxui/component/component_base.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <ftxui/dom/elements.hpp>
using namespace ftxui;
int main() {
// 状態変数
std::string input_value;
int slider_value = 50;
bool checkbox_checked = false;
int menu_selected = 0;
// コンポーネントの作成
auto input = Input(&input_value, "名前を入力...");
auto slider = Slider("音量: ", &slider_value, 0, 100, 1);
auto checkbox = Checkbox("通知を有効にする", &checkbox_checked);
std::vector<std::string> menu_items = {
"新規作成",
"開く",
"保存",
"終了"
};
auto menu = Menu(&menu_items, &menu_selected);
// レイアウト
auto container = Container::Vertical({
input,
slider,
checkbox,
menu,
});
// レンダラー
auto renderer = Renderer(container, [&] {
return vbox({
text("設定画面") | bold | center,
separator(),
hbox({text("名前: "), input->Render()}),
slider->Render(),
checkbox->Render(),
separator(),
text("メニュー:"),
menu->Render() | frame | size(HEIGHT, LESS_THAN, 10),
separator(),
text("入力値: " + input_value),
text("スライダー: " + std::to_string(slider_value)),
}) | border;
});
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(renderer);
return 0;
}
カスタムコンポーネント
#include <ftxui/component/component.hpp>
#include <ftxui/component/component_base.hpp>
#include <ftxui/dom/elements.hpp>
using namespace ftxui;
// カスタムボタンコンポーネント
class CustomButton : public ComponentBase {
private:
std::string label_;
std::function<void()> on_click_;
bool hovered_ = false;
public:
CustomButton(const std::string& label, std::function<void()> on_click)
: label_(label), on_click_(on_click) {}
Element Render() override {
auto style = hovered_ ? inverted : nothing;
return text("[ " + label_ + " ]") | style | reflect(box_);
}
bool OnEvent(Event event) override {
if (event.is_mouse()) {
auto mouse = event.mouse();
hovered_ = box_.Contain(mouse.x, mouse.y);
if (mouse.button == Mouse::Left &&
mouse.motion == Mouse::Released &&
hovered_) {
on_click_();
return true;
}
}
if (event == Event::Return && Focused()) {
on_click_();
return true;
}
return false;
}
bool Focusable() const override { return true; }
private:
Box box_;
};
// 使用例
int main() {
int counter = 0;
auto button = Make<CustomButton>("クリック!", [&] {
counter++;
});
auto renderer = Renderer(button, [&] {
return vbox({
text("カウンター: " + std::to_string(counter)) | center,
separator(),
button->Render() | center,
}) | border | size(WIDTH, EQUAL, 30);
});
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(renderer);
return 0;
}
アニメーション
#include <ftxui/component/animation.hpp>
#include <ftxui/component/component.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <ftxui/dom/elements.hpp>
#include <chrono>
using namespace ftxui;
using namespace std::chrono_literals;
int main() {
// アニメーション変数
auto duration = 2s;
auto start_time = std::chrono::steady_clock::now();
auto component = Renderer([&] {
auto now = std::chrono::steady_clock::now();
auto elapsed = now - start_time;
float progress = std::chrono::duration<float>(elapsed).count() /
std::chrono::duration<float>(duration).count();
progress = std::min(1.0f, progress);
// イージング関数
auto ease_in_out = [](float t) {
return t < 0.5f ? 2 * t * t : -1 + (4 - 2 * t) * t;
};
float animated_value = ease_in_out(progress);
int position = static_cast<int>(animated_value * 40);
return vbox({
text("アニメーションデモ") | bold | center,
separator(),
hbox({
text(std::string(position, ' ')),
text("●") | color(Color::Red),
}),
separator(),
gauge(progress) | color(Color::Blue),
text("進行: " + std::to_string(int(progress * 100)) + "%") | center,
}) | border;
});
auto screen = ScreenInteractive::TerminalOutput();
// アニメーションループ
std::atomic<bool> refresh_ui_continue = true;
std::thread refresh_ui([&] {
while (refresh_ui_continue) {
std::this_thread::sleep_for(16ms);
screen.PostEvent(Event::Custom);
}
});
screen.Loop(component);
refresh_ui_continue = false;
refresh_ui.join();
return 0;
}
高度な機能
Flexboxレイアウト
// Flexboxを使用した柔軟なレイアウト
auto layout = flexbox({
{
text("左側") | border,
FlexboxConfig().Set(FlexboxConfig::Direction::Column)
.Set(FlexboxConfig::Wrap::NoWrap)
.Set(FlexboxConfig::JustifyContent::Center)
},
{
text("中央") | border | flex,
FlexboxConfig().Set(FlexboxConfig::AlignItems::Center)
},
{
text("右側") | border,
FlexboxConfig().Set(FlexboxConfig::Basis, 20)
},
});
Canvas要素
// Canvasを使用した描画
auto canvas_element = canvas([](Canvas& c) {
// ブレイル文字を使用した高解像度描画
c.DrawText(10, 5, "Canvas Demo");
c.DrawLine(0, 0, 40, 20);
c.DrawCircle(20, 10, 5);
// ブロック文字を使用
c.DrawBlock(30, 15, true);
});
モーダルダイアログ
class ModalComponent : public ComponentBase {
private:
bool show_modal_ = false;
Component container_;
public:
ModalComponent() {
auto modal_content = Renderer([&] {
return vbox({
text("確認") | bold | center,
separator(),
text("本当に終了しますか?"),
separator(),
hbox({
button("はい", [&] {
show_modal_ = false;
// 終了処理
}),
text(" "),
button("いいえ", [&] {
show_modal_ = false;
}),
}) | center,
}) | border | center;
});
auto main_content = button("終了", [&] {
show_modal_ = true;
});
container_ = Container::Tab(
{main_content, modal_content},
&show_modal_
);
}
Element Render() override {
return container_->Render();
}
bool OnEvent(Event event) override {
return container_->OnEvent(event);
}
};
エコシステム
関連プロジェクト
- ftxui-starter: プロジェクトテンプレート
- json-tui: JSONビューア
- git-tui: Gitクライアント
- spotify-tui: Spotifyクライアント
ビルドシステム
- CMake: ネイティブサポート
- vcpkg: パッケージマネージャー
- Conan: パッケージマネージャー
- Bazel: ビルドシステム
利点
- モダンな設計: 関数型・リアクティブプログラミング
- 依存関係なし: ヘッダーオンリーで簡単統合
- 豊富な機能: 多様なコンポーネントとレイアウト
- 高パフォーマンス: 効率的なレンダリング
- クロスプラットフォーム: Windows、Linux、macOS対応
制約事項
- C++17必須: 古いコンパイラでは使用不可
- 学習曲線: 関数型パラダイムの理解が必要
- デバッグ: TUIアプリのデバッグは複雑
- ドキュメント: 日本語資料が少ない
他のライブラリとの比較
項目 | FTXUI | ncurses | ImTui |
---|---|---|---|
パラダイム | 関数型 | 命令型 | 即時モード |
依存関係 | なし | システム | ncurses |
学習コスト | 中 | 高 | 低 |
モダンさ | 非常に高 | 低 | 高 |
機能 | 豊富 | 基本的 | 中程度 |
まとめ
FTXUIは、モダンなC++でTUIアプリケーションを開発するための優れたライブラリです。関数型・リアクティブプログラミングのアプローチにより、複雑なUIを宣言的に構築でき、保守性の高いコードを実現します。ヘッダーオンリーで依存関係がないため、プロジェクトへの統合も簡単です。Webフロントエンド開発の経験がある開発者には特に親しみやすく、美しくインタラクティブなターミナルアプリケーションを効率的に開発できます。