WebCFace 2.9.0
Web-based Communication Framework & Dashboard-like UI
Loading...
Searching...
No Matches
4-3. Field

Since
1.11 1.10 3.1
See also

WebCFaceで送受信されるそれぞれのデータを Field と呼びます。 データ型としては Value, Text, Func, View, Log, Canvas2D, Image, Canvas3D, RobotModel が用意されており、詳細はそれぞれのページで説明しています。

このページには各データ型に共通の情報を載せています。

名前の指定

  • C++ Client::child() または Member::child() に名前を指定することで Field オブジェクトを取得できます。

    webcface::Field hoge = wcli.child("hoge"); // 自分の hoge という名前のデータ
    webcface::Field fuga = wcli.member("foo").child("fuga"); // foo というメンバーの fuga というデータ
    ClientDataの参照とメンバ名とデータ名を持つクラス
    Definition field.h:71
    Member_ member() const
    Memberを返す
    Definition field.h:107
    Field child(const SharedString &field) const
    Definition field.cc:42

    または ["名前"] でも同様に取得できます。

    webcface::Field hoge = wcli["hoge"];
    webcface::Field fuga = wcli.member("foo")["fuga"];
    // ↑ wcli["foo"]["fuga"] は別の意味になるので注意
  • JavaScript Client.child() または Member.child() に名前を指定することで Field オブジェクトを取得できます。

    const hoge = wcli.child("hoge"); // 自分の hoge という名前のデータ
    const fuga = wcli.member("foo").child("fuga"); // foo というメンバーの fuga というデータ
  • Python Client.child() または Member.child() に名前を指定することで Field オブジェクトを取得できます。

    hoge = wcli.child("hoge") # 自分の hoge という名前のデータ
    fuga = wcli.member("foo").child("fuga") # foo というメンバーの fuga というデータ

データ型

Field型のままではデータの送信や受信はできません。 各種データ型のメソッドを使う必要があります。

  • C++ 例えば child() の代わりに value() でアクセスすると Value 型が返ります。 他の型についても同様です。

    webcface::Value hoge = wcli.value("hoge"); // 自分の hoge という名前のValue型データ
    webcface::Value fuga = wcli.member("foo").value("fuga"); // foo というメンバーの fuga というValue型データ
    実数値またはその配列の送受信データを表すクラス
    Definition value.h:59
    Value_ value(std::string_view field="") const
    Definition field.h:186

    または、Fieldに対して .value() でもValue型に変換できます。

    webcface::Value hoge = wcli.field("hoge").value();
    // webcface::Value hoge = wcli["hoge"].value(); でも同じ
    webcface::Value fuga = wcli.member("foo").field("fuga");
    // webcface::Value fuga = wcli.member("foo")["fuga"].value(); でも同じ
    Member_ member() const
    Memberを返す
    Definition field.h:107
  • JavaScript 例えば child() の代わりに value() でアクセスすると Value 型が返ります。 他の型についても同様です。

    const hoge = wcli.value("hoge"); // 自分の hoge という名前のValue型データ
    const fuga = wcli.member("foo").value("fuga"); // foo というメンバーの fuga というValue型データ

    または、Fieldに対して .value() でもValue型に変換できます。

    const hoge = wcli.field("hoge").value();
    const fuga = wcli.member("foo").field("fuga");
  • Python 例えば child() の代わりに value() でアクセスすると Value 型が返ります。 他の型についても同様です。

    hoge = wcli.value("hoge") # 自分の hoge という名前のValue型データ
    fuga = wcli.member("foo").value("fuga") # foo というメンバーの fuga というValue型データ

    または、Fieldに対して .value() でもValue型に変換できます。

    hoge = wcli.field("hoge").value()
    fuga = wcli.member("foo").field("fuga")

グループ化

Fieldの名前を半角ピリオドで区切ると、WebUI上ではフォルダアイコンで表示されグループ化されて表示されます。

value_child

