Skip to content

Latest commit

 

History

History
762 lines (585 loc) · 25.2 KB

11.command_binding.md

File metadata and controls

762 lines (585 loc) · 25.2 KB

第 11 章 命令绑定

在传统的开发方式中,用户操作控件的时候,控件会触发一些事件,在这些事件处理函数中,去完成某些任务。在 MVVM 模式当中,则是通过命令绑定规则,建立控件事件与 Model 函数之间的联系,用户触发某个事件之后,框架自动执行 Model 中对应的函数。这种绑定关系更容易理解,让 View 与 Model 之间的耦合也更加松散。

11.1 命令绑定的基本用法

命令绑定规则也是一个控件属性:

属性的名称由两部分组成,两者之间用英文冒号分隔。

  • v-on 表示该属性是一个命令绑定规则。
  • 第二部分是控件事件的名称,表示对该事件触发时,自动执行指定的命令。

命令的名称放在'{'和'}'之间,命令对应 View Model 中的函数。

如:

v-on:click="{apply}" 表示将控件的"click"事件与 ViewModel 的"apply"命令关联起来。

目前支持的事件有(以后根据需要增加):

  1. 指针事件
  • click 点击事件
  • pointer_up 指针抬起事件
  • pointer_down 指针按下事件
  • pointer_move 指针移动事件
  1. 按键事件
  • key_up 按键抬起事件
  • key_down 按键按下事件
  • key_long_press 按键长按事件
  • key_up_before_children 按键抬起事件,在子控件处理之前触发
  • key_down_before_children 按键按下事件,在子控件处理之前触发
  • global_key_up 全局按键抬起事件
  • global_key_down 全局按键按下事件
  • global_key_long_press 全局按键长按事件

全局按键用来处理全局的快捷键,即使窗口在后台也可以收到事件,通常绑定到主窗口上。

  1. 定时器
  • timer 定时器(具体用法请参考awtk/docs/fscript_widget.md)
  1. 窗口事件
  • window_close 窗口关闭事件
  • window_open 窗口打开事件
  • window_will_open 窗口即将打开事件

窗口事件只适用于窗口。

  1. 值事件
  • value_changed 值改变事件
  • value_changed_by_ui 值(通过 UI 修改)改变事件
  1. 焦点事件
  • focus 得到焦点事件
  • blur 失去焦点事件

最新支持的事情请参考 这里

我们还是以温度控制器为例,假设我们调节温度之后,点击"Apply"按钮,才让新的温度生效,如果新的温度与旧的温度相同,则禁用"Apply"按钮,否则启用"Apply"按钮。

新的界面大概是这样的:

view

它的界面描述文件是这样:

<window v-model="temperature_ex">
  <label  x="center" y="middle:-40" w="80%" h="40" v-data:text="{value}"/>
  <slider x="center" y="middle" w="90%" h="20" v-data:value="{value}"/>
  <button text="Apply" x="center" y="middle:40" w="40%" h="40" v-on:click="{apply}"/>
</window>

拖动滑块改变温度的值,如果新的值与旧的值不同,"Apply"按钮处于启用状态,当点击"Apply"时,就会调用 ViewModel 中的"apply",它将旧的值设置为新的值,"Apply"按钮重新处于禁用状态。

ViewModel 再调用 Model 的 apply 函数,ViewModel 的代码是自动生成的,这里只列出 Model 中的代码:

/**
 * @method temperature_apply
 * 使用新设置的值生效。
 *
 * @annotation ["command"]
 * @param {temperature_t*} temperature temperature 对象。
 *
 * @return {ret_t} 返回 RET_OK 表示成功;返回 RET_OBJECT_CHANGED 表示 Model 有变化,View 需要刷新;返回其它表示失败。
 */
ret_t temperature_apply(temperature_t* temperature);

/**
 * @method temperature_can_apply
 * 检查 apply 命令是否可以执行。
 *
 * @param {temperature_t*} temperature temperature 对象。
 *
 * @return {bool_t} 返回 FALSE 表示不能执行,否则表示可以执行。
 */
