全て、
次の問題があります。 複数のテーブルとウィンドウを開いたり閉じたりするスクリプトがあり、これを処理するためにいくつかの名前空間を作成します。 また、メインウィンドウの<< On Close()でこれらの名前空間を削除します。
スクリプトの2つのインスタンスを実行しているときに、一方のメインウィンドウを閉じると名前空間が削除され、もう一方のスクリプトが壊れることがわかりました。
インスタンスごとに名前空間を分離するにはどうすればよいですか、あるいは、script \ add-inの1つのインスタンスのみを実行できるようにするにはどうすればよいですか?
私はそれを理解しています
ns = New Namespace();
nsは参照であり、名前空間が作成されるたびに割り当てられる「#43」のような一意の名前があります。 その名前は< ns実行中のスクリプトインスタンスの1つで、「#43」を参照しています。 ns別の実行中のインスタンスでは、たとえば「#44」を参照していますか?
アプリケーションによって異なります。 たとえば、次のようになります。
- 特定のウィンドウ名が存在するかどうかを確認します
- 名前空間を使用して、それらがすでに存在するかどうかを確認します
次に、それらが存在するかどうかに基づいて、何らかのアクションを実行します。
スクリプトガイド>プログラミングメソッド>高度なスコープと名前空間(help、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>2 つのグローバル関数を既に読み込んでいる場合は、それらをスクリプトから除外することができます。これらは、名前空間内の関数を変更して、それらがどの名前空間にあるかを認識できるようにするだけでなく、 <<関数の設定( ... )表示ツリーのメソッドを使用して、スコープ名前空間内の関連する関数を呼び出します。また、これにより自動的に<<クローズ時()を実行するウィンドウのメソッドself:on close()関数 (存在する場合)。
これにより、デフォルトでスコープが削除されることに注意してください自己ウィンドウを閉じたときの名前空間。これは必ずしも望ましい動作ではありませんが、この単純なデモでは十分です。
スクリプトの最後の 2 行はそれぞれウィンドウを開きますが、それらの間にクロストークはありません (ボタンを押すことでいくつかのテーブルを読み込むことができ、ウィンドウが閉じられるとテーブルも自動的に閉じられます)。
こんにちは@miguello 、
ご指摘のとおり、変数 ns は名前空間だけでなくスクリプトごとに一意である必要があります。 @jthi はNames Default to here(1) を使用してこの問題を解決しています。これを明示的に定義し、動作をよりよく理解するには、次の 2 行をいくつかの異なるウィンドウで実行してみてください。
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);
スクリプトの先頭に を追加すると、問題が解決する可能性があります。また、そこにあったすべての変数を here 名前空間に配置することで、新しい名前付き名前空間の作成を完全に回避できる場合もあります。
インスタンスというのは、複数のインクルードを行うという意味ですか?それとも関数のようなものですか?
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式すら必要ありません。
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}));