Note
ROSのTopicではPointやTransformなど目的に応じてさまざまな型が用意されていますが、 WebCFaceではそういう場合はValueを複数用意して送信することを想定しています。
  • C++

    wcli.child("pos.x");
    wcli.child("pos.y");
    wcli.child("pos.z");

    のように名前を指定する代わりに、 Field::child() または 各種データ型::child() でもグループ内のデータを指定できます。

    webcface::Field pos = wcli.child("pos");
    pos.child("x"); // => "pos.x"
    pos.child("y"); // => "pos.y"
    pos.child("z"); // => "pos.z"
    // Value型の pos に対して .child("x") をした場合は、
    // Value型の pos.x データになる

    または ["名前"] でも同様です。

    webcface::Field pos = wcli["pos"];
    pos["x"]; // => "pos.x"
    pos["y"]; // => "pos.y"
    pos["z"]; // => "pos.z"
    Deprecated:
    1.11 Value::child() (または[])の引数が数値(または"1"のような文字列でも同じ)の場合、 グループ化ではなく配列としての値代入が優先されます。 (これはValue型のみの特別な処理です。)
    ただし以下のような場合は通常の文字列と同様に処理します。
    wcli.value("data")[0]["a"] = 1; // value("data.0.a") = 1

    2.8 child() や [] 内に数値を入れられる仕様はdeprecatedです。 (Value型の配列アクセスを除く)

  • JavaScript
    wcli.child("pos.x");
    wcli.child("pos.y");
    wcli.child("pos.z");
    のように名前を指定する代わりに、 Field::child() または 各種データ型::child() でもグループ内のデータを指定できます。
    const pos = wcli.child("pos");
    pos.child("x"); // => "pos.x"
    pos.child("y"); // => "pos.y"
    pos.child("z"); // => "pos.z"
    // Value型の pos に対して .child("x") をした場合は、
    // Value型の pos.x データになる
  • Python
    wcli.child("pos.x")
    wcli.child("pos.y")
    wcli.child("pos.z")
    のように名前を指定する代わりに、 Field::child() または 各種データ型::child() でもグループ内のデータを指定できます。
    pos = wcli.child("pos")
    pos.child("x") # => "pos.x"
    pos.child("y") # => "pos.y"
    pos.child("z") # => "pos.z"
    # Value型の pos に対して .child("x") をした場合は、
    # Value型の pos.x データになる

名前などの操作

  • C++ Field::member() でそのFieldが所属するMemberを取得できます。

    assert(wcli.child("pos.x").member().name() == wcli.name());
    assert(wcli.member("foo").child("pos.x").member().name() == "foo");

    Field::name(), (2.0 nameW()) で名前を取得できます。

    assert(wcli.child("pos.x").name() == "pos.x");

    child() とは逆に、Field::parent() でグループのField (nameの最後のピリオドの前までのField) を取得できます。 cpp assert(wcli.child("pos.x").parent().name() == "pos");

    Field::lastName() (2.0 lastNameW()) でピリオドで区切られた最後の部分を取り出すことができます。 cpp assert(wcli.child("pos.x").lastName() == "x");

  • JavaScript Field.member でそのFieldが所属するMemberを取得できます。

    assert(wcli.child("pos.x").member.name == wcli.name);
    assert(wcli.member("foo").child("pos.x").member.name == "foo");

    Field.name で名前を取得できます。

    assert(wcli.child("pos.x").name == "pos.x");
  • Python Field.member でそのFieldが所属するMemberを取得できます。

    assert wcli.child("pos.x").member.name == wcli.name
    assert wcli.member("foo").child("pos.x").member.name == "foo"

    Field.name で名前を取得できます。

    assert wcli.child("pos.x").name == "pos.x"

基本的な通信の仕様

クライアントが送信したデータは、サーバーを経由して別のクライアントに送られます。 (Valueに限らず、これ以降説明する他のデータ型のfieldについても同様です。)

pub-sub

サーバー→クライアント間では、初期状態ではデータは送信されず、 クライアントがリクエストを送って初めてサーバーからデータが順次送られてくるようになります。

基本的にクライアント→サーバーの方向にはすべてのデータが送信されるのに対し、サーバー→クライアントの方向には必要なデータのみを送信する設計になっていますが、これは前者はlocalhost(サーバーとクライアントが同じPC)のみで、後者はWi-FiやLANでも通信することを想定したものです。 (通信量は増えますがクライアント→サーバーのデータ送信をWi-FiやLAN経由で行うことも可能です)

送信