bool_t temperature_can_apply(temperature_t* temperature);

在命令绑定规则中,还可以指定一些高级参数,这些参数之间用英文逗号分隔,后面我们将详细介绍这些参数的作用。

Windows 的命令行下,读者可以运行 demo6 来查看实际的效果。

bin\demo6.exe

11.2 命令的参数

在命令绑定规则中,可以指定一个参数,该参数并不是必须的,但有时命令参数确实能带来不少便利。

在命令绑定规则中,通过 Args 指定命令的参数。

11.2.1 Args 的形式

Args 有以下三种形式:

1. 普通字符串

Args 的值不经过二次处理,直接为命令的字符串类型的参数。例如将字符串 "0" 作为参数传给命令,代码如下:

v-on:click="{addChar, Args=0}"

2. 字符串形式的参数序列(string?)

Args 的值以"string?"为前缀时,默认其后跟随"name=value"格式的参数。若存在多个参数,参数之间用一个"&"隔开。例如为"navigate"命令指定3个参数,参数1名称为"target"、值为"demo33_a",参数2为"close_current"、值为"true",参数3名称为"open_new"、值为"false",代码如下:

v-on:click="{navigate, Args=string?target=demo33_a&amp;close_current=true&amp;open_new=false}"

在 xml 文件中需要使用转义字符 "&amp;" 表示 "&" 符号。

在 C 语言的 View Model 中,命令的参数仍为 Args 的值,可以使用 tk_command_arguments_to_object 函数将其转换为tk_object_t 对象;

在 JS 语言的 View Model 中,命令的参数则直接转换为一个 Object。

3. fscript表达式形式的参数序列(fscript?)

Args 的值以"fscript?"为前缀时,默认其后跟随"name=value of fscript expression"格式的参数。若存在多个参数,参数之间用一个"&"隔开。例如为"setCurrent"命令指定1个参数,参数名称为"index"、值为"index"变量的值,代码如下:

v-on:click="{setCurrent, Args=fscript?index=index, AutoDisable=false}"

在 C 语言的 View Model 中,"fscript?"形式的命令参数会自动转换为"string?"形式再向下传递;

在 JS 语言的 View Model 中,命令的参数则直接转换为一个 Object。

11.2.2 示例

现在我们以一个简单计算器的例子,来看看字符串命令参数是如何使用,以及它带来的便利性。

计算器的界面大概是这样的:

view

计算器的界面描述文件是这样的:

<window v-model="calculator">
  <edit name="expr" x="c" y="10" w="90%" h="30" focus="true" readonly="true" input_type="custom" text="" tips="expression" v-data:text="{expr}"/>
  <view y="60" x="c" w="90%" h="-60" is_keyboard="true" 
    children_layout="default(r=4,c=4,m=5,s=5)" >
    <button name="0" text="0" v-on:click="{addChar, Args=0}"/>
    <button name="1" text="1" v-on:click="{addChar, Args=1}"/>
    <button name="2" text="2" v-on:click="{addChar, Args=2}"/>
    <button name="3" text="3" v-on:click="{addChar, Args=3}"/>
    <button name="4" text="4" v-on:click="{addChar, Args=4}"/>
    <button name="5" text="5" v-on:click="{addChar, Args=5}"/>
    <button name="6" text="6" v-on:click="{addChar, Args=6}"/>
    <button name="7" text="7" v-on:click="{addChar, Args=7}"/>
    <button name="8" text="8" v-on:click="{addChar, Args=8}"/>
    <button name="9" text="9" v-on:click="{addChar, Args=9}"/>
    <button name="+" text="+" v-on:click="{addChar, Args=+}"/>
    <button name="-" text="-" v-on:click="{addChar, Args=-}"/>
    <button name="*" text="*" v-on:click="{addChar, Args=*}"/>
    <button name="/" text="/" v-on:click="{addChar, Args=/}"/>
    <button name="=" text="=" v-on:click="{eval}"/>
    <button name="backspace" text="<=" v-on:click="{removeChar}"/>
  </view>
