jxWebUI--web组件说明
jxWebUI中的web组件都是通过文本进行定义的,定义语句放入capa.page修饰符进行修饰的函数的doc中,如:
@capa.page
def hello_world(ci, db, ctx):'''table table_hello_world width=900:rowtext text_hello_world text='hello_world',bind=text_hello_world,width=200;'''jxWebLogger.info(f'Hello world!')
上述代码定义了一个hello_world的page,然后就可以通过各种入口让用户点击后打开了。
一个page可以有一条或多条定义语句,每条语句必须以英文分号结束。
一个page包含的定义语句有四种:table、dataTable、单独的web定义语句、compute语句。
由于这种格式化字符串定义方式对初学者不够友好,所以在0.2版中新提供了编程式web界面定义。
本质上,编程式web界面定义只是格式化字符串定义方式的套壳,就是将开发者用描述web界面的代码执行后得到界面对应的格式化字符串。
上述hello_world界面用编程的方式描述为:
@capa.web
def hello_world(page):t = page.table().width(900)r = t.row()r.text().text('hello_world').width(200).bind('text_hello_world')
此外,由于page所修饰的函数的函数体不是pass,代表其在hello_world界面显示完毕后,还需要执行该函数以完成界面的初始化工作。所以换用web修饰后,还需要再为hello_world界面定义一个界面初始化函数:
@capa.disp
def hello_world(ci, db, ctx):jxWebLogger.info(f'Hello world!')
现在就有了两个hello_world函数,它们共同实现了hello_world页面。其中用web修饰的hello_world函数提供了一个page参数,开发者就可以通过给page添加各种web组件来创建hello_world界面了。另一个用disp修饰的hello_world函数,则是专用于hello_world页面的界面初始化函数,其将在hello_world页面显示后被调用,以完成hello_world页面的初始化工作。
page中可添加的web组件
一个page其实对应的就是html中的div,就是用来包含其它web组件的。但由于web组件如何定位、美化需要复杂的前端设计与技巧,不符合jxWebUI简化python程序员使用的初衷。所以使用了page只能包含table和dataTable两个组件,然后再在二者中添加组件的方式来简化web组件的布局。
table
table是容器表,也就是利用表的行列对齐的特点,用来将其它web组件整整齐齐显示用的。
table定义的详细说明请参考:容器表。
dataTable
dataTable是数据表,是重要的数据显示手段。
dataTable在jxWebUI中有两大类:
- 用于显示查询结果的条件查询分页显示的数据表
- 同时完成表格数据的录入与显示的输入输出数据表
在jxWebUI中区分这两种数据表的根据就是看dataTable在定义时是否指定了属性:pagination。定义了pagination=true的就是查询表,没定义的就是输入输出表。
dataTable的详细说明请参考:数据表与数据库访问、用数据表输入输出数据等。
page的特殊属性
page本身只是个div容器,不需要任何属性。但有两个特殊用途需要为其分别使用针对性的属性
okBtn
前面的说明中反复指出,在jxWebUI中一个capa就是一个用来衔接web界面和python代码的桥,原则上应该一个功能模块启用一个capa,用来定义本模块所有用到的page。
所以,一个capa可以定义非常多的page,但其一个实例capaInstance只能管理一个显示到tab中的主page和多个对话框。
主page就是显示到tab中的page;对话框就是主page中的按钮或工具条被点击后通过弹窗方式显示的page。
如何定义一个对话框的page,请参考:对话框。
这里要说明的就是为了定义对话框,需要设置page的一个特殊属性:okBtn。
compute
compute是针对联动计算的特殊属性,详见:前端联动计算。
数据装订
很多时候,我们在打开一个页面后,都需要对页面进行初始的数据装订。这个初始化工作就是在page修饰符所修饰的函数来完成的,上面hello_world的函数体中有如下的代码:
jxWebLogger.info(f'Hello world!')
则在打开hello_world页面后,可以在日志中观察到一个输出:Hello world!
额外说明
组件名
所有web组件都必须有一个唯一名【同一capa】。
如果某个page非常复杂,每个组件都必须有一个唯一名会非常麻烦,所以编程式web界面定义中如果开发者不显式给出组件名,则jxWebUI会自动为其生成一个名字。但这个名字谁也不知道,自然也就无法被开发者操作。
所以,如果操作者需要对某个组件操作,则必须显式给出组件名。典型的,当需要用数据表来输入输出表数据时,就必须知道表名。
web组件的对象函数
所有的web组件都是通过对象函数的方式进行描述的。这些对象函数包括两类:
1、添加子组件
page有两个:
- table,添加了一个容器表
- dataTable,添加了一个数据表
容器表table只能添加一个子组件:row。而row则可以添加文本、输入框、按钮等输入输出组件。
数据表dataTable只能添加一个子组件:col。col无法再添加任何子组件。
其它输入输出的组件都无法添加子组件。
2、设置属性
除了添加子组件的对象函数,其它对象函数都是属性定义,用来给组件设置属性。各组件能接收什么样的属性都已经做出了明确的限制,如果设置未定义的属性,会掷出异常。
page有两个属性,上面已经列出了。其它组件的属性,请参考各自的说明。
流式操作
web组件的添加与设置属性,都是流式操作,也就是一个web组件可以在一行完成全部的定义
宽度
table和dataTable的宽度则是真实宽度,其它组件的width则不是真实宽度,而是相对宽度。也就是说,表中一个组件的实际宽度其实是本身所设置的width值在本行所有组件宽度之和中的占比。
表是行列对齐的,所以容器表中各组件的宽度既和本行其它组件宽度和有关,也和本列其它组件的宽度有关。
所以呢,最好把所有组件的宽度统一一下,如根据提示词的长度,统一设置提示用的text组件的宽度为120,输入框、下拉菜单等输入输出组件为180,这样一个提示词一个输入输出组件两辆一组是300宽,然后一行排布3组。
如果确实需要某个组件有不同的宽度,则可以给容器表设置一个属性:
t.alone(True)
这样的话,则表中的每一行都是独立排布的,不受其它行的影响,也就是只进行了行对齐,不再进行列对齐。
但列不对齐就会很不美观,这时可以采取两个小技巧:
1、其它列依然按一组300、每行3组进行排布。特殊列可以按:
r.text().text('提示词').width(120)
r.input().bind('数据名').width(780)
这样还是可以在提示词这一列做了对齐的。
也就是严格按每行900宽,本行所有组件宽的和也是900,这样手动进行排布来实现行列的伪对齐。
2、在需要的地方添加指定宽度的空白文本。如
r.text().text('提示词').width(120)
r.text().text('').width(180)
r.input().bind('数据名').width(300)
r.text().text('').width(300)
空白文本在视觉效果上就是啥都没有【但有行列边线】,就相当于指定宽度的占位框。
原则上,主page中的表宽度一般设为900,对话框中的表宽度应设为600。主page的表宽可以根据自己的实际情况略做调整,而对话框中的表宽就应设定为600,因为对话框所依托的div就是600宽,偏差太大的话会非常不美观。