各種データ型のメソッド (Value.set() や View.sync() など) を使って送信するデータをセットし、 その後 Client::sync() をすることで実際にデータが送信されます。

Client::sync() については 4-1. Client の送受信の章を参照してください。

1.8 1.4.1 1.1.2 クライアント→サーバー間では、同じデータを繰り返し送信した場合は2回目以降はデータを送信しないことで通信量を削減しています。

受信

各種データ型のrequestメソッド (Value.request() や View.request() など) を使ってデータをリクエストできます。 (リクエストの送信は Client::sync() とは非同期に行われます。)

データが一度リクエストされた状態であればそれ以降 Client::sync() 時にデータが受信され、 各種データ型のメソッド (Value.tryGet(), get() など) でデータを取得できます。

また、データを一度もリクエストしていない状態で teyGet(), get() などの関数を呼んでデータを取得しようとした際にも自動的にリクエストが送られます。

時刻

  • C++ Value::time() でその値が送信されたとき(そのMemberがsync()で送信したとき)の時刻が得られます。
    1.7 Member::syncTime() に変更 (Textなど他のデータの送信時刻と共通です)
  • C
    Since
    2.0
    wcfMemberSyncTime() でその値が送信されたとき(そのMemberがsync()で送信したとき)の時刻が得られます。 (Textなど他のデータの送信時刻と共通です)
  • JavaScript Value.time() でその値が送信されたとき(そのMemberがsync()で送信したとき)の時刻が得られます。
    1.6 Member.syncTime() に変更 (Textなど他のデータの送信時刻と共通です)
  • Python Member.sync_time() でその値が送信されたとき(そのMemberがsync()で送信したとき)の時刻が得られます。 (Textなど他のデータの送信時刻と共通です)

Entry

データが送信された際、 Entry としてそのデータの存在が全クライアントに通知されます。 受信したEntryはリクエスト状態とは関係なく取得可能です。