</window>

这里我们可以看到,数字和运算符全部绑定到"addChar"这个命令上,只是通过参数来区分的,ViewModel 中,我们只需要实现 addChar 函数即可。如果不使用命令参数,我们就要为每一个按钮写一个命令,那是非常繁琐的。

下面我们看看模型的声明 (demo7/calculator.h):

/**
 * @class calculator_t
 *
 * @annotation ["model"]
 * 计算器。
 *
 */
typedef struct _calculator_t {
  /**
   * @property {const char*} expr
   * @annotation ["readable", "writable"]
   * 表达式。
   */
  str_t expr;

} calculator_t;

/**
 * @method calculator_create
 * 创建 calculator 对象。
 *
 * @annotation ["constructor"]
 * @return {calculator_t*} 返回 calculator 对象。
 */
calculator_t* calculator_create(void);

/**
 * @method calculator_destroy
 * 销毁 calculator 对象。
 *
 * @annotation ["destructor"]
 * @param {calculator_t*} calculator calculator 对象。
 *
 * @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
 */
ret_t calculator_destroy(calculator_t* calculator);

/**
 * @method calculator_get_expr
 * 获取当前表达式。
 * @param {calculator_t*} calculator calculator 对象。
 *
 * @return {const char*} 返回表达式。
 */
const char* calculator_get_expr(calculator_t* calculator);

/**
 * @method calculator_set_expr
 * 设置当前表达式。
 *
 * @param {calculator_t*} calculator calculator 对象。
 * @param {const char*} expr 表达式。
 *
 * @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
 */
ret_t calculator_set_expr(calculator_t* calculator, const char* expr);

/**
 * @method calculator_add_char
 * 追加一个字符。
 *
 * @annotation ["command"]
 * @param {calculator_t*} calculator calculator 对象。
 * @param {const char*} args 参数。
 *
 * @return {ret_t} 返回 RET_OBJECT_CHANGED 表示模型有变化,View 需要刷新;返回其它表示失败。
 */
ret_t calculator_add_char(calculator_t* calculator, const char* args);

/**
 * @method calculator_remove_char
 * 删除最后一个字符串。
 *
 * @annotation ["command"]
 * @param {calculator_t*} calculator calculator 对象。
 *
 * @return {ret_t} 返回 RET_OBJECT_CHANGED 表示模型有变化,View 需要刷新;返回其它表示失败。
 */
ret_t calculator_remove_char(calculator_t* calculator);

/**
 * @method calculator_can_remove_char
 * 检查 remove_char 命令是否可以执行。
 *
 * @param {calculator_t*} calculator calculator 对象。
 *
 * @return {bool_t} 返回 FALSE 表示不能执行,否则表示可以执行。
 */
bool_t calculator_can_remove_char(calculator_t* calculator);

/**
 * @method calculator_eval
 * 计算表达式。
 *
 * @annotation ["command"]
 * @param {calculator_t*} calculator calculator 对象。
 *
 * @return {ret_t} 返回 RET_OBJECT_CHANGED 表示模型有变化,View 需要刷新;返回其它表示失败。
 */
ret_t calculator_eval(calculator_t* calculator);

/**
 * @method calculator_can_eval
 * 检查 eval 命令是否可以执行。
 *
 * @param {calculator_t*} calculator calculator 对象。
 *
 * @return {bool_t} 返回 FALSE 表示不能执行,否则表示可以执行。
 */
bool_t calculator_can_eval(calculator_t* calculator);

Windows 的命令行下,读者可以运行 demo7 来查看实际的效果。

bin\demo7.exe

11.3 更新 Model 的参数

在前面我们提到,将数据从 View 同步到 Model 有三种触发方式,其中一个称为显式更新,需要在命令执行之前,显式的将 View 的数据同步到 Model。

这可以通过命令的 UpdateModel 参数来实现。其用法如下:

先将数据更新的触发方式指定为 Explicit:

v-data:value="{value, Trigger=Explicit}"

