全部,
我有以下問題。 我有一個打開\關閉多個表和窗口的腳本,我創建了幾個命名空間來處理這個問題。 我還在主窗口的 <
我發現當我有兩個腳本實例運行時,在其中一個中關閉主窗口會刪除命名空間並破壞另一個腳本。
如何使每個實例的命名空間分開,或者,我如何只允許腳本\加載項的一個實例運行?
我明白在
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使用此處的預設名稱解決了這個問題(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();
並注意它的行為方式與前面的範例相同。嘗試在沒有here命名空間的情況下,所有對 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}));