Note
(serverが1.10以降の場合) データの名前を半角ピリオドから始めると、Entryが他クライアントに送信されなくなります。 (WebUI上に表示することなくデータを送ることができます)
Warning
半角ピリオド2つから始まる名前はwebcface内部の処理で利用する場合があるので使用しないでください。
  • C++ 例えば Member::values() で 1.6 Member::valueEntries() でそのMemberが送信しているvalueのリストが得られます。

    Text, Func, View など他のデータ型に関しても同様に textEntries(), funcEntries(), viewEntries() などで取得できます。

    for(const webcface::Value &v: wcli.member("foo").valueEntries()){
    // ...
    }

    2.1 Value::exists() でそのデータが送信されているかどうかを確認できます。 tryGet() と違い、データそのものを受信するリクエストは送られません。 他のデータ型に関しても同様に Text::exists(), Func::exists(), View::exists() などが使えます。

    1.11 Field::valueEntries() でそのfield以下のvalueのみが得られます (Textなど他の型についても同様)

    std::vector<webcface::Value> values = wcli.member("foo").field("pos").valueEntries();
    // pos.x, pos.y などのvalueが得られる

    2.6 Field::childrenRecurse() ですべてのデータ型についてそのfield以下に存在するentryを確認できます。 cpp std::vector<webcface::Field> values = wcli.member("foo").field("pos").childrenRecurse(); // pos.x, pos.y などのデータ(型に関係なく)のリストが得られる また、Field::children() では次のピリオドで区切られているグループを取得できます。 cpp std::vector<webcface::Field> values = wcli.member("foo").field("pos").children(); // 例えば、 pos.x, pos.y, pos.vel.x, pos.vel.y が存在した場合、 // pos.x, pos.y, pos.vel が得られる Field::hasChildren() でそのfield以下にデータが存在するかを確認できます。

  • C

    Since
    2.0

    wcfValueEntryList, wcfValueEntryListW にchar*の配列とサイズを渡すと、valueの一覧を取得できます。

    const char *value_list[10];
    int actual_value_num;
    wcfValueEntryList(wcli, "foo", value_list, 10, &actual_value_num);
    wcfStatus wcfValueEntryList(wcfClient *wcli, const char *member, const char **list, int size, int *field_num)
    memberが公開しているValueのリストを得る
    Definition member.cc:139

    それぞれのvalue名の文字列は、 wcfClose() するまではfreeされません。

    Text, Func, View など他のデータ型に関しても同様に wcfTextEntryList(), wcfFuncEntryList(), wcfViewEntryList() などで取得できます。

  • JavaScript Member.values() 1.10 Member.valueEntries() でそのMemberが送信しているvalueのリストが得られます

    for(const v of wcli.member("foo").values()){
    // ...
    }

    Text, Func, View など他のデータ型に関しても同様に textEntries(), funcEntries(), viewEntries() などで取得できます。

    1.8 Value.exists() でそのデータが送信されているかどうかを確認できます。 tryGet() と違い、データそのものを受信するリクエストは送られません。 他のデータ型に関しても同様に Text.exists(), Func.exists(), View.exists() などが使えます。

    1.10 Field.valueEntries() でそのfield以下のvalueのみが得られます (Textなど他の型についても同様)

    const values = wcli.member("foo").field("pos").valueEntries();
    // pos.x, pos.y などのvalueが得られる

    1.10 Field.childrenRecurse() ですべてのデータ型についてそのfield以下に存在するentryを確認できます。 ts const values = wcli.member("foo").field("pos").childrenRecurse(); // pos.x, pos.y などのデータ(型に関係なく)のリストが得られる また、Field.children() では次のピリオドで区切られているグループを取得できます。 ts const values = wcli.member("foo").field("pos").children(); // 例えば、 pos.x, pos.y, pos.vel.x, pos.vel.y が存在した場合、 // pos.x, pos.y, pos.vel が得られる Field.hasChildren() でそのfield以下にデータが存在するかを確認できます。

  • Python Member.values() 1.1 Member.value_entries() でそのMemberが送信しているvalueのリストが得られます

    for v in wcli.member("foo").value_entries():
    # ...

    Text, Func, View など他のデータ型に関しても同様に text_entries(), func_entries(), view_entries() などで取得できます。

    2.0 Value.exists() でそのデータが送信されているかどうかを確認できます。 try_get() と違い、データそのものを受信するリクエストは送られません。 他のデータ型に関しても同様に Text.exists(), Func.exists(), View.exists() などが使えます。

    3.1 Field.value_entries() でそのfield以下のvalueのみが得られます (Textなど他の型についても同様)

    values = wcli.member("foo").field("pos").value_entries()
    # pos.x, pos.y などのvalueが得られる

    3.1 Field.children(recurse=True) ですべてのデータ型についてそのfield以下に存在するentryを確認できます。 python values = wcli.member("foo").field("pos").children(recurse=True) @section autotoc_md78 pos.x, pos.y などのデータ(型に関係なく)のリストが得られる また、Field.children(recurse=False) では次のピリオドで区切られているグループを取得できます。 python values = wcli.member("foo").field("pos").children(recurse=False); @section autotoc_md79 例えば、 pos.x, pos.y, pos.vel.x, pos.vel.y が存在した場合、 @section autotoc_md80 pos.x, pos.y, pos.vel が得られる Field.has_children() でそのfield以下にデータが存在するかを確認できます。

Entry イベント

他のメンバーが新しくデータを追加したときに呼び出されるコールバックを設定できます。 ValueEntry, TextEntry など各データ型にそれぞれあります。

イベントの詳細な使い方はMemberEntryと同様です(Member のページを参照してください)。 このクライアントが接続する前から存在したデータについては start(), waitConnection() 時に一度に送られるので、 コールバックの設定はstart()より前に行うと良いです。