然后再指定命令的 UpdateModel 参数:

v-on:click="{nothing, UpdateModel=true}"

这里我们用了 nothing 命令,它是一个特殊命令,除了参数要求的事情之外,它什么也不做。这里它就只是同步 View 的数据到 Model。

完整示例如下:

<window v-model="temperature">
  <label x="center" y="middle" w="50%" h="40" v-data:text="{value}"/>
  <slider x="center" y="middle:40" w="80%" h="20" v-data:value="{value, Trigger=Explicit}"/>
  <button name="apply" text="Apply" x="center" y="bottom:10" w="80%" h="30" 
    v-on:click="{nothing, UpdateModel=True}"/>
</window>

Windows 的命令行下,读者可以运行 demo4 来查看实际的效果。

bin\demo4.exe

11.4 关闭当前窗口的参数

有时,在执行完某个命令后,需要关闭当前窗口。但命令是在 ViewModel 中实现的,它不能直接操作界面,也就不能直接关闭窗口,否则就与 View 耦合起来了。

在执行完某个命令后,需要关闭当前窗口,可以通过命令的 CloseWindow 参数来实现。其用法如下:

v-on:click="{nothing, CloseWindow=true}"

如果只是单纯的关闭当前窗口,可以使用 nothing 命令,也可以在执行实际的命令后关闭。

比如,下面这个例子中:

  • 点击"OK"按钮,执行 return 命令,然后关闭窗口。
  • 点击"Cancel"按钮,执行 nothing 命令,然后关闭窗口。
<window children_layout="default(r=3, c=1)" v-model="room_settings">
 <label floating="true" x="center" y="10" w="50%" h="40" v-data:text="{room}"/>

  <view>
    <label x="center" y="30" w="90%" h="40" text="temperature"/>
    <label x="center" y="middle" w="50%" h="40" v-data:text="{temp}"/>
    <slider x="center" y="middle:40" w="80%" h="20" v-data:value="{temp, Trigger=Changing}"/>
  </view>

  <view>
    <label x="center" y="30" w="90%" h="40" text="humidity"/>
    <label x="center" y="middle" w="50%" h="40" v-data:text="{humidity}"/>
    <slider x="center" y="middle:40" w="80%" h="20" v-data:value="{humidity, Trigger=Changing}"/>
  </view>

  <button text="OK" floating="true" x="center:-90" y="bottom:40" w="100" h="40" 
    v-on:click="{return, CloseWindow=True}"/>

  <button text="Cancel" floating="true" x="center:90" y="bottom:40" w="100" h="40" 
    v-on:click="{nothing, CloseWindow=True}"/>
</window>

Windows 的命令行下,读者可以运行 demo12 来查看实际的效果。

bin\demo12.exe

11.5 退出应用程序的参数

有时,在执行完某个命令后,需要退出应用程序。但命令是在 ViewModel 中实现的,不能直接退出应用程序,否则该命令就无法进行单元测试。

在执行完某个命令后,需要退出应用程序,可以通过命令的 QuitApp 参数来实现。其用法如下:

v-on:click="{nothing, QuitApp=true}"

如果只是单纯的退出应用程序,使用 nothing 命令即可。

完整示例如下:

<window v-model="temperature_timer">
  <label x="center" y="30" w="90%" h="40" text="temperature"/>
  <label x="center" y="middle" w="50%" h="40" v-data:text="{value}"/>
  <progress_bar x="center" y="middle:-40" w="80%" h="20" v-data:value="{value}" v-on:value_changed="{fscript, Args=print(&quot;progress_bar_value_changed&quot;)}"/>
  <slider x="center" y="middle:40" w="80%" h="30" v-data:value="{value, Trigger=Changing}" v-on:value_changed_by_ui="{fscript, Args=print(&quot;slider_value_changed_by_ui&quot;)}"/>
  <button text="Quit" x="center" y="bottom:40" w="40%" h="40" v-on:click="{nothing, QuitApp=true}"/>
</window>

