Alle,
Ich habe folgendes Problem. Ich habe ein Skript, das mehrere Tabellen und Fenster öffnet/schließt, und ich erstelle mehrere Namespaces, um dies zu handhaben. Ich lösche diese Namensräume auch in <
Ich habe festgestellt, dass, wenn zwei Instanzen des Skripts ausgeführt werden, das Schließen des Hauptfensters in einem von ihnen die Namespaces löscht und das andere Skript beschädigt.
Wie kann ich Namespaces für jede Instanz separat erstellen oder alternativ nur eine Instanz des Skripts/Add-Ins ausführen lassen?
Ich verstehe das in
ns = New Namespace();
ns ist eine Referenz, und es gibt einen eindeutigen Namen wie "#43", der jedes Mal zugewiesen wird, wenn ein Namespace erstellt wird. Ich kann diesen Namen mit < ns in einer laufenden Skriptinstanz bezieht sich auf "#43", und ns in einer anderen laufenden Instanz bezieht sich beispielsweise auf "#44"?
Hängt von der Anwendung ab. Sie könnten zum Beispiel:
- Überprüfen Sie, ob ein bestimmter Fenstername existiert
- Verwenden Sie benannte Namensräume und prüfen Sie, ob diese bereits vorhanden sind
und führen Sie dann eine Aktion aus, je nachdem, ob sie vorhanden sind oder nicht.
Scripting Guide > Programming Methods > Advanced Scoping and Namespaces (Hilfe, jmp.com) ist ziemlich gut zu lesen
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...");
);Die richtige Bereichssteuerung und Ressourcenverwaltung in JMP kann schwierig sein – die JMP-Objekte Datentabelle() , und Namensraum() werden immer nur explizit aus dem Speicher freigegeben und niemals durch Dereferenzierung.
Für meine Zwecke habe ich eine Meta-Programmierbibliothek erstellt, die die gesamte erforderliche Bereichsverwaltung und Ressourcensteuerung handhaben kann (da dies Teil meiner Arbeit ist, kann ich die Dateien nicht freigeben), aber etwas Ähnliches ist hier:
::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>Wenn Sie die beiden globalen Funktionen bereits geladen haben, können Sie sie aus dem Skript heraushalten – sie dienen dazu, die Funktionen innerhalb des Namensraums zu ändern, um zu wissen, in welchem Namensraum sie sich befinden, und um die zu ändern <<FUNKTION setzen=""> Methoden des Anzeigebaums, um die relevanten Funktionen innerhalb des Scoping-Namensraums aufzurufen.Außerdem wird dies automatisch eingestellt<CODE class=" language-jsl"> <<BEIM schließen=""> Methode des Fensters zum Ausführen der<CODE class=" language-jsl"> selbst: beim Schließen () Funktion (falls vorhanden).
Beachten Sie, dass dadurch standardmäßig der Bereich gelöscht wird selbst Namespace, wenn das Fenster geschlossen wird.Dies ist nicht immer das gewünschte Verhalten, aber für diese einfache Demo reicht es aus.
Die letzten beiden Zeilen des Skripts öffnen jeweils ein Fenster, aber es gibt kein Übersprechen zwischen ihnen (Sie können einige Tabellen laden, indem Sie auf die Schaltfläche klicken, und wenn das Fenster geschlossen wird, werden die Tabellen automatisch auch geschlossen)
Hallo @miguello ,
Wie Sie bereits erwähnt haben, muss die Variable ns für jedes Skript eindeutig sein, nicht nur für den Namespace. @jthi löst dies mit Names Default to here(1). Um dies explizit zu definieren und vielleicht besser zu verstehen, wie es funktioniert, führen Sie diese beiden Zeilen in einigen verschiedenen Fenstern aus:
here:ns = New Namespace();
here:ns:a = random normal();
und dann verwenden
show namespaces()
um den Wert von a in jedem Namespace anzuzeigen. Aufruf
here:ns:a
aus jedem einzelnen Fenster gibt den Wert dieses Fensters zurück. Führen Sie in einem anderen Fenster Folgendes aus:
Names default to here(1);
ns = New Namespace();
ns:a = random normal();
und beachten Sie, dass es sich genauso verhält wie im vorherigen Beispiel. Versuchen Sie das ohne den here-Namespace und alle Verweise auf a geben denselben Wert zurück, was darauf hinweist, dass sie aus demselben Namespace stammen.
Setzen Sie also einfach
Names default to here(1);
am Anfang Ihres Skripts könnte Ihr Problem beheben. Sie können möglicherweise auch die Erstellung neuer benannter Namespaces vollständig vermeiden, indem Sie alle Variablen, die Sie dort hatten, stattdessen direkt in den hier vorhandenen Namespace einfügen.
Wenn Sie Instanzen sagen, meinen Sie damit, dass Sie mehrere Includes durchführen? Oder wie bei einer Funktion?
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}));
Das funktioniert bei mir.
*Bearbeiten* Eigentlich ist es sogar noch einfacher. Sie brauchen den Eval-Ausdruck nicht einmal, da es sich nicht um eine Laufzeitsache handelt.
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}));