Todos,
Tengo un siguiente problema. Tengo un script que abre/cierra varias tablas y ventanas, y creo varios espacios de nombres para manejar esto. También elimino esos espacios de nombres en <
Descubrí que cuando tengo dos instancias de la secuencia de comandos en ejecución, cerrar la ventana principal en una de ellas elimina los espacios de nombres y rompe la otra secuencia de comandos.
¿Cómo hago que los espacios de nombres se separen para cada instancia o, alternativamente, cómo permito que solo se ejecute una instancia del script\add-in?
entiendo que en
ns = New Namespace();
ns es una referencia y hay un nombre único, como "#43", que se asigna cada vez que se crea un espacio de nombres. Puedo obtener ese nombre con < ns en una instancia de secuencia de comandos en ejecución se refiere a "# 43", y ns en otra instancia en ejecución se refiere a, digamos, "#44"?
Depende de la aplicación. Podrías, por ejemplo:
- Compruebe si existe un nombre de ventana específico
- Use espacios de nombres con nombre y verifique si ya existen
y luego realizar alguna acción en función de si existen o no.
Guía de secuencias de comandos > Métodos de programación > Alcance avanzado y espacios de nombres (ayuda, jmp.com) es bastante buena lectura
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...");
);Hacer el control de alcance y la gestión de recursos adecuados en JMP puede ser complicado: los objetos JMP Tabla de datos() , y espacio de nombres() solo se liberan explícitamente de la memoria y nunca por desreferencia.
Para mis propósitos, he creado una biblioteca de metaprogramación que puede manejar toda la gestión de alcance y el control de recursos necesarios (como es parte de mi trabajo, no puedo compartir los archivos), pero algo parecido está aquí:
::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>Si ya cargó las dos funciones globales, puede mantenerlas fuera del script; sirven para modificar las funciones dentro del espacio de nombres para saber en qué espacio de nombres se encuentran, así como para modificar el <<ESTABLECER función=""> métodos del árbol de visualización para llamar a las funciones relevantes dentro del espacio de nombres de ámbito.Además, esto establecerá automáticamente el<CODE class=" language-jsl"> <<AL cerrar=""> método de la ventana para ejecutar el<CODE class=" language-jsl"> self: al cerrar() función (si existe).
Tenga en cuenta que esto, de forma predeterminada, eliminará el alcance uno mismo espacio de nombres cuando se cierra la ventana.Este no es siempre el comportamiento deseado, pero para esta demostración simple será suficiente.
Cada una de las dos últimas líneas del script abre una ventana, pero no hay comunicación cruzada entre ellas (puede cargar algunas tablas presionando el botón, y cuando la ventana está cerrada, las tablas también se cierran automáticamente)
Hola @miguello ,
Como señalaste, necesitas que la variable ns sea única para cada script, no solo para el espacio de nombres. @jthi resuelve esto usando Names Default to here(1). Para definir esto explícitamente, y quizás entender mejor cómo funciona, intenta ejecutar estas dos líneas en algunas ventanas diferentes,
here:ns = New Namespace();
here:ns:a = random normal();
y luego usa
show namespaces()
para ver el valor de a en cada espacio de nombres. Llamada
here:ns:a
Desde cada ventana individual se devolverá el valor de esa ventana. En otra ventana, ejecute lo siguiente:
Names default to here(1);
ns = New Namespace();
ns:a = random normal();
y observe cómo se comporta de la misma manera que el ejemplo anterior. Intente hacerlo sin el espacio de nombres here y todas las referencias a a devolverán el mismo valor, lo que indica que son del mismo espacio de nombres.
Entonces, simplemente poniendo
Names default to here(1);
en la parte superior de su script podría solucionar su problema. También podría evitar por completo la creación de nuevos espacios de nombres con nombre al colocar todas las variables que tenía allí directamente en el espacio de nombres aquí.
Cuando dices instancias, ¿te refieres a que estás haciendo múltiples inclusiones? ¿O como una función?
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}));
Esto funciona para mí.
*Editar* De hecho, es aún más fácil. Ni siquiera necesitas la expresión de evaluación porque no es algo en tiempo de ejecución.
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}));