WebCFace 2.5.2
Web-based Communication Framework & Dashboard-like UI
Loading...
Searching...
No Matches
5-4. View

Since
See also

テキストやボタンなどの配置を送受信します。

送信

Note
Viewの2回目以降の送信時にはWebCFace内部では前回からの差分のみが送信されるので、通信量が削減されます
  • C++ Client::view からViewオブジェクトを作り、 View::add() などで要素を追加し、 最後にView::sync()をしてからClient::sync()をすることで送信されます。

    Viewはstd::ostreamを継承しており、 add() の代わりに v << 表示する値; というようにもできます。 ostreamに出力可能なものはそのままviewにテキストとして出力できます。 ostreamと同様にフォーマットを指定したり、std::endlで改行もできます。

    webcface::View v = wcli.view("a");
    // v.init(); // ←オブジェクトvを新規に構築せず繰り返し使いまわす場合は必要
    v << "hello world" << std::endl; // v.add("hello world").add("\n") と等価
    v << i << std::endl; // i はintの変数とか
    v << webcface::button("a", [] { std::cout << "hello" << std::endl; }) << std::endl;
    v.sync(); // ここまでにvに追加したものをクライアントに反映
    wcli.sync();
    Viewの送受信データを表すクラス
    Definition view.h:26
    const View & sync() const
    Viewの内容をclientに反映し送信可能にする
    Definition view.cc:31
    View view(std::string_view field="") const
    Definition field.cc:74

    example_view.png

    Warning
    2.0 ワイド文字列を出力したい場合はostreamに直接渡すのではなく Component::text を使う必要があります。 (後述)

    C++ではViewのデストラクタでも自動的にView.sync()が呼ばれます。

    {
    webcface::View v = wcli.view("a");
    v << ...;
    v << ...;
    // v.sync(); (自動で呼ばれる)
    }
    wcli.sync();
    Note
    1.2 Viewオブジェクトをコピーした場合、Viewオブジェクトの内容はコピーされるのではなく共有され、そのすべてのコピーが破棄されるまでsync()は呼ばれません。
  • C

    Since
    1.7

    wcfViewComponent, (2.0 wcfViewComponentW) の配列を wcfViewSet, (2.0 wcfViewSetW) に指定することで送信されます。

    vc[0] = wcfText("hello world\n");
    char buf[10];
    sprintf(buf, "%d", i); // i はintの変数とか
    vc[1] = wcfText(buf);
    vc[2] = wcfNewLine(); // wcfText("\n") と同じ
    wcfFuncListen(wcli, "hoge", ...) // 関数の登録: 詳細は Func のページを参照
    vc[3] = wcfButton("a", NULL, "hoge");
    wcfViewSet(wcli, "a", vc, 4);
    wcfStatus wcfSync(wcfClient *wcli)
    送信用にセットしたデータをすべて送信キューに入れ、受信したデータを処理する
    Definition client.cc:72
    wcfStatus wcfFuncListen(wcfClient *wcli, const char *field, const wcfValType *arg_types, int arg_size, wcfValType return_type)
    関数呼び出しの待受を開始する
    Definition func.cc:314
    wcfViewComponent wcfNewLine(void)
    Definition view.cc:61
    wcfViewComponent wcfText(const char *text)
    Definition view.cc:59
    wcfStatus wcfViewSet(wcfClient *wcli, const char *field, const wcfViewComponent *components, int size)
    Viewを送信する
    Definition view.cc:155
    wcfViewComponent wcfButton(const char *text, const char *on_click_member, const char *on_click_field)
    Definition view.cc:63
    Viewの要素を表すstruct.
    Definition def_types.h:218

    example_view.png

  • JavaScript Client::view からViewオブジェクトを作り、 set()の引数に要素をまとめてセットして使います。

    wcli.view("a").set([
    "hello world\n",
    i, // i は適当な変数とか
    "\n",
    viewComponents.button("a", () => console.log("hello"))
    ]);

    example_view.png

  • Python Client.view からViewオブジェクトを作り、 View.add() などで要素を追加し、 最後にView.sync()をしてからClient.sync()をすることで送信されます。

    v = wcli.view("a")
    # v.init() ←オブジェクトvを新規に構築せず繰り返し使いまわす場合は必要
    v.add("hello world\n")
    v.add(i, "\n") # i は適当な変数とか
    v.add(webcface.components.button("a", lambda: print("hello")))
    v.sync()
    TemporalViewComponent button(std::string_view text, T &&func)
    buttonコンポーネント
    Definition components.h:615

    add() にはコンマ区切りで複数の要素を渡すこともできます(1つずつadd()するのと同じです)

    example_view.png

    with構文を使って with wcli.view("hoge") as v: などとするとwithを抜けるときに自動でv.sync()がされます。

    with wcli.view("a") as v:
    v.add(...)
    v.add(...)
    # v.sync() (自動で呼ばれる)

