全部,
我有以下问题。 我有一个打开\关闭多个表和窗口的脚本,我创建了几个命名空间来处理这个问题。 我还在主窗口的 <
我发现当我有两个脚本实例运行时,在其中一个中关闭主窗口会删除命名空间并破坏另一个脚本。
如何使每个实例的命名空间分开,或者,我如何只允许脚本\加载项的一个实例运行?
我明白在
ns = New Namespace();
ns是一个引用,并且有一个唯一的名称,例如每次创建命名空间时分配的“#43”。 我可以通过 < ns在一个正在运行的脚本实例中是指“#43”,并且ns在另一个正在运行的实例中指的是,比如说,“#44”?
取决于应用程序。 例如,您可以:
- 检查特定窗口名称是否存在
- 使用命名空间并检查它们是否已经存在
然后根据它们是否存在执行一些操作。
脚本指南 > 编程方法 > 高级范围和命名空间(帮助,jmp.com)读起来还算不错
Names Default To Here(1);
// Delete Namespaces()
ns1 = New Namespace("AA");
show(ns1);
ns1 = New Namespace();
ns3 = New Namespace();
show(Get Namespace Names());
show(ns1);
If(Contains(Get Namespace Names(), "AA"),
ns1 = Namespace("AA");
);
show(ns1);
If(Contains(Get Window List() << Get Window Title, "window_title"),
Window("window_title") << Bring Window To Front;
Throw("Window already exists...");
);在 JMP 中进行适当的范围控制和资源管理可能会很棘手——JMP 对象数据表() , 和命名空间()只会从内存中显式释放,而不会通过取消引用来释放。
出于我的目的,我创建了一个元编程库,它可以处理所有必要的范围管理和资源控制(因为它是我工作的一部分,我不能共享文件),但有点像这里:
::modify display tree functions = Function( {self, display tree},
{Default Local},
box types = {"TextEditBox", "ButtonBox", "ListBoxBox"}; // Add others here
For( i = 1, i <= N Items( box types ), i++,
boxes = display tree << XPath( "//" || box types[i] );
For( j = 1, j <= N Items( boxes ), j++,
box = boxes[j];
function = Parse( Char( box << Get Function ) );
If( Try( Is Missing( function ), 0 ), Continue() ); // no function set
If( Head Name( function ) != "Function",
arg = Name Expr( function );
If( Head Name( arg ) != "Glue", // function is the right type -- a single call
new arg = Eval Expr( Glue( self = Namespace( Expr( self << Get Name ) ) ) );
Insert Into( new arg, Parse( "self:" || Char( Name Expr( arg ) ) ) );
Eval( Substitute( Expr(
box << Set Function( Local( {self}, __expr__ ) )
)
,
Expr( __expr__ ), Name Expr( new arg )
) )
)
,
arg = Arg( function, N Arg( function ) );
If( Head Name( arg ) != "Glue", // function is the right type -- a single call
new arg = Eval Expr( Glue( self = Namespace( Expr( self << Get Name ) ) ) );
Insert Into( new arg, Parse( "self:" || Char( Name Expr( arg ) ) ) );
Eval( Substitute( Expr(
box << Set Function(
Function( __args__,
{self},
__expr__
)
)
),
Expr( __args__ ), Arg( function, 1 )
,
Expr( __expr__ ), Name Expr( new arg )
) )
)
);
)
)
);
::inject self namespace = Function( {script},
{Default Local},
self = New Namespace();
script = Arg( script, 1 );
windows = {};
For( i = 1, i <= N Arg( script ), i++,
arg i = Arg( script, i );
If( Head Name( arg i ) == "Assign",
Remove From( script, i );
Insert Into( script,
Substitute(
Expr( Assign( _a_, _b_ ) )
,
Expr( _a_ ), Parse( "self:" || Char( Arg( arg i, 1 ) ) )
,
Expr( _b_ ), Arg( arg i, 2 )
)
,
i
);
arg i = Arg( script, i )
);
If( Head Name( arg i ) == "Assign" & As Name( Head Name( Arg( arg i, 2 ) ) ) == As Name( "New Window" ),
Insert Into( windows, Char( Arg( arg i, 1 ) ) )
);
If( Head Name( arg i ) == "Assign" & Head Name( Arg( arg i, 2 ) ) == "Function",
Remove From( script, i );
Insert Into( script,
Substitute( Expr(
Assign( _arg1_, Function( _args_,
{Default Local},
_script_
) )
),
Expr( _arg1_ ), Arg( arg i, 1 )
,
Expr( _args_ ), Arg( Arg( arg i, 2 ), 1 )
,
Expr( _script_ ), If( Head Name( Arg( Arg( arg i, 2 ), N Arg( Arg( arg i, 2 ) ) ) ) == "Glue",
Insert( Arg( Arg( arg i, 2 ), N Arg( Arg( arg i, 2 ) ) ),
Eval Expr( self = Namespace( Expr( self << Get Name ) ) ),
1
)
,
Eval Expr(
Glue(
self = Namespace( Expr( self << Get Name ) ),
Expr( Arg( Arg( arg i, 2 ), N Arg( Arg( arg i, 2 ) ) ) )
)
)
)
)
,
i
)
)
);
Insert Into( script, 0 );
Eval( script );
For( w = 1, w <= N Items( windows ), w++,
win = Eval( Parse( windows[w] ) );
::modify display tree functions( self, win );
Eval( Eval Expr(
win << On Close(
Local( {self = Namespace( Expr( self << Get Name ) )},
Try( self:on close );
Delete Namespaces( Force( 1 ), self )
)
)
) )
);
self
);
script = {
a = 1;
__tables = {};
add table = Function( {_table},
Insert Into( self:__tables, _table )
);
close tables = Function( {},
For( i = 1, i <= N Items( self:__tables ), i++,
Try( Close( self:__tables[i], No Save ) )
)
);
func = Function( {b},
Show( b + self:a )
);
on close = Function( {},
Print( "Closing!!" );
self:close tables;
);
run button = Function( {},
Print( "You pressed the button" );
table = Open( "$SAMPLE_DATA/Big Class.jmp" );
self:add table( table << Subset( All Rows, All Columns, Not Linked ) );
Close( table, No Save );
);
win = New Window( "teest",
List Box( {"A","B"}, <<SET function=""></SET>如果您已经加载了这两个全局函数,那么您可以将它们排除在脚本之外——它们用于修改命名空间中的函数以了解它们所在的命名空间,以及修改<<设置函数( ... )显示树的方法来调用作用域命名空间内的相关函数。此外,这将自动设置<<关闭时()运行窗口的方法自我:关闭()函数(如果存在)。
请注意,默认情况下,这将删除范围自己窗口关闭时的命名空间。这并不总是需要的行为,但对于这个简单的演示来说就足够了。
脚本的最后两行各打开一个窗口,但它们之间没有串扰(您可以通过按下按钮加载一些表格,当窗口关闭时表格也会自动关闭)
嗨@miguello ,
正如您所指出的,您需要变量 ns 对每个脚本都是唯一的,而不仅仅是命名空间。 @jthi使用名称默认为 here(1) 解决了这个问题。要明确定义这一点,也许更好地理解它的工作原理,请尝试在几个不同的窗口中运行这两行,
here:ns = New Namespace();
here:ns:a = random normal();
然后使用
show namespaces()
查看每个命名空间中的 a 的值。调用
here:ns:a
从每个单独的窗口将返回该窗口的值。在另一个窗口中,运行以下命令:
Names default to here(1);
ns = New Namespace();
ns:a = random normal();
并注意它的行为方式与上一个示例相同。尝试不使用此处命名空间,所有对 a 的引用都将返回相同的值,表明它们来自同一命名空间。
所以,只要
Names default to here(1);
脚本顶部的可能会解决您的问题。您还可以通过将那里的所有变量都放在此处的命名空间中来完全避免创建新的命名命名空间。
你说的“实例”是指多次包含吗?还是像函数一样?
Names default to here(1);
create_instance = function({ns},
Eval(EvalExpr(
nw = new window("Test",
window:ns = namespace(Expr(ns << Get name()));
<< On Close(
Delete Namespaces(force(1), window:ns);
),
Buttonbox("Press Me",
print(window:ns << Get name());
show(window:ns:x, window:ns:y);
)
)
));
);
create_instance(ns1 = new namespace({x=14;y=28}));
create_instance(ns2 = new namespace({x=140;y=280}));
这对我有用。
*编辑* 其实更简单。你甚至不需要 eval expr,因为它不是运行时的东西。
create_instance = function({ns},
nw = new window("Test",
window:ns = ns;
<< On Close(
Delete Namespaces(force(1), window:ns);
),
Buttonbox("Press Me",
print(window:ns << Get name());
show(window:ns:x, window:ns:y);
)
)
);
create_instance(ns1 = new namespace({x=14;y=28}));
create_instance(ns2 = new namespace({x=140;y=280}));