ValueEntryではデータの存在を知ることしかできません。 データの内容を取得するにはコールバックの中で改めてget()やrequest()を呼ぶか、 後述のValueChangeイベントを使ってください。

  • C++ 2.0 Member::onValueEntry() でコールバックを設定できます。 新しく追加されたValueの情報が引数に渡されます。

    wcli.member("foo").onValueEntry([](webcface::Value v){ /* ... */ });

    ver1.11以前では .onValueEntry().appendListener(...)

    他のデータ型に関しても同様に onTextEntry(), onFuncEntry(), onViewEntry() などが使えます。

    Note
    • コールバックを設定する前から存在したデータについてはコールバックは呼び出されません。
    • 2.0 Client::waitConnection()は接続時にサーバーに存在するデータすべてについてコールバックを呼んでからreturnします。
      • そのため、すべてのデータに対してコールバックが呼ばれるようにしたい場合は、 Member名がわかっていれば初回の Client::sync() Client::start() または waitConnection() 前に設定してください。
      • すべてのメンバーのすべてのデータに対してコールバックが呼ばれるようにしたい場合は、 Client::onMemberEntry() イベントのコールバックの中で各種イベントを設定すればよいです。

  • C

    Since
    2.0

    wcfValueEntryEvent, wcfValueEntryEventW で引数に const char * 2つと void * をとる関数ポインタをコールバックとして設定できます。
    新しく追加されたValueの名前が引数に渡されます。 void*引数には登録時に任意のデータのポインタを渡すことができます。(使用しない場合はNULLでよいです。)

    void callback_value_entry(const char *member_name, const char *value_name, void *user_data_p) {
    // member_name is "foo"
    struct UserData *user_data = (struct UserData *)user_data_p;
    // ...
    }
    struct UserData user_data = {...};
    wcfValueEntryEvent(wcli, "foo", callback_value_entry, &user_data);
    wcfStatus wcfValueEntryEvent(wcfClient *wcli, const char *member, wcfEventCallback2 callback, void *user_data)
    Valueが追加された時のイベント
    Definition member.cc:172

    他のデータ型に関しても同様に wcfTextEntryEvent(), wcfFuncEntryEvent(), wcfViewEntryEvent() などが使えます。

    Note
    • コールバックを設定する前から存在したデータについてはコールバックは呼び出されません。
    • wcfWaitConnection()は接続時にサーバーに存在するデータすべてについてコールバックを呼んでからreturnします。
      • そのため、すべてのデータに対してコールバックが呼ばれるようにしたい場合は、 Member名がわかっていれば wcfStart() または wcfWaitConnection() 前に設定してください。
      • すべてのメンバーのすべてのデータに対してコールバックが呼ばれるようにしたい場合は、 MemberEntryイベントのコールバックの中で各種イベントを設定すればよいです。

  • JavaScript Member.onValueEntry でコールバックを設定できます。 新しく追加されたValueの情報が引数に渡されます。

    import { Value } from "webcface";
    wcli.member("foo").onValueEntry.on((v: Value) => { /* ... */ });

    他のデータ型に関しても同様に onTextEntry, onFuncEntry, onViewEntry などが使えます。

    Note
    • コールバックを設定する前から存在したデータについてはコールバックは呼び出されません。
    • すべてのデータに対してコールバックが呼ばれるようにしたい場合は、 Member名がわかっていれば Client.start() 前に設定してください。
    • すべてのメンバーのすべてのデータに対してコールバックが呼ばれるようにしたい場合は、 Client.onMemberEntry イベントのコールバックの中で各種イベントを設定すればよいです。

  • Python Member.on_value_entry() でコールバックを設定できます。 新しく追加されたValueの情報が引数に渡されます。

    def value_entry(v: webcface.Value):
    pass
    wcli.member("foo").on_value_entry(value_entry)
    • ver1.1以前では on_value_entry.connect(...)
    • 他のデータ型に関しても同様に on_text_entry(), on_func_entry(), on_view_entry() などが使えます。
    • on_member_entryと同様、デコレータにすることもできます。
    Note
    • コールバックを設定する前から存在したデータについてはコールバックは呼び出されません。
    • 2.0 Client.wait_connection()は接続時にサーバーに存在するデータすべてについてコールバックを呼んでからreturnします。
    • すべてのデータに対してコールバックが呼ばれるようにしたい場合は、 Member名がわかっていればClient.start() または wait_connection() 前に設定してください。
    • すべてのメンバーのすべてのデータに対してコールバックが呼ばれるようにしたい場合は、 Client.on_member_entry() イベントのコールバックの中で各種イベントを設定すればよいです。

Change イベント, Sync イベント

受信したデータが変化したときにコールバックを呼び出すことができます。 Change イベントにコールバックを設定するとget()やrequest()を呼ばなくても自動的にその値がリクエストされます。

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