ViewComponent

Viewに追加する各種要素をViewComponentといいます。

  • C++ webcface::ViewComponents
    1.9 webcface::Components
    2.0 webcface::components 名前空間に定義されています。

    using namespace webcface::components;
    Definition components.h:380

    をすると便利かもしれません

    Note
    • namespace components はinlineなので、 webcface:: の名前空間でもアクセス可能です。
    • また以前のnamespace名もエイリアスになっておりどちらでもokです。

    各要素はそれぞれの関数から webcface::TemporalViewComponent または webcface::TemporalComponent のオブジェクトとして得られます。

    1.11 引数にView(コピーまたはconst参照)を取る関数オブジェクトをViewに渡すと、その場でその関数が呼び出されます。 複数のViewComponentを出力する処理をまとめて使いまわしたい場合に便利です。

    auto showNameAndValue(const std::string &name, int value) {
    return [=](const webcface::View &view) {
    view << name << " = " << value;
    };
    }
    webcface::View v = wcli.view("a");
    v << showNameAndValue("foo", 123) << std::endl; // v << "foo = 123";
    v.sync();
  • JavaScript JavaScriptでは viewComponents オブジェクト内にそれぞれの要素を表す関数があります
    import { viewComponents } from "webcface";
  • Python Pythonでは webcface.view_components 3.0 webcface.components モジュール内にそれぞれの要素を表す関数があります
    from webcface.components import *
    とすることもできます

text

文字列です。そのまま表示します。

  • C++ std::ostreamでフォーマット可能なデータはそのまま渡して文字列化できます。 View::add()関数, set()関数でも同様に文字列に変換されます。

    v.add("hello").add(123);
    v << "hello" << 123;
    const View & add(T &&rhs) const
    コンポーネントなどを追加
    Definition view.h:243

    文字列を直接渡す代わりに text(文字列) でViewComponentに変換すると、textColorなど後述のオプションを指定することもできるようになります。

    2.0 Viewに直接ワイド文字列を出力することはできませんが、text()の引数にはワイド文字列も使用可能です。

  • C wcfText, (2.0 wcfTextW) でテキストを指定します。
    vc[0] = wcfText("hello");
  • JavaScript string, number, boolean は文字列に変換されます。
    wcli.view("hoge").set([
    "hello",
    123,
    ]);
    文字列を直接渡す代わりに text(文字列) でViewComponentに変換すると、textColorなど後述のオプションを指定することもできるようになります。
    import { viewComponents, viewColor } from "webcface";
    wcli.view("hoge").set([
    viewComponents.text("hello", { textColor: viewColor.red }),
    123,
    ]);
  • Python str, int, float, bool はaddの引数に直接指定すると文字列に変換されます。

    v.add("hello").add(123)

    文字列を直接渡す代わりに text(文字列) でViewComponentに変換すると、text_colorなど後述のオプションを指定することもできるようになります。

    v.add(components.text("hello", text_color=webcface.ViewColor.RED))

    3.0 オプションはadd()の引数としても渡すことができます。

    v.add("hello", text_color=webcface.ViewColor.RED)

newLine