Windows 的命令行下,读者可以运行 demo10 来查看实际的效果。

bin\demo10.exe

11.6 按键过滤参数

在处理按键事件的时候,通常我们并不希望按任意键都触发命令,而是按下特殊的键时才触发命令。这有点像快捷键的处理方式,比如按下 ctrl+s 才触发"save"命令,按下 ctrl+o 时才触发"open"命令。

可以指定按键过滤参数来实现这种效果,指定按键过滤参数很简单,在事件后面紧跟按键的值即可。如:

 v-on:key_down:ctrl_s="{apply}" 表示按下 ctrl+s 时,执行 apply 命令。 

注意:不再使用‘+’作为按键分隔符,而是改为使用下划线‘_’,但仍然保存对旧版的兼容。

常用的按键符号与键值的对应关系如下:

符号名除了字母外不区分大小写,建议用小写。 ctrl/shift/alt 表示左右的按键都可以。

按键的符号 键值
RETURN TK_KEY_RETURN
ESCAPE TK_KEY_ESCAPE
BACKSPACE TK_KEY_BACKSPACE
TAB TK_KEY_TAB
SPACE TK_KEY_SPACE
EXCLAIM TK_KEY_EXCLAIM
QUOTEDBL TK_KEY_QUOTEDBL
HASH TK_KEY_HASH
PERCENT TK_KEY_PERCENT
DOLLAR TK_KEY_DOLLAR
AMPERSAND TK_KEY_AMPERSAND
QUOTE TK_KEY_QUOTE
LEFTPAREN TK_KEY_LEFTPAREN
RIGHTPAREN TK_KEY_RIGHTPAREN
ASTERISK TK_KEY_ASTERISK
PLUS TK_KEY_PLUS
COMMA TK_KEY_COMMA
MINUS TK_KEY_MINUS
PERIOD TK_KEY_PERIOD
SLASH TK_KEY_SLASH
0 TK_KEY_0
1 TK_KEY_1
2 TK_KEY_2
3 TK_KEY_3
4 TK_KEY_4
5 TK_KEY_5
6 TK_KEY_6
7 TK_KEY_7
8 TK_KEY_8
9 TK_KEY_9
a TK_KEY_a
b TK_KEY_b
c TK_KEY_c
d TK_KEY_d
e TK_KEY_e
f TK_KEY_f
g TK_KEY_g
h TK_KEY_h
i TK_KEY_i
j TK_KEY_j
k TK_KEY_k
l TK_KEY_l
m TK_KEY_m
n TK_KEY_n
o TK_KEY_o
p TK_KEY_p
q TK_KEY_q
r TK_KEY_r
s TK_KEY_s
t TK_KEY_t
u TK_KEY_u
v TK_KEY_v
w TK_KEY_w
x TK_KEY_x
y TK_KEY_y
z TK_KEY_z
A TK_KEY_A
B TK_KEY_B
C TK_KEY_C
D TK_KEY_D
E TK_KEY_E
F TK_KEY_F
G TK_KEY_G
H TK_KEY_H
I TK_KEY_I
J TK_KEY_J
K TK_KEY_K
L TK_KEY_L
M TK_KEY_M
N TK_KEY_N
O TK_KEY_O
P TK_KEY_P
Q TK_KEY_Q
R TK_KEY_R
S TK_KEY_S
T TK_KEY_T
U TK_KEY_U
V TK_KEY_V
W TK_KEY_W
X TK_KEY_X
Y TK_KEY_Y
Z TK_KEY_Z
DOT TK_KEY_DOT
DELETE TK_KEY_DELETE
LEFTBRACE TK_KEY_LEFTBRACE
RIGHTBRACE TK_KEY_RIGHTBRACE
LCTRL TK_KEY_LCTRL
RCTRL TK_KEY_RCTRL
LSHIFT TK_KEY_LSHIFT
RSHIFT TK_KEY_RSHIFT
LALT TK_KEY_LALT
RALT TK_KEY_RALT
CAPSLOCK TK_KEY_CAPSLOCK
HOME TK_KEY_HOME
END TK_KEY_END
INSERT TK_KEY_INSERT
UP TK_KEY_UP
DOWN TK_KEY_DOWN
LEFT TK_KEY_LEFT
RIGHT TK_KEY_RIGHT
PAGEUP TK_KEY_PAGEUP
PAGEDOWN TK_KEY_PAGEDOWN
F1 TK_KEY_F1
F2 TK_KEY_F2
F3 TK_KEY_F3
F4 TK_KEY_F4
F5 TK_KEY_F5
F6 TK_KEY_F6
F7 TK_KEY_F7
F8 TK_KEY_F8
F9 TK_KEY_F9
F10 TK_KEY_F10
F11 TK_KEY_F11
F12 TK_KEY_F12;

