Tout,
J'ai un problème suivant. J'ai un script qui ouvre\ferme plusieurs tables et fenêtres, et je crée plusieurs espaces de noms pour gérer cela. Je supprime également ces espaces de noms dans <
J'ai constaté que lorsque j'ai deux instances du script en cours d'exécution, la fermeture de la fenêtre principale dans l'une d'elles supprime les espaces de noms et casse l'autre script.
Comment puis-je séparer les espaces de noms pour chaque instance ou, alternativement, comment n'autoriser qu'une seule instance du script \ add-in en cours d'exécution ?
je comprends que dans
ns = New Namespace();
ns est une référence, et il y a un nom unique, comme "#43" qui est attribué à chaque fois qu'un espace de noms est créé. Je peux obtenir ce nom par < ns dans une instance de script en cours d'exécution fait référence à "#43", et ns dans une autre instance en cours d'exécution fait référence, disons, à "#44" ?
Dépend de l'application. Vous pourriez par exemple :
- Vérifier si un nom de fenêtre spécifique existe
- Utilisez des espaces de noms nommés et vérifiez si ceux-ci existent déjà
puis effectuez une action en fonction de leur existence ou non.
Guide de script > Méthodes de programmation > Portée avancée et espaces de noms (help, jmp.com) se lit assez bien
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...");
);Le contrôle de la portée et la gestion des ressources dans JMP peuvent s'avérer délicats : les objets JMP Table de données() , et Espace de noms() ne sont jamais explicitement libérés de la mémoire et jamais par déréférencement.
Pour mes besoins, j'ai créé une bibliothèque de méta-programmation qui peut gérer toute la gestion de la portée et le contrôle des ressources nécessaires (comme cela fait partie de mon travail, je ne peux pas partager les fichiers), mais quelque chose d'un peu comme ça est ici :
::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 vous avez déjà chargé les deux fonctions globales, vous pouvez les garder hors du script - elles servent à modifier les fonctions dans l'espace de noms pour savoir dans quel espace de noms elles se trouvent, ainsi qu'à modifier le <<DÉFINIR la="" fonction=""> méthodes de l'arborescence d'affichage pour appeler les fonctions pertinentes dans l'espace de noms de portée.En outre, cela définira automatiquement le<CODE class=" language-jsl"> <<À la fermeture() méthode de la fenêtre pour exécuter le soi:à la fermeture() fonction (si elle existe).
Notez que cela supprimera, par défaut, la portée soi espace de noms lorsque la fenêtre se ferme.Ce n'est pas toujours le comportement souhaité, mais pour cette simple démo cela suffira.
Les deux dernières lignes du script ouvrent chacune une fenêtre, mais il n'y a pas de diaphonie entre elles (vous pouvez charger certaines tables en appuyant sur le bouton, et lorsque la fenêtre est fermée, les tables sont également automatiquement fermées)
Salut @miguello ,
Comme vous l'avez souligné, vous avez besoin que la variable ns soit unique pour chaque script, pas seulement pour l'espace de noms. @jthi résout ce problème en utilisant Names Default to here(1). Pour définir cela explicitement, et peut-être mieux comprendre comment cela fonctionne, essayez d'exécuter ces deux lignes dans quelques fenêtres différentes,
here:ns = New Namespace();
here:ns:a = random normal();
et ensuite utiliser
show namespaces()
pour voir la valeur de a dans chaque espace de noms. Appel
here:ns:a
à partir de chaque fenêtre individuelle, la valeur de cette fenêtre sera renvoyée. Dans une autre fenêtre, exécutez ceci :
Names default to here(1);
ns = New Namespace();
ns:a = random normal();
et notez comment il se comporte de la même manière que l'exemple précédent. Essayez cela sans l'espace de noms here et toutes les références à a renverront la même valeur, indiquant qu'ils proviennent du même espace de noms.
Donc, juste en mettant
Names default to here(1);
en haut de votre script pourrait résoudre votre problème. Vous pourriez également éviter de créer entièrement de nouveaux espaces de noms nommés en plaçant toutes ces variables que vous aviez là directement dans l'espace de noms ici.
Quand vous parlez d'instances, voulez-vous dire que vous effectuez plusieurs inclusions ? Ou une fonction ?
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}));
Cela fonctionne pour moi.
*Modifier* En fait, c'est encore plus simple. Vous n'avez même pas besoin de l'expression d'évaluation, car elle n'est pas exécutée.
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}));