改行します。

  • C++ webcface::newLine() の他、std::endl"\n"でも改行できます。 \nは単体でなく文字列中にあってもそこで改行されます。
    v.add("hello\nhello");
    v.add("hello").add("\n").add("hello");
    v << "hello\nhello";
    v << "hello" << std::endl << "hello";
    using namespace webcface::Components;
    v.add(text("hello")).add(newLine()).add(text("hello"));
    v << text("hello") << newLine() << text("hello");
  • C wcfText に\nを渡すか、 wcfNewLine, (2.0 wcfNewLineW) で指定できます。 wcfTextの文字列の途中に\nがある場合もそこで改行されます

    vc[0] = wcfText("\n");
    vc[0] = wcfNewLine();
    Warning
    newLineには文字列を渡す機能はないですが、他の要素と型を合わせるためにwcfNewLineとwcfNewLineWを使い分ける必要があります
  • JavaScript newLine()の他"\n"でも改行できます。 \nは単体でなく文字列中にあってもそこで改行されます。
    wcli.view("hoge").set([
    "hello\nhello",
    viewComponents.newLine(),
    "hello",
    ]);
  • Python new_line() の他、"\n"でも改行できます。 \nは単体でなく文字列中にあってもそこで改行されます。
    v.add("hello\nhello");
    v.add("hello").add("\n").add("hello");
    v.add(text("hello")).add(new_line()).add(text("hello"));

button

ボタンを表示します。

クリック時の動作は、関数を登録済みのFuncオブジェクトかFuncListenerオブジェクトを指定するか、または関数を直接設定できます。

Note
別のMemberのFuncオブジェクトを渡すこともできます (ボタンを押すと別のMemberに登録されている関数が実行される)
Warning
2.5 3.0 buttonや、このあと説明するinputなど、インタラクティブな動作を伴う要素には id として一意な文字列を指定してください。 通常は指定しなくても動作しますが、 次の例のようにview内に要素が出現したり消滅したりするようなものを書いた場合 その切り替わりのタイミングで要素の内容がずれる場合があります。
auto v = wcli.view("a");
if(some_condition){
// some_conditionによって表示されたりされなかったりする
v << webcface::button(...);
}
v << webcface::button(...);
v.sync();
  • C++ Funcオブジェクト、 2.5 FuncListerオブジェクト の場合

    wcli.func("hoge").set(/*...*/);
    v << webcface::button("表示する文字列", wcli.func("hoge")).id("button1");
    // v.add(...) でも同様

    関数を直接渡す場合 (非表示のFuncとして登録され、他のFuncと同様に扱われます。 WebUIや他MemberからはFuncの存在は見えません)

    v << webcface::button("表示する文字列", [](){ /* ... */ }).id("button1");
  • C 関数の登録方法は Func を参照してください。 表示する文字列に加え登録したFuncのmember名と名前を wcfButton, (2.0 wcfButtonW) に指定します。 member名をNULLまたは空文字列にすると自分自身が登録した関数を指します。
    vc[0] = wcfButton("表示する文字列", NULL, "hoge");
  • JavaScript Funcオブジェクトの場合
    wcli.func("hoge").set(/* ... */);
    wcli.view("hoge").set([
    viewComponents.button("表示する文字列", wcli.func("hoge")),
    ]);
    関数を直接渡す場合 (WebUIや他MemberからはFuncの存在は見えません)
    wcli.view("hoge").set([
    viewComponents.button("表示する文字列", () => {/* ... */})
    ]);
  • Python Funcオブジェクト、FuncListenerオブジェクトの場合
    wcli.func("hoge").set(...)
    v.add(components.button("表示する文字列", wcli.func("hoge"), id="button1"))
    関数を直接渡す場合 (WebUIや他MemberからはFuncの存在は見えません)
    def hoge():
    pass
    v.add(components.button("表示する文字列", hoge, id="button1"));

input

Since
1.101.62.0

viewに入力欄を表示します。

  • textInput: 文字列入力
  • decimalInput: 小数入力
  • numberInput: 整数の入力
  • selectInput: リストから値を選択させる
  • toggleInput: クリックするたびに値が切り替わる
  • sliderInput: 数値を指定するスライダー
  • checkInput: チェックボックス