按键事件的处理,一般放在窗口上,可以同时指定多个事件。

下面的例子中,我们对两个按键进行了处理:

  • ctrl+s 执行 apply 命令。
  • escape 退出应用程序。
<window v-model="temperature_ex" 
 v-on:key_down:ctrl_s="{apply}" 
 v-on:key_long_press:f3="{apply}" 
 v-on:key_down:escape="{nothing, QuitApp=true}">
  <label  x="center" y="middle:-80" w="80%" h="40" text="ctrl+s/long press F3 to apply\nescape to quit"/>
  <label  x="center" y="middle:-40" w="80%" h="40" v-data:text="{value}"/>
  <slider x="center" y="middle" w="90%" h="20" v-data:value="{value}"/>
  <button text="Apply" x="center" y="middle:40" w="40%" h="40" v-on:click="{apply}"/>
</window>

Windows 的命令行下,读者可以运行 demo14 来查看实际的效果。

bin\demo14.exe

11.7 内置命令

AWTK-MVVM 框架内置了几条常用的命令,可以避免在每个 Model 里都去实现。即使 View 没有绑定 ViewModel,这些命令也是可以执行的,所以在一些简单的情况下,开发者甚至连 ViewModel 都不用提供。

11.7.1 nothing

它本身什么也不做,行为取决于参数。前面已经出现了好几次,读者应该已经熟悉了,这里不再赘述了。

11.7.2 navigate

打开新窗口是经常要处理的事情,如果不需要在新窗口和当前窗口之间传递数据,那么可以直接使用 navigate 命令,并把 args 指定为新窗口的名称即可。如:

  v-on:click="{navigate, args=humidity}"/>

我们来看看完整的例子,在这个例子中,并没有用 v-model 指定 ViewModel,这是可以的:

<window
 v-on:global_key_down:f1="{fscript, Args=print(&quot;global_key_down:f1&quot;)}" 
 v-on:global_key_long_press:f2="{fscript, Args=print(&quot;global_key_long_press:f2&quot;)}" >
  <button text="Temperature" x="center" y="middle:-40" w="40%" h="40" 
    v-on:click="{navigate, Args=temperature9}"/>
  <button text="Humidity" x="center" y="middle:40" w="40%" h="40" 
    v-on:click="{navigate, Args=humidity}"/>
</window>

Windows 的命令行下,读者可以运行 demo9 来查看实际的效果。

bin\demo9.exe

窗口导航是一个有趣的话题,涉及的内容也比较多,下一章我们再详细讨论。

11.7.3 SendKey

过时:推荐使用 fscript 代替本函数。

按键的名称请参考:https://github.com/zlgopen/awtk/blob/master/src/base/enums.c

  • 参数格式:widget_name:key_name

SendKey 命令示例:下面的例子给 edit 控件发送 backspace 按钮消息。

    <button text="Backspace" v-on:click="{SendKey, Args=edit:backspace}"/>

fscript 脚本示例:

    <button text="Backspace" on:click="send_key(window.edit, 'backspace')"/>

完整示例请参考 demo30

11.7.4 SetWidgetProp

过时:推荐使用 fscript 代替本函数。

设置指定控件的属性。

  • 参数格式:widget_name.prop_name:prop_value

