- 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で改行もできます。
例
v << "hello world" << std::endl;
v << i << std::endl;
v <<
webcface::button(
"a", [] { std::cout <<
"hello" << std::endl; }) << std::endl;
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
- Warning
- 2.0 ワイド文字列を出力したい場合はostreamに直接渡すのではなく Component::text を使う必要があります。 (後述)
C++ではViewのデストラクタでも自動的にView.sync()が呼ばれます。
{
v << ...;
v << ...;
}
wcli.sync();
- Note
- 1.2 Viewオブジェクトをコピーした場合、Viewオブジェクトの内容はコピーされるのではなく共有され、そのすべてのコピーが破棄されるまでsync()は呼ばれません。
C
- Since
- 1.7
wcfViewComponent, (2.0 wcfViewComponentW) の配列を wcfViewSet, (2.0 wcfViewSetW) に指定することで送信されます。
例
char buf[10];
sprintf(buf, "%d", i);
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
JavaScript Client::view からViewオブジェクトを作り、 set()の引数に要素をまとめてセットして使います。
例
wcli.view("a").set([
"hello world\n",
i, // i は適当な変数とか
"\n",
viewComponents.button("a", () => console.log("hello"))
]);
Python Client.view からViewオブジェクトを作り、 View.add() などで要素を追加し、 最後にView.sync()をしてからClient.sync()をすることで送信されます。
例
v = wcli.view("a")
v.add("hello world\n")
v.add(i, "\n")
v.sync()
TemporalViewComponent button(std::string_view text, T &&func)
buttonコンポーネント
Definition components.h:615
add() にはコンマ区切りで複数の要素を渡すこともできます(1つずつadd()するのと同じです)
with構文を使って with wcli.view("hoge") as v:
などとするとwithを抜けるときに自動でv.sync()がされます。
with wcli.view("a") as v:
v.add(...)
v.add(...)
ViewComponent
Viewに追加する各種要素をViewComponentといいます。
C++ webcface::ViewComponents
1.9 webcface::Components
2.0 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) {
view << name << " = " << value;
};
}
v << showNameAndValue("foo", 123) << std::endl;
- JavaScript JavaScriptでは
viewComponents
オブジェクト内にそれぞれの要素を表す関数があります import { viewComponents } from "webcface";
- Python Pythonでは
webcface.view_components
3.0 webcface.components
モジュール内にそれぞれの要素を表す関数があります とすることもできます
text
文字列です。そのまま表示します。
C++ std::ostreamでフォーマット可能なデータはそのまま渡して文字列化できます。 View::add()関数, set()関数でも同様に文字列に変換されます。
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) でテキストを指定します。
- 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の引数に直接指定すると文字列に変換されます。
文字列を直接渡す代わりに 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
改行します。
button
ボタンを表示します。
クリック時の動作は、関数を登録済みのFuncオブジェクトかFuncListenerオブジェクトを指定するか、または関数を直接設定できます。
- Note
- 別のMemberのFuncオブジェクトを渡すこともできます (ボタンを押すと別のMemberに登録されている関数が実行される)
- Warning
- 2.5 3.0 buttonや、このあと説明するinputなど、インタラクティブな動作を伴う要素には id として一意な文字列を指定してください。 通常は指定しなくても動作しますが、 次の例のようにview内に要素が出現したり消滅したりするようなものを書いた場合 その切り替わりのタイミングで要素の内容がずれる場合があります。
input
- Since
- 1.101.62.0
viewに入力欄を表示します。
- textInput: 文字列入力
- decimalInput: 小数入力
- numberInput: 整数の入力
- selectInput: リストから値を選択させる
- toggleInput: クリックするたびに値が切り替わる
- sliderInput: 数値を指定するスライダー
- checkInput: チェックボックス
InputRef
C++ 入力された値にアクセスするため webcface::InputRef オブジェクトを作成し、inputにbindします。 そのInputRefオブジェクトをコピーまたは参照で別の関数などに渡すと、あとから値を取得することができます。
[=] { std::cout << input_val << std::endl; })
.id("button1")
<< std::endl;
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){
[=] { std::cout << input_val << std::endl; })
.id("button1")
<< std::endl;
}
この場合は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(() => {
wcli.view("hoge").set([
viewComponents.button("cout", () => console.log(inputVal.get())),
viewComponents.textInput("表示する文字列", { bind: inputVal }),
]);
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")
wcli.sync()
この場合はview.sync()が実行される時に前周期のinput_valの内容が復元されるという挙動になります。 (したがってv.sync()より前ではinput_valの値は未初期化になります)
- Note
- 内部の実装では入力値を受け取りInputRefに値をセットする関数をonChangeにセットしています。 また、InputRefの値はText型のデータとしてviewを表示しているクライアントに送信されます。
onChange
C++ onChange() で値が入力されたときに実行する関数を設定でき、こちらでも値が取得できます。 buttonに渡す関数と同様、関数オブジェクト、Funcオブジェクト、FuncListenerオブジェクトが使用できます。
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: 文字の色を変更します。
- bgColor: 背景色を変更します。
- 各種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 構造体のメンバーでオプションを指定することができます。
@ 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を返し、そのデータのリクエストをサーバーに送ります。
- 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 と同様なのでそちらを参照してください