イベントの詳細な使い方はonMemberEntryと同様です(Member のページを参照してください)。

  • C++ 2.0 Value::onChange(), Member::onSync() でコールバックを設定できます。 他のデータ型についても同様です。

    引数にはそれぞれそのValue自身,Member自身が渡されます。 (キャプチャでも同じことができるのでなくてもよい)

    wcli.member("foo").value("hoge").onChange([](webcface::Value v){ /* ... */ });
    wcli.member("foo").onSync([](webcface::Member m){ /* ... */ });
    Memberを指すクラス
    Definition member.h:23
    • ver1.11以前は value("hoge").appendListener(...), member("foo").onSync().appendListener(...) です
    • 1.7 引数を持たない関数もイベントのコールバックに設定可能です。
      wcli.member("foo").value("hoge").onChange([](){ /* ... */ });
      wcli.member("foo").onSync([](){ /* ... */ });
      (ver1.11以前は appendListener())

    すべてのデータを受信したい場合は ValueEntry イベントの中でonChangeを設定すると可能です。

    wcli.onMemberEntry([](webcface::Member m){
    // ...
    });
    });
    });
    const Member & onValueEntry(std::function< void(Value)> callback) const
    valueが追加された時のイベント
    Definition member.cc:53
    const Value & onChange(std::function< void(Value)> callback) const
    値が変化したときに呼び出されるコールバックを設定
    Definition value.cc:56
  • C

    Since
    2.0

    wcfValueChangeEvent, wcfValueChangeEventW で引数に const char * 2つと void * をとる関数ポインタをコールバックとして設定できます。 void*引数には登録時に任意のデータのポインタを渡すことができます。(使用しない場合はNULLでよいです。)

    他のデータ型についても同様です。

    void callback_value_change(const char *member_name, const char *value_name, void *user_data_p) {
    // member_name is "foo", value_name is "hoge"
    // struct UserData *user_data = (struct UserData *)user_data_p;
    // ...
    double value[5];
    int size;
    wcfValueGetVecD(wcli, member_name, value_name, value, 5, &size);
    }
    struct UserData user_data = {...};
    wcfValueChangeEvent(wcli, "foo", "hoge", callback_value_change, &user_data);
    wcfStatus wcfValueGetVecD(wcfClient *wcli, const char *member, const char *field, double *values, int size, int *recv_size)
    値を受信する
    Definition value.cc:125
    wcfStatus wcfValueChangeEvent(wcfClient *wcli, const char *member, const char *field, wcfEventCallback2 callback, void *user_data)
    Valueが変化した時のイベント
    Definition value.cc:143
  • JavaScript Value.on(), Member.onSync.on() などでコールバックを設定できます。 他のデータ型についても同様です。

    引数にはそれぞれそのValue自身,Member自身が渡されます。 (なくてもよい)

    import { Member, Value } from "webcface";
    wcli.member("foo").value("hoge").on((v: Value) => { /* ... */ });
    wcli.member("foo").onSync.on((m: Member) => { /* ... */ });

    例えば全Memberの全Valueデータを受信するには

    wcli.onMemberEntry.on((m: Member) => {
    m.onValueEntry.on((v: Value) => {
    v.on((v: Value) => {
    // ...
    });
    });
    });

    のようにすると可能です。

  • Python 2.0 Value.on_change(), Member.on_sync() でコールバックを設定できます。 他のデータ型についても同様です。

    引数にはそれぞれそのValue自身,Member自身が渡されます。

    def value_change(v: webcface.Value):
    pass
    wcli.member("foo").value("hoge").on_change(value_change)
    def synced(m: webcface.Member):
    pass
    wcli.member("foo").on_sync(synced)

    すべてのデータを受信したい場合は ValueEntry イベントの中でonChangeを設定すると可能です。

    @wcli.on_member_entry
    def member_entry(m: Member):
    @m.on_value_entry
    def value_entry(v: Value):
    @v.on_change
    def on_change(v: Value):
    pass
Python 〜ver1.1の仕様

pythonでは Value.signal プロパティがこのイベントのsignalを返します。

def value_change(v: webcface.Value):
pass
wcli.member("foo").value("hoge").signal.connect(value_change)
def synced(m: webcface.Member):
pass
wcli.member("foo").on_sync.connect(synced)

Previous Next
4-2. Member 5-1. Value