提示用户选择列是JMP脚本中非常常见的任务。在编写脚本时,需要考虑一些因素,以帮助您确定最佳方法。
首先,想想你希望窗口的外观如何。除了选择列之外,窗口是否应该允许用户指定其他选项?最重要的是,你希望窗口如何运行?
模态窗口与非模态窗口
模态窗口会导致脚本暂停并等待用户交互。用户与窗口交互并将其关闭后,脚本的剩余部分才会继续执行。例如,“首选项”窗口(“文件”>“首选项”)就是一个模态窗口。在“首选项”窗口关闭之前,JMP 不会执行任何其他操作。
使用非模态窗口,窗口会保持打开状态,脚本无需等待任何用户交互即可完成。例如,Fit Model 平台启动窗口(分析 > Fit Model)。请注意,您可以保持窗口打开并在 JMP 中执行其他任务。甚至还有一个复选框,用于在分析创建完成后保持对话框打开。这就是非模态窗口的示例。您可以选择使用保持打开状态的非模态窗口,以便用户可以选择不同的列和角色。
那么,如何决定使用模态窗口还是非模态窗口呢?主要考虑因素是您是否希望 JMP 等待用户输入。如果脚本的其余部分依赖于用户的选择,那么您应该使用模态窗口。由于创建模态窗口有两种常用方法,让我们来探讨一下这些选项。
列对话框()
ColumnDialog() 是一个内置函数,可用于快速生成模态对话框,提示用户从当前数据表中选择列。脚本编写者只需选择对话框中显示的框类型,但对布局几乎没有控制权。以下示例脚本提示用户选择两列 X 轴列和两列 Y 轴列。
Names Default To Here( 1 );
dt = Open( "$SAMPLE_DATA/Fitness.jmp" );
dlg = Column Dialog(
yList = Col List( "Y",
Min Col( 2 ),
Max Col( 2 ),
Data Type( "Numeric" )
),
effectList = Col List( "Effects",
Min Col( 2 ),
Max Col( 3 ),
Data Type( "Numeric" )
)
);
向用户显示的窗口如下所示:

请注意,脚本作者只提供了两个“列列表”显示框的选项。左侧当前数据表中的列列表是内置功能的一部分。
用户做出选择并点击确定后,结果会显示用户选择的列表,例如:
dlg = {yList = {:Age, :Oxy}, effectList = {:RunPulse, :RstPulse}, Button(1)};
列表中的各个表达式不会被求值。因此,要使用选定的列,您可以通过几种方式卸载列列表以供分析使用。例如,您可以将dlg列表变量设为下标,并将列列表分配给一个新变量,或者您可以使用相同的名称:
yList = dlg["yList"];
effectList = dlg["effectList"];
另一种卸载列列表的方法是使用 `Eval List()` 函数来评估 `dlg` 列表变量中的项。在评估列表中的其他项之前,会先移除 `dlg` 列表中的最后一个项,因为`Button(1)`不需要任何评估。
Eval List( Remove( dlg, -1 ) )
现在,如果您运行显示符号 ();您将看到所有已定义的变量,并且列选择存储在 yList 和 effectList 变量中。
// Here
dlg = {yList = {:Age, :Oxy}, effectList = {:RunPulse, :RstPulse}, Button( 1 )};
dt = Data Table( "Fitness" );
effectList = {:RunPulse, :RstPulse};
yList = {:Age, :Oxy};
// 4 Here
无论你选择哪种方法来卸载这些值,都可以在分析中使用 yList 和 effectList 变量:
fm = dt << Fit Model(
Y( Eval( yList ) ),
Effects( Eval( effectList ) ),
Personality( "Standard Least Squares" ),
Emphasis( "Effect Leverage" ),
Run
);
那么,使用 ColumnDialog() 时需要考虑哪些主要因素呢?
- 当前数据表中的列选择器始终存在。虽然这在需要用户选择列时很方便,但也限制了此类模态窗口的使用。
- 您需要编写的脚本代码量相当少。您可能会发现内置功能完全能够满足您的需求。但是,自定义功能有限。例如,只有三个构造函数可以控制窗口中显示框的排列方式:HList()、VList() 和 Line Up Box()。
- ColumnDialog() 函数返回的值是固定的。作为脚本编写者,您应该知道 ColumnDialog() 函数始终会返回一个需要提取的值列表。缺点是需要额外的步骤来卸载这些值,并且在检索用户选择的方式上灵活性较低。
有关 Column Dialog() 可用构造函数的完整列表,请查看脚本指南中“显示树”章节的“Column Dialogs 构造函数”部分。
新建窗口()
`New Window()` 是一个内置函数,可用于生成模态或非模态窗口,其用途广泛,例如提示用户选择列,或向用户显示重要信息。由于提供了数量众多且种类繁多的显示框,您可以使用 `New Window()` 创建高度自定义的模态窗口。
随着自定义选项的增加,需要编写的代码量也随之增加。以下示例展示了一个与上面所示的“列对话框”类似的窗口。请注意,某些显示框的名称相似。例如,“垂直列表框”、“水平列表框”、“面板框”和“列列表框”用于控制窗口的布局。其余显示框则是窗口中可见的元素,例如按钮和列列表。
Names Default To Here( 1 );
dt = Open( "$SAMPLE_DATA/Fitness.jmp" );
nw = New Window( "Launch Dialog",
<
<MODAL>
V List Box( Align( "right" ),
<STRONG>H List Box</STRONG>(
<STRONG>Panel Box</STRONG>( "Select Columns", clb = Filter Col Selector( dt, all ) ),
<STRONG>Panel Box</STRONG>( "Cast Selected Columns into Fit Model Roles",
<STRONG>Lineup Box</STRONG>( N Col( 2 ), Spacing( 5 ), Button Box( "Y", clbY << Append( clb << Get Selected ) ), clbY = Col List Box( "Numeric", MinItems( 2 ), MaxItems( 2 ), nlines( 3 ) ), Button Box( "Effects", clbEffects << Append( clb << Get Selected ) ), clbEffects = Col List Box( "Numeric", MinItems( 2 ), MaxItems( 3 ), nlines( 4 ) ), Button Box( "Remove", clbY << Remove Selected; clbEffects << Remove Selected; ) ) ) ),
<STRONG>H List Box</STRONG>( Button Box( "OK", yVars = clby << Get Items( "Column Reference" ); eVars = clbEffects << Get Items( "Column Reference" ); ), Button Box( "Cancel" ) ) ) );
</MODAL>
向用户显示的窗口如下所示:

在这个示例窗口的脚本编写方式中,“确定”按钮会将选定的列赋值给 JSL 变量。您可能会想到,也可以在“Y”按钮和“效果”按钮的脚本中赋值列,作为一种替代方案。这确实可行。但是,由于用户可以将列拖放到列列表框中,这些按钮可能永远不会被点击。因此,按钮脚本将永远不会执行。有关其他方法,请参阅脚本编写指南中“显示树”章节的“从窗口提取值”部分。
运行展示 ( yVars, eVars );将在日志中列出这些值(查看 > 日志):
yVars = {:Age, :Oxy};
eVars = {:RunPulse, :RstPulse};
这些变量无需卸载即可在 Fit 模型启动中使用。
fm = dt << Fit Model(
Y( Eval( yVars ) ),
Effects( Eval( eVars ) ),
Personality( "Standard Least Squares" ),
Emphasis( "Effect Leverage" ),
Run
);
不要被大量的脚本代码吓到。我们来看看这个模态新窗口 (New Window()) 中可用的一些自定义选项。以下项目与上图中的数字相对应。
- New Window() 函数允许您为脚本项目提供一个有意义的窗口标题。在本例中,我们使用了简单的标题“启动对话框”。
- 分组上方显示的文字可以自定义。这样,您可以为用户提供分组的简短说明或描述。
- 可以通过 `Col List Box()` 函数的可选参数来指定显示的行数,该函数用于显示选定的列。这样,您可以控制显示框中显示的列数。您还可以为了美观而添加额外的空间,如上图所示。
- 列列表可以来自任何已打开的数据表,而不仅仅是当前打开的表。请记住,`New Window()` 函数可用于各种对话消息传递。因此,显示列列表是可选的。
- “确定”按钮可以自定义功能。此外,“取消”按钮是可选的。
New Window() 函数提供了比这里演示的更多的构造函数,例如滑块、单选按钮、图片、图表等等!要查看 New Window() 函数可用的构造函数列表,请参阅脚本编写指南中“显示树”章节的“为 New Windows 构建显示框”部分。
总而言之,`ColumnDialog()` 提供了一种快速简便的窗口创建方式,但自定义功能有限。另一方面,模态的 `NewWindow()` 提供了极大的自定义灵活性,但创建时需要更多的思考和脚本编写。显然,这两种方法各有优势,我猜您最终都会发现它们的用武之地。幸运的是,您的工具箱里完全可以容纳它们!