Tutto,
Ho un seguente problema. Ho uno script che apre\chiude più tabelle e finestre e creo diversi spazi dei nomi per gestirlo. Elimino anche quegli spazi dei nomi in <
Ho scoperto che quando ho due istanze dello script in esecuzione, chiudendo la finestra principale in una di esse si eliminano gli spazi dei nomi e si interrompe l'altro script.
Come faccio a separare gli spazi dei nomi per ogni istanza o, in alternativa, come posso consentire solo a un'istanza dello script\add-in in esecuzione?
Lo capisco dentro
ns = New Namespace();
ns è un riferimento ed è presente un nome univoco, come "#43", che viene assegnato ogni volta che viene creato uno spazio dei nomi. Posso ottenere quel nome da < ns in un'istanza di script in esecuzione si riferisce a "#43" e ns in un'altra istanza in esecuzione si riferisce, diciamo, a "#44"?
Dipende dall'applicazione. Potresti ad esempio:
- Verificare se esiste un nome specifico della finestra
- Usa gli spazi dei nomi con nome e controlla se esistono già
e quindi eseguire alcune azioni in base al fatto che esistano o meno.
Guida agli script > Metodi di programmazione > Scoping avanzato e spazi dei nomi (guida, jmp.com) si legge abbastanza bene
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...");
);Fare un controllo dell'ambito e una gestione delle risorse adeguati in JMP può essere complicato: gli oggetti JMP Tabella dati() , e Spazio dei nomi() sono sempre e solo esplicitamente liberati dalla memoria e mai per dereferenziazione.
Per i miei scopi ho creato una libreria di meta-programmazione in grado di gestire tutta la gestione dell'ambito e il controllo delle risorse necessarie (poiché fa parte del mio lavoro non posso condividere i file), ma qualcosa di simile è qui:
::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>Se hai già caricato le due funzioni globali, puoi tenerle fuori dallo script: servono a modificare le funzioni all'interno dello spazio dei nomi per essere a conoscenza dello spazio dei nomi in cui si trovano, oltre a modificare il <<IMPOSTA funzione=""> metodi dell'albero di visualizzazione per chiamare le funzioni rilevanti all'interno dello spazio dei nomi di ambito.Inoltre, questo imposterà automaticamente il<CODE class=" language-jsl"> <<IN chiusura=""> metodo della finestra per eseguire il<CODE class=" language-jsl"> sé: alla chiusura() funzione (se esiste).
Si noti che questo, per impostazione predefinita, eliminerà l'ambito se stesso namespace quando la finestra si chiude.Questo non è sempre il comportamento desiderato, ma per questa semplice demo sarà sufficiente.
Le ultime due righe dello script aprono ciascuna una finestra, ma non c'è dialogo incrociato tra di loro (puoi caricare alcune tabelle premendo il pulsante, e quando la finestra è chiusa anche le tabelle vengono automaticamente chiuse)
Ciao @miguello ,
Come hai sottolineato, hai bisogno che la variabile ns sia univoca per ogni script, non solo per lo spazio dei nomi. @jthi risolve questo problema usando Names Default to here(1). Per definirlo esplicitamente, e forse capire meglio come funziona, prova a eseguire queste due righe in alcune finestre diverse,
here:ns = New Namespace();
here:ns:a = random normal();
e poi usa
show namespaces()
per vedere il valore di a in ogni namespace. Chiamata
here:ns:a
da ogni singola finestra restituirà il valore di quella finestra. In un'altra finestra, esegui questo:
Names default to here(1);
ns = New Namespace();
ns:a = random normal();
e nota come si comporta nello stesso modo dell'esempio precedente. Provalo senza il namespace here e tutti i riferimenti ad a restituiranno lo stesso valore, indicando che provengono dallo stesso namespace.
Quindi, semplicemente mettendo
Names default to here(1);
in cima al tuo script potrebbe risolvere il problema. Potresti anche riuscire a evitare di creare nuovi namespace denominati inserendo tutte quelle variabili che avevi lì proprio nel namespace here.
Quando parli di istanze, intendi che stai eseguendo più inclusioni? O come una funzione?
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}));
Per me funziona.
*Modifica* in realtà è ancora più semplice. Non hai nemmeno bisogno di eval expr perché non è una cosa che riguarda l'esecuzione.
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}));