STARLIMS IDE:
Applications中的Form类型:
此处仅记录HTML form的编写笔记。
使用toolbox设计HTML form:
toolbox里面是form的各种控件。
每个控件包含:
【备注】:可以将每个控件,当做一个封装了特定功能和属性的class。【注意】:首字母都是大写的!!!
当鼠标选中html form中的某个具体的控件时,控件的properties会在右下角显示:
编辑完代码后,要先保存,再点击运行按钮。若是不保存,最新的更新将不会奏效。
html form会在浏览器中启动。
form和脚本script的控制:
新建的form和脚本,默认是check out;
必须签出现有的表单或脚本以进行编辑,防止冲突。
编辑好的form和脚本,需要check in,让其他用户可见,否则运行时,更新将不生效。
【备注】:
版本控制可以查看历史记录。
事件处理程序是javaScript函数,会在事件发生时,自动执行。
当按钮被点击的时候触发。
打开一个新的html form,可以实现form之间参数的传递。
form.ShowModalDialog(lims.GetFormSource("窗口路径"),[参数集合]);
【示例】:
var sValue = await form.ShowModalDialog(lims.GetFormSource("ReportsApprovalNew.AddPatientRecord"),[sSampleNo,sFolderNo,sPid,sMetadataGuid]);
弹出窗口,窗口路径使用lims.GetFormSource("form路径"),调用其他窗体。
【备注】:
后跳出的窗体中可以用form.formArguments[序号]获取前一个窗体的传值。
【备注】:lims.CallServerAsync();异步调用Server Scripts脚本(async是立即返回的)。
lims.CallServer("server script脚本路径",[方法参数集合]);
【示例】:
var aRetVal = lims.CallServer("ReportsApprovalNew.CreateMetadata", [sFolderNo]);
【备注】:
server script中通过:PARAMETERS关键字获取传参。
Form, Group Box, Panel, Split Container Panel,有一些属性用于调整网页上的自己的布局和子控件的布局。
控制父容器内的控件的安排。有3种方法:
控件展示就是手动放置的地方,所见即所得:
控制件按添加到容器的顺序水平排列(并排)side-by-side
控件按它们被添加到容器中的顺序垂直排列。
【注意】:
Layout布局,除了ABSOLUTE选项,其余的VBOX和HBOX选项,都是针对控件插入的顺序布局的。
用于控制父容器中包含的子项的对齐方式。
【注意】:
Align布局和Layout布局要放在一起才能生效!!!
此时Align调节的是垂直方向的布局 (上、中、下)
此时Align调节的是水平方向的布局 (左、中、右)
控制子项如何在容器中打包在一起。它可以通过三种方式来实现。
【注意】:
pack布局和Layout布局要放在一起才能生效!!!
设置要应用于父容器中的所有子项的填充。控制控件之间的间距(像素)。
【注意】:1、Padding布局和Layout布局要放在一起才能生效!!!2、若是Padding设置的是30px,则控件的上、下、左、右都是30px。
指定最后一个子控件是否会延伸,以使其占用父容器中的所有剩余空间。
【注意】:
Stretch布局和Layout布局+pack布局(默认是start)一起用,拉伸控制取决于包装。
anchor和dock是控件的两个公用的布局属性:
【注意】:
1、两个属性不同时设置!!!没有意义!
2、都是将控件连接到他们父窗体的某个位置。
3、此时将Layout设置为abstract,否则可能不生效。
不设置anchor和dock的时候,控件位置是固定的,不会随着窗口大小自适应!!!
不设置anchor和dock的时候
黑色表示选中,如图例,始终保持本控件和其所直属父控件的右侧及上侧距离不变,因此窗口大小改变的时候,控件会移动位置,保持距离窗口的右侧和上侧的距离会不变。
由于例中设定上、下、左、右距离都保持不变,因此当窗口大小改变,控件的大小也会随之改变,以保证其对窗口的上、下、左、右距离都保持不变。
【注意】:
会自适应!!!最终的停靠效果取决于控件添加的顺序!
第五节说的相对布局,控制的是控件和自己的子控件直接的布局;
第六节说的布局,控制的是控件和自己的直接父控件之间的布局。
data source:
常用于,单行输入模式:可以水平拉伸变宽,不能垂直拉伸变高。
font-字体
emptyText:文本框空白时的提示文字,鼠标点击,文字消失。
Password:true输入时展示星号保密;
Readonly:true只读,不可以输入;
OnKeyPress:快捷键的设置。
两个文本框内的数字相加
async function btAdd_OnClick( sender, eventArgs )
{
alert(txtA + txtB);
}
async function btAdd_OnClick( sender, eventArgs )
{
// String 装 int类型
var num1 = parseInt(txtA.Text);
// String 装 int类型
var num2 = Int32.Parse(txtB.Text);
var res = num1 + num2;
alert(res);
}
【备注】:
一般和label控件一起用。
Text:文本显示
Checked:(true/false)是否被选中
onCheckedChange:选中状态发生变化,可以是用户点击,也可以是代码的修改,如:
checkBox1.Checked = true;
用复选框控制textBox的密码属性
【注意】:
一个窗体上,如果不对RadioButton控件进行分组,那么无论有多少个单选按钮,我们都只能选择一个。若我们需要有多组的单选按钮,就需要用到分组控件GroupBox或者Panel控件了
点击按钮,获取选中的单选按钮的值。
async function btRadioBt_OnClick( sender, eventArgs )
{
var radios = gbRadioBt.All(SL.RadioButton);
for(var i = 0; i < radios.Count; i++){
if(radios[i].Checked){
alert(radios[i].Text);
}
}
}
【注意】:
GroupBox(控件组)控件一般是作为其他控件的组的容器的形式存在的,这样有利于用户识别,使界面变得更加友好。
当移动单个GroupBox控件时,它所包含的所有控件也将一起移动。
CheckBoxes属性,控制node前面是否有复选框。
async function treeView1_OnAfterCheck( sender, eventArgs )
{
var node = eventArgs["node"];
if(node.Checked){
if(node.Text == "DDL"){
alert("DDL choose!!!");
}else{
alert(" not DDL choose!!!");
}
}
}
【示例】:
data source:
select
FOLDERNO as name,
FOLDERNO as text,
FOLDERNO as value,
'' as parent
from FOLDERS
where FOLDERNO = 'X00023738'
or FOLDERNO = 'X00023737'
union
select
ORDNO as name,
ORDNO as text,
ORDNO as value,
FOLDERNO as parent
from ORDERS
where FOLDERNO = 'X00023738'
or FOLDERNO = 'X00023737'
结果展示:
data source:
:DECLARE sqlStr;
sqlStr := "select ORIGREC, name, sex, comments from WSTEST where 1=1";
:RETURN GetDataSet(sqlStr);
右击,选择root table designer,设置显示的列和列名
【注意】:
此时打开root table designer,data source中的表名和列名已存在!
datagridID.Data = lims.GetDataSource("data source路径");
var dgWsTestTable = form.All( "dgWsTestTable" ); // DataGrid
async function Form1_OnLoad( sender, eventArgs )
{
dgWsTestTable.Data = lims.GetDataSource("WsTest.ListWsTestTable");
}
右击,选择root table designer,添加root table和列
【注意】:
此时打开root table designer,是空白的,要自己新增表和列,名字要和data source中的表名和列名一样!!!
SelectionMode:multiple,允许按住shift健多选
filterRowVisible:ture,允许每一列有查询功能
GroupbyBoxVisible:true,允许表可以分组。
单元格可以使其他控件类型,默认是文本框
【示例1】 :改变datagrid中某一列的单元格类型
【注意】:
datagrid的update功能是自动实现的。不需要额外写代码。
【示例2】:添加搜索功能
js代码:
async function btNameSearch_OnClick( sender, eventArgs )
{
var nameSearch = tbNameSearch.Text + "%";
dgWsTestTable.Data = lims.GetDataSource("WsTest.ListWsTestTable",[nameSearch]);
}
data source代码:
:PARAMETERS name := "";
:DECLARE sqlStr, StrWhr;
StrWhr := "1=1";
:IF .NOT. empty(name);
StrWhr := StrWhr + " and name like '" + name + "%'";
:ENDIF;
sqlStr := "select ORIGREC, name, sex, comments from WSTEST where " + StrWhr;
usrmes(sqlStr);
:RETURN GetDataSet(sqlStr);
【示例3】:展示datagrid中每一行数据的详情
js代码:
// 默认显示首行,选中行数改变,改事件便会被触发
async function dgWsTestTable_OnRowChange( sender, eventArgs )
{
var currentRowData = dgWsTestTable.GetCurrentDataRow();
txtName.Text = currentRowData[1];
txtSex.Text = currentRowData[2];
txtComm.Text = currentRowData[3];
}
【示例4】:使用代码给datagrid添加行列值
async function btFill_OnClick( sender, eventArgs )
{
var dt = new System.Data.DataTable();
// 列的id
dt.Columns.Add("namekey");
dt.Columns.Add("namevalue");
dt.Rows.Add("Marian", "Veteanu");
dt.Rows.Add("Claudiu", "Codreanu");
var ds = new System.Data.DataSet();
ds.Tables.Add(dt);
dGrid.DataSet = ds;
}
【注意】:
1、datagrid要先和数据库中的表绑定,否则只能新增行,不能新增行内的数据,而且,因为datagrid更新事件是自动的,所以,不和数据库中的表绑定的话,新增行后,自动更新时会报错!!!
2、列中的caption属性要有值,否则列表头不展示!!!
3、datagrid <—— dataset <—— dataTable(添加:行,列)
4、如果用户更新了数据网格中的任何数据,并且没有保存这些更改,那么所有未保存的数据都将在数据单元格中显示为红色标志。
2种方式调整控件属性:
【示例】:通过点击第二个按钮控制第一个按钮的是否可以点击的属性
async function btnDisplayBtn_OnClick( sender, eventArgs )
{
if(btnDisplayBtn.Text.StartsWith("D")){
btnSaveUser.Enabled = false;
btnDisplayBtn.Text = "enable button";
}else{
btnSaveUser.Enabled = true;
btnDisplayBtn.Text = "Display button";
}
}
【示例】:listBox的数据绑定,使其展示的数据动态来源于数据库
在data source中定义,表名应该获取哪些数据。
【注意】:
要定义成SQL类型,不要定义成STARLIMS类型。
从获取的数据中,应该显示哪些数据,例如显示哪个列。
async function Form1_OnLoad( sender, eventArgs )
{
var folderno ="T00015304";
comboBox.Data = lims.GetDataSource ("WsTest.ComBoxData", [folderno]);
}
WsTest.ComBoxData:
:PARAMETERS folderNumber := 'T00015302';
select ORDNO from ORDERS where FOLDERNO LIKE @folderNumber
【示例】:使用按钮,修改multiChoice控件的item的值
async function btClear_OnClick( sender, eventArgs )
{
multiChoice.Items.Clear();
alert("clear all ok");
}
async function btAddItem_OnClick( sender, eventArgs )
{
// 第一个参数是value,第二个参数是显示值
multiChoice.Items.Add("1","AAA");
multiChoice.Items.Add("2","BBB");
multiChoice.Items.Add("3","CCC");
}
async function btChange_OnClick( sender, eventArgs )
{
multiChoice.DataBindingBehavior = "replace";
multiChoice.DisplayMember = "FOLDERNO";
multiChoice.ValueMember = "ORDNO";
multiChoice.Data = lims.GetDataSource("WsTest.ComBoxData");
}
WsTest.ComBoxData:
select top 10 ORDNO, FOLDERNO from ORDERS
两个同步任务必须相互感知,并且一个任务必须以某种依赖于另一个任务的方式执行,例如:等待另一个任务的执行结果。
function doSomething( param1, param2 )
{
}
不必等待另一个函数的操作完成才能完成其他任务。意味着该函数的执行不会阻塞后面代码的执行。
async function Form1_OnLoad( sender, eventArgs )
{
}
【注意】:
关键字async。
async——异步
async就是用来声明一个异步方法,作为一个关键字放在函数前面,表示该函数是一个异步函数。await = async wait
await是用来等待异步方法执行。因此async/await的作用就是将异步逻辑,转化为同步的顺序来书写。
调用Server Scripts脚本(同步)
调用脚本并等待服务器完成请求,然后再执行其他代码。
lims.CallServer("server script脚本路径",[方法参数集合]);
示例:
async function btAdd_OnClick( sender, eventArgs )
{
// String 装 int类型
var num1 = parseInt(txtA.Text);
// String 装 int类型
var num2 = Int32.Parse(txtB.Text);
var res = num1 + num2;
alert(res);
}
async function btRemoteAdd_OnClick( sender, eventArgs )
{
var num1 = parseInt(txtA.Text);
var num2 = Int32.Parse(txtB.Text);
var sum = lims.CallServer("ZZZ.WSTEST001", [num1, num2]);
alert(sum);
}
异步调用Server Scripts脚本(async是立即返回的)
调用该脚本,而不等待服务器完成该请求。
lims.CallServerAsync("脚本路径",[方法参数集合]);
【注意】:
使用await调用lims.CallServerAsync()函数,就是同步执行了!!!
示例:
async function btnLong_OnClick( sender, eventArgs )
{
var a = parseInt(txtA.Text);
var b = Int32.Parse(txtB.Text);
try {
// 同步执行
// var result = lims.CallServerAsync("ZZZ.LongResponse",[a,b]);
var result = await lims.CallServerAsync("ZZZ.LongResponse",[a,b]);
alert("I got the result from the long script and it is " + result.toString());
}
catch(error) {
alert("The long Script generated an exception and the detail is " + error);
}
finally {
alert("This is the finally");
}
}
ZZZ.LongResponse(SSL)代码:
:PARAMETERS a,b;
:DEFAULT a, 5;
:DEFAULT b, 7;
:DECLARE number, startTime, endTime;
number := 0;
startTime := Now();
usrmes("startTime:Hour: ", startTime:Hour);
usrmes("startTime:Minute ", startTime:Minute);
usrmes("startTime:Second ", startTime:Second);
:WHILE (number +=1) < 1000;
usrmes(" " + str(number) + " ");
:ENDWHILE;
endTime := Now();
usrmes("endTime:Hour: ", endTime:Hour);
usrmes("endTime:Minute ", endTime:Minute);
usrmes("endTime:Second ", endTime:Second);
:RETURN a+b;
吐槽一下:
SSL处理while循环的10000条打印输出,要四十几秒,而java只要几十毫秒,1s不到。
两种打开弹出窗口的方式:
模态形式已经抓住了用户的焦点,直到被驳回。
示例:
async function btShowModalDialog_OnClick( sender, eventArgs )
{
form.ShowModalDialog(lims.GetFormSource("SampleReception.frmLocationManagement_Covid"));
}
Modeless允许您返回到调用表单。
示例:
async function btShowModelessDialog_OnClick( sender, eventArgs )
{
form.ShowModelessDialog(lims.GetFormSource("SampleReception.frmLocationManagement_Covid"));
}
【注意】:
弹窗右上角的×,是默认自动回带的。可以点击关闭弹窗。
当弹出窗口打开时,打开窗口传入的参数可以通过表单的这个属性作为数组访问。
async function btShowModalDialog_OnClick( sender, eventArgs )
{
alert(txtFirst.Text);
var augments = [txtFirst.Text, "999"];
// 弹窗传值,用数组形式!!!
var returnValue = await form.ShowModalDialog(lims.GetFormSource("WsTest.popupForm2"), augments);
// 获取弹出窗口的返回值。
if(returnValue != null){
txtFirst.Text = returnValue[1];
}else{
txtFirst.Text = "ppp";
}
}
打开的弹窗:
async function Form1_OnLoad( sender, eventArgs )
{
if(form.formArguments != null){
var ds0 = form.formArguments[0];
txtFirst.Text = ds0;
}else{
txtFirst.Text = "222";
}
}
async function btClose_OnClick( sender, eventArgs )
{
// 返回值
form.returnValue = [txtSecond.Text, txtFirst.Text];
form.Close();
}
任何需要传递回ShowModalDialog()的数据都可以作为数组加载到表单的这个属性中,并在表单关闭时传递。
示例:
form1:
async function btEdit_OnClick( sender, eventArgs )
{
var initialData = [lblFname.Text, lblLname.Text, lblEmail.Text];
// alert(initialData);
var editData = await form.ShowModelessDialog(lims.GetFormSource("WsTest.editPersion"), initialData);
FillControll(editData);
}
function FillControll(data)
{
if(data != null){
lblFname.Text = data[0];
lblLname.Text = data[1];
lblEmail.Text = data[2];
}
}
async function btClose_OnClick( sender, eventArgs )
{
await form.Close();
}
edit form2:
async function Form1_OnLoad( sender, eventArgs )
{
// 获取form1的传值
var persionData = form.formArguments;
if(persionData != null){
txtFName.Text = persionData[0];
txtLname.Text = persionData[1];
txtEmail.Text = persionData[2];
}
}
async function btOk_OnClick( sender, eventArgs )
{
// 将值返回给form1
form.returnValue = [txtFName.Text, txtLname.Text, txtEmail.Text];
form.Close();
}
当function定义在另一个form中时,从当前form以外调用函数。
示例:以上示例,改成在edit form2中点击apply按钮,调用form1中的FillControll()函数,以实现在form2中修改的textbox中的值能回传到form1中
form1:
async function btEdit_OnClick( sender, eventArgs )
{
var initialData = [lblFname.Text, lblLname.Text, lblEmail.Text];
// alert(initialData);
var editData = await form.ShowModelessDialog(lims.GetFormSource("WsTest.editPersion"), initialData);
// FillControll(editData);
}
function FillControll(data)
{
if(data != null){
lblFname.Text = data[0];
lblLname.Text = data[1];
lblEmail.Text = data[2];
}
}
async function btClose_OnClick( sender, eventArgs )
{
await form.Close();
}
edit form2:
async function Form1_OnLoad( sender, eventArgs )
{
var persionData = form.formArguments;
if(persionData != null){
txtFName.Text = persionData[0];
txtLname.Text = persionData[1];
txtEmail.Text = persionData[2];
}
}
async function btOk_OnClick( sender, eventArgs )
{
form.returnValue = [txtFName.Text, txtLname.Text, txtEmail.Text];
form.Close();
}
async function btApply_OnClick( sender, eventArgs )
{
var openForm = form.opener;
// 调用form1中的函数
openForm.ExecFunction("FillControll", [GetEditValues()]);
}
function GetEditValues(){
return [txtFName.Text, txtLname.Text, txtEmail.Text];
}
只要form open,变量值就一直存在。
只要浏览器打开,变量值就一直存在。
范围:form。
form.Variables["company"] = "STARLIMS Corp.";
alert(form.Variables["company"]);
范围:浏览器。
navigator.Variables["city"] = "Hollywood, FL.";
alert(navigator.Variables["city"]);
【示例1】:在当前同一个form中不同的scripts之间交换数据。
【示例2】:可以在navigator变量中存放任意类型,甚至是一个form引用。
form1:
async function btOpen_OnClick( sender, eventArgs )
{
// form.ShowModelessDialog(lims.GetFormSource("WsTest.wsPopupTest"), null, "BorderStyle=FixedToolWindow");
form.ShowModelessDialog(lims.GetFormSource("WsTest.wsPopupTest"));
}
async function bt_close_OnClick( sender, eventArgs )
{
var frmpop = navigator.Variables["formPop"];
if(frmpop != null){
navigator.Variables.Remove("formPop");
frmpop.Close();
}else{
alert("111");
}
}
form2:
async function Form1_OnLoad( sender, eventArgs )
{
// 放了当前的form
navigator.Variables.Set("formPop", form);
}
类型:
Dialogs.MessageBox(message, caption, buttons, icon);
【示例】:
async function btMessageBox_OnClick( sender, eventArgs )
{
var res1 = Dialogs.MessageBox(form.Resources["hello1"]);
var res2 = Dialogs.MessageBox(form.Resources["hello2"], form.Resources["welcome"]);
var res3 = Dialogs.MessageBox(form.Resources["saveFailed"], form.Resources["warning"], "AbortRetryIgnore");
var res3 = Dialogs.MessageBox(form.Resources["saveFailed"], form.Resources["star"], "AbortRetryIgnore", "Warning");
}
async function btInputBox_OnClick( sender, eventArgs )
{
var s1 = Dialogs.InputBox("John Doe", form.Resources["entryName"]);
var s2 = Dialogs.InputBox("John Doe", form.Resources["entryName"], form.Resources["editPers"]);
var s3 = Dialogs.InputBox("John Doe", form.Resources["entryName"],form.Resources["editPers"], lims.GetDataSource("QUICKINTRO.GETNAMES"));
alert(form.Resources["inputMes"]+s1+form.Resources["mes2"]+s2+form.Resources["mes3"]+s3);
}
async function btMultiChoiceDialog_OnClick( sender, eventArgs )
{
var data = lims.GetDataSource("QUICKINTRO.GETNAMES");
var arr1 = Dialogs.ShowMultiChoiceDialog("please select users", "team members", data);
// 初始就已选中两项
var arr2 = Dialogs.ShowMultiChoiceDialog("please select users", "team members", data, ["John Doe", "Fred Pelish"]);
//先alert,再展示MultiChoiceDialog
alert("your selection:\n Dialog 1: " + arr1 + "\n Dialog 2: " + arr2);
}
async function btCheckListBoxDialog_OnClick( sender, eventArgs )
{
var data = lims.GetDataSource("QUICKINTRO.GETNAMES");
var arr1 = await Dialogs.ShowCheckListBoxDialog("please select users", "team members", data);
var arr2 = await Dialogs.ShowCheckListBoxDialog("please select users", "team members", data, ["John Doe", "Fred Pelish"]);
alert("your selection:\n Dialog 1: " + arr1 + "\n Dialog 2: " + arr2);
}
打开文件窗口
【示例】:
async function btOpenFileDialog_OnClick( sender, eventArgs )
{
var file = await Dialogs.ShowOpenFileDialog();
alert("select files:" + file);
}
颜色弹窗。
【示例】:
async function btColorDialog_OnClick( sender, eventArgs )
{
var color1 = await Dialogs.ShowColorDialog();
var color2 = await Dialogs.ShowColorDialog("#FF00FF");
alert(form.Resources["selectColors"] + color1 + form.Resources["selectColor2"] + color2);
}
窗体程序有很多的事件,比如按钮点击事件,双击事件,Form_Load事件,这些事件的实现里都有两个参数:一个是object类型的sender参数,另一个是派生自EventArgs类。
Sender参数指的是引发事件的对象。在事件处理程序中,我们经常需要知道是哪个对象引发了事件。通过sender参数,我们可以按需要访问该对象并执行相应的操作。
例如:button的点击事件,那么这个sender就代表这个button自己。
示例:点击左边的按钮,在右边的输入框中显示点击过的按钮的text。
function handlePhoneKey( sender){
// 使用sender参数,获取触发事件的对象
var key = sender.Text;
if((key != '#') && (key != '*') ){
txtPhoneNo.Text += key;
}
}
每一个按钮的onclick事件都添加这个函数。
记录事件传递过来的额外信息。
一般用于传递用户点击的位置啊,键盘按下的键等事件的额外信息。
例如鼠标点击的位置、按下、释放等信息。
示例:
async function callBt_OnClick( sender, eventArgs )
{
var btn = sender.Text;
alert("You clicked button " + btn);
// 调用Form1_OnClose()函数
form.Close();
}
async function Form1_OnClose( sender, eventArgs )
{
var ret = await Dialogs.MessageBox(form.Resources["cancelo"], form.Resources["question"], "YesNoCancel", "Question");
eventArgs.Set("Cancel", ret != "Yes");
}
在一个form中插入另一个form,使用frame控件
示例:
async function bt_frameShow_OnClick( sender, eventArgs )
{
// 有进度条可以拖动内容
//frameShow.ContentOverflow = "SCROLL";
// 没有进度条可以拖动内容
frameShow.ContentOverflow = "ANCHOR";
// 在frame中展示另一个form的页面
await frameShow.Navigate(lims.GetFormSource("SampleReception.frmLocationManagement_Covid"));
}
示例:点击一个按钮,动态创建另一个按钮。
async function button1b_OnClick( sender, eventArgs )
{
var btnDynamic = new Button();
btnDynamic.Id = "btnDynamic";
btnDynamic.Text = "dynamic button new";
btnDynamic.Left = 140;
btnDynamic.Top = 140;
btnDynamic.Width = 160;
btnDynamic.OnClick = "HandleBtnDynamic(sender, eventArgs)";
// 将控件添加到form中
form.Controls.Add(btnDynamic);
}
async function HandleBtnDynamic( sender, eventArgs )
{
await Dialogs.MessageBox(form.Resources["message"] + sender.Id);
}