InputRef

  • C++ 入力された値にアクセスするため webcface::InputRef オブジェクトを作成し、inputにbindします。 そのInputRefオブジェクトをコピーまたは参照で別の関数などに渡すと、あとから値を取得することができます。

    static webcface::InputRef input_val;
    v << webcface::button("cout ",
    [=] { std::cout << input_val << std::endl; })
    .id("button1")
    << webcface::textInput("表示する文字列").bind(input_val).id("input1")
    << std::endl;
    名前を指定しないText
    Definition text.h:439
    TemporalViewComponent & id(std::string_view id)
    idを設定
    Definition component_view.cc:250
    TemporalViewComponent & bind(const InputRef &ref) &
    変更した値を格納するInputRefを設定
    Definition component_view.cc:302
    TemporalViewComponent textInput(std::string_view text="")
    Definition components.h:631
    Warning
    上の例ではinput_valをstatic変数にし寿命が切れないようにしていますが、 staticにできない場合(複数のviewで使い回す場合など)は次の例のようにviewの生成ごとにInputRefオブジェクトを生成・破棄しても動作はします。
    while (true){
    auto v = wcli.view("a");
    webcface::InputRef input_val;
    v << webcface::button("cout ",
    [=] { std::cout << input_val << std::endl; })
    .id("button1")
    << webcface::textInput("表示する文字列").bind(input_val).id("input1")
    << std::endl;
    // std::cout << "input_val = " << input_val.get(); この場合ここでは使えない
    v.sync();
    wcli.sync();
    }
    この場合はv.sync()の時に前周期のinput_valの内容が復元されるという挙動になります。 (したがってv.sync()より前では値が未初期化になります)

    1.11 InputRefの値は asStringRef(), asString(), asBool(), as<double>() で型を指定して取得できます。
    2.0 asWStringRef(), asWString(), asDouble(), asInt(), asLLong() も使えます。
    (std::string, double, bool などの型にキャストすることでも値を得られます。)
    (任意の型に対応したい場合は get()webcface::ValAdaptor 型として取得できます。)

    Note
    内部の実装では入力値を受け取りInputRefに値をセットする関数をonChangeにセットしています。 また、InputRefの値はText型のデータとしてviewを表示しているクライアントに送信されます。

  • JavaScript 入力された値にアクセスするため InputRef オブジェクトを作成し、inputにbindします。 そのInputRefオブジェクトを別の関数などに渡すと、あとから値を取得することができます。
    import { InputRef, viewComponents } from "webcface";
    const inputVal = new InputRef();
    setInterval(() => {
    wcli.view("hoge").set([
    viewComponents.button("cout", () => console.log(inputVal.get())),
    viewComponents.textInput("表示する文字列", { bind: inputVal }),
    ]);
    wcli.sync();
    }, 100);
    Warning
    viewを繰り返し送信するときInputRefオブジェクトは同じものを使いまわすのでも、 毎回新しいInputRefオブジェクトを生成するのでも、どちらでも動作します。
    import { InputRef, viewComponents } from "webcface";
    setInterval(() => {
    const inputVal = new InputRef(); // 毎回新しいInputRef
    wcli.view("hoge").set([
    viewComponents.button("cout", () => console.log(inputVal.get())), // ok
    viewComponents.textInput("表示する文字列", { bind: inputVal }),
    // inputVal.get(), // ここでは使えない
    ]);
    wcli.sync();
    }, 100);
    この場合はview.set()が実行される時に前周期のinputValの内容が復元されるという挙動になります。 (したがってv.set()の引数内ではinputValの値は未初期化になります)
    Note
    内部の実装では入力値を受け取りInputRefに値をセットする関数をonChangeにセットしています。 また、InputRefの値はText型のデータとしてviewを表示しているクライアントに送信されます。
  • Python 入力された値にアクセスするため InputRef オブジェクトを作成し、inputにbindします。 そのInputRefオブジェクトをコピーまたは参照で別の関数などに渡すと、あとから値を取得することができます。

    from webcface import InputRef
    input_val = InputRef()
    def print_val():
    print(str(input_val.get()))
    v.add(components.button("print", print_val, id="button1"))
    v.add(components.text_input("表示する文字列", bind=input_val, id="input1")
    Warning
    viewを繰り返し送信するときInputRefオブジェクトは同じものを使いまわすのでも、 毎回新しいInputRefオブジェクトを生成するのでも、どちらでも動作します。
    from webcface import InputRef
    while True:
    input_val = InputRef()
    def print_val():
    print(str(input_val.get()))
    with wcli.view("hoge") as v:
    v.add(components.button("print", print_val, id="button1"))
    v.add(components.text_input("表示する文字列", bind=input_val, id="input1")
    # print(input_val.get()) # ここでは使えない
    # v.sync()
    wcli.sync()
    この場合はview.sync()が実行される時に前周期のinput_valの内容が復元されるという挙動になります。 (したがってv.sync()より前ではinput_valの値は未初期化になります)
    Note
    内部の実装では入力値を受け取りInputRefに値をセットする関数をonChangeにセットしています。 また、InputRefの値はText型のデータとしてviewを表示しているクライアントに送信されます。

onChange

  • C++ onChange() で値が入力されたときに実行する関数を設定でき、こちらでも値が取得できます。 buttonに渡す関数と同様、関数オブジェクト、Funcオブジェクト、FuncListenerオブジェクトが使用できます。

    v << webcface::textInput("表示する文字列").id("input1").onChange([](std::string val) {
    std::cout << "input changed: " << val << std::endl;
    });
    TemporalViewComponent & onChange(T func) &
    値が変化した時に実行される関数を設定
    Definition component_view.h:429
    Note
    bindとonChangeを両方設定することはできません。

  • JavaScript onChange で値が入力されたときに実行する関数を設定でき、こちらでも値が取得できます。 buttonに渡す関数と同様、関数、Funcオブジェクトが使用できます。

    viewComponents.textInput("表示する文字列", {
    onChange: (val: string | number | boolean) => console.log(val),
    })
    Note
    bindとonChangeを両方設定することはできません。

  • Python on_change で値が入力されたときに実行する関数を設定でき、こちらでも値が取得できます。 buttonに渡す関数と同様、関数、ラムダ式、またはFuncオブジェクト、FuncListenerオブジェクトが使用できます。

    components.text_input("表示する文字列", id="input1", on_change=...)
    Note
    bindとonChangeを両方設定することはできません。

オプション

各ViewComponentには以下のオプションを指定することができます。 (要素の種類によっては効果がないものもあります)

  • textColor: 文字の色を変更します。
    • WebUIではデフォルトは黒です
  • bgColor: 背景色を変更します。
    • WebUIではデフォルトは緑です
  • 各種inputに指定できるオプション (FuncのArgオプションと同様です。)
    • init: 初期値
    • min: 最小値, max: 最大値 (decimalInput, numberInput, sliderInputのみ)
    • min: 最小文字数, max: 最大文字数 (textInputのみ)
    • step: 刻み幅 (numberInput, sliderInputのみ)
    • option: 選択肢 (selectInput, toggleInput)
Note
webcface-tuiでは文字色と背景色に指定した白と黒がそれぞれ反転して表示されます。
  • C++ button(...).textColor(...) などのようにメソッドチェーンすることで各要素にオプションを設定できます。 詳細は webcface::TemporalViewComponent のリファレンスを参照してください。

    色は webcface::ViewColor のenumで指定します。

  • C wcfViewComponent 構造体のメンバーでオプションを指定することができます。

    vc[0] = wcfText("hello world\n");
    vc[0].text_color = WCF_COLOR_RED;
    @ WCF_COLOR_RED
    Definition def_types.h:200
  • JavaScript button("text", { textColor: ... }) などのように、オプションはそれぞれ関数の引数にオブジェクトで渡すことができます。
  • Python button("text", text_color=...) などのように、それぞれ関数のキーワード引数でオプションを設定できます。

    3.0 add() の引数にキーワード引数を追加しても同様に要素にオプションが追加されます。

受信

ViewデータはWebUIに表示するだけでなく、ValueやTextと同様プログラムから受信することもできます。 (これを使うのはViewを表示するアプリを作る場合などですかね)

  • C++ Member::view() でViewクラスのオブジェクトが得られ、 View::tryGet(), View::get() で受信したViewデータを取得できます。

    Viewデータは webcface::ViewComponent のリストとして得られ、 ViewComponentオブジェクトから各種プロパティを取得できます。

    例えばfooというクライアントのhogeという名前のデータを取得したい場合は次のようにします。

    std::optional<std::vector<ViewComponent>> hoge = wcli.member("foo").view("hoge").tryGet();
    • 値をまだ受信していない場合 tryGet() はstd::nulloptを返し、そのデータのリクエストをサーバーに送ります。
      • リクエストは 次にClient::sync()したときに 1.2自動的に別スレッドで送信されます。
      • そのデータを受信した後(4-1. Clientを参照)、再度tryGet()することで値が得られます。
    • View::get() はstd::nulloptの代わりに空のvectorを返します。

    1.7 View::request() で明示的にリクエストを送信することもできます。

  • C

    Since
    1.7

    wcfViewGet, (2.0 wcfViewGetW) で wcfViewComponent, (2.0 wcfViewComponentW) の配列が得られます。

    取得した配列は不要になったら wcfDestroy で破棄してください。

  • JavaScript Member.view() でViewクラスのオブジェクトが得られ、 View.tryGet(), View.get() で受信したViewデータを取得できます。

    Viewデータは ViewComponent のリストとして得られ、 ViewComponentオブジェクトから各種プロパティを取得できます。

    例えばfooというクライアントのhogeという名前のデータを取得したい場合は次のようにします。

    const hoge: ViewComponent[] | null = wcli.member("foo").view("hoge").tryGet();
    • 値を受信していない場合 tryGet() はnullを返し、そのデータのリクエストをサーバーに送ります。
      • リクエストは 次にClient.sync()したときに 1.1自動的に別スレッドで送信されます。
      • そのデータを受信した後(4-1. Clientを参照)、再度tryGet()することで値が得られます。
    • get() はnullの代わりに空のリストを返します。

    1.1 View.request()で明示的にリクエストを送信することもできます。

  • Python Member.view() でViewクラスのオブジェクトが得られ、 View.tryGet(), View.get() で受信したViewデータを取得できます。

    Viewデータは webcface.ViewComponent のリストとして得られ、 ViewComponentオブジェクトから各種プロパティを取得できます。

    例えばfooというクライアントのhogeという名前のデータを取得したい場合は次のようにします。

    hoge = wcli.member("foo").view("hoge").try_get()
    • 値を受信していない場合 try_get() はNoneを返し、そのデータのリクエストをサーバーに送ります。
      • そのデータを受信した後(4-1. Clientを参照)、再度try_get()することで値が得られます。
    • get() はNoneの代わりに空のリストを返します。

    View.request()で明示的にリクエストを送信することもできます。

onClick

ViewComponent::onClick() でボタン要素のクリック時に実行するべき関数がFuncオブジェクトとして取得できます。 したがって、ボタンを表示し、クリックされたときにonClick().runAsync()などとすることでそのボタンを動作させられます。

onChangeとbind

1.10 1.6 2.0

各種Input要素の現在の値は ViewComponent::bind() で Textオブジェクトとして 2.0 2.0 Variant オブジェクトとして取得できます。 したがってbind()の値をInputの初期値として使用すればよいです。

Inputの値を変更する際は、(view送信側がbindを設定したかonChangeを設定したかに関わらず) ViewComponent::onChange() を使います。 引数に変化後の値を渡してonChange().runAsync("変化後の値")などとすることで onChangeに設定された関数を実行すると同時にbindの値も変更されます。

id

1.10 1.6 3.0

ViewComponent::id() で各要素に割り振られたid(文字列)を取得できます。 このidはそのview内で一意で、(buttonやInputの総数や順序が変わらなければ) 同じbutton、同じinputには常に同じidが振られます。

時刻

View::time() でその値が送信されたとき(そのMemberがsync()したとき)の時刻が得られます。
1.7 1.6 Member::syncTime() に統一しました。詳細は 5-1. Value を参照

Entry

Valueと同様、データ自体を受信しなくてもデータが存在するかどうかは取得することができます。 使い方は Value と同様なのでそちらを参照してください

Event

受信したデータが変化したときにコールバックを呼び出すことができます。 コールバックを設定することでもその値はリクエストされます。

また、データが変化したどうかに関わらずそのMemberがsync()したときにコールバックを呼び出したい場合は Member::onSync() が使えます

使い方は Value と同様なのでそちらを参照してください

Previous Next
5-3. Func 5-5. Log