SetWidgetProp 命令示例:下面的例子设置 edit 控件的 visible 属性为 false,及隐藏该控件。

    <button text="Hide" v-on:click="{SetWidgetProp, Args=edit.visible:false}"/>

fscript 脚本示例:

    <button text="Hide" on:click="widget_set(window.edit, visible, false)"/>

完整示例请参考 demo30

11.7.5 debug

过时:推荐使用 fscript 代替本函数。

用于打印一条调试信息。

debug 命令示例:

  <progress_bar x="center" y="middle:-40" w="80%" h="20" v-data:value="{value}" 
    v-on:value_changed="{debug, args=progress_bar_value_changed}"/>
  <slider x="center" y="middle:40" w="80%" h="30" v-data:value="{value, Trigger=Changing}" 
    v-on:value_changed_by_ui="{debug, args=slider_value_changed_by_ui}"/>

fscript 脚本示例:

  <progress_bar x="center" y="middle:-40" w="80%" h="20" v-data:value="{value}" 
    v-on:value_changed="{fscript, Args=print(&quot;progress_bar_value_changed&quot;)}"/>
  <slider x="center" y="middle:40" w="80%" h="30" v-data:value="{value, Trigger=Changing}" 
    v-on:value_changed_by_ui="{fscript, Args=print(&quot;slider_value_changed_by_ui&quot;)}"/>

注意:在 xml 文件中需要使用转义字符 "&quot;" 表示双引号 " 。

完整示例请参考 demo10

11.7.6 fscript

执行一段 fscript 脚本。fscript 的用法请参考 fscript 手册, MVVM 新增函数请参考:高级用法 中关于嵌入表达式一节。

示例:

<button name="inc" text="Inc" v-on:click="{fscript, Args=widget_set(window.slider1.value, widget_get(window.slider1.value)+10)}" />
<button name="dec" text="Dec" v-on:click="{fscript, Args=widget_set(window.slider1.value, widget_get(window.slider1.value)-10)}" />
<button text="Open" v-on:click="{fscript, Args=navigator_to(temperature28)}" />
<button text="Replace" v-on:click="{fscript, Args=navigator_replace(temperature28)}" />
<button text="Exec Open" v-on:click="{fscript, Args=exec(navigate, temperature28)}" />
<button text="Back" v-on:click="{fscript, Args=back()}" />
<button text="Home" v-on:click="{fscript, Args=back_to_home()}" />

当代码有多行的时候,如果把代码放在 Args 中,不好编辑也容易出错,此时可以把代码放到独立的属性中,再用 widget_eval 来调用。如:

    <button text="Test1" v-on:click="{fscript, Args=widget_eval(self.code)}">
      <property name="code"><![CDATA[
        var a = len(widget_get(window.edit.text))
        if(a < 10) {
          send_key(window.edit, str(a)) 
        } else {
          widget_set(window.edit, text, "")
        }
      ]]></property>
    </button>

如果不需要调用模型的函数,可以通过 on: 来编写处理事件的函数,写法更为简单。详细用法请参考这里

    <button text="Test2">
      <property name="on:click"><![CDATA[
        var a = len(widget_get(window.edit.text))
        if(a < 10) {
          send_key(window.edit, str(a)) 
        } else {
          widget_set(window.edit, text, "")
        }
      ]]></property>
    </button>
    <button text="Char:a" on:click="send_key(window.edit, 'a')"/>
    <button text="Backspace" on:click="send_key(window.edit, 'backspace')"/>
    <button text="Show" on:click="widget_set(window.edit, visible, true)"/>
    <button text="Hide" on:click="widget_set(window.edit, visible, false)"/>
    <button text="Quit" on:click="quit()"/>

11.8 控件的 enable 属性

默认情况下,如果一个控件(比如按钮)绑定了一个命令,其 enable 属性是由对应的 can_exec 函数决定是否可用。如果不想由 can_exec 决定,而是自己设置,可以通过指定参数 AutoDisable=false 实现。如:

{Save, AutoDisable=false}