Hola a todos,
Estoy tratando de crear una ventana de diálogo con varios cuadros de lista, cada uno de los cuales contiene todos los valores de una columna correspondiente en una tabla de datos. Al seleccionar uno o más elementos en cualquiera de las listas, quiero que los elementos de las listas restantes se filtren de acuerdo con esa selección. He implementado lo que acabo de describir a continuación, pero aquí está la cosa: si relleno la ventana de diálogo en un bucle en lugar de codificar los índices de subconjunto de la lista con números enteros como se muestra a continuación, la función se llama con el valor actual de i en el momento de ejecución en lugar del valor que tomó cuando se creó el cuadro de lista en el bucle. Leí la guía de secuencias de comandos y probé varias opciones, incluidas Eval( Eval Expr( Expr())) y Eval Substitute( Expr(), Expr())) pero no puedo hacer que funcione. Ahora estoy listo para construir toda la expresión como una cadena larga en un bucle y evaluarla (Parse()), pero eso parece una tontería. ¿Puede alguien ayudarme con la sintaxis adecuada aquí?
Gracias,
johan
Names Default To Here( 1 );
If( !Namespace Exists( "fq" ),
New Namespace(
"fq"
)
);
dt = New Table( "Sample data",
Add Rows( 9 ),
New Column( "id",
Character,
"Nominal",
Set Values( {"a", "a", "a", "b", "b", "b", "c", "c", "c"} )
),
New Column( "value",
Character,
"Nominal",
Set Values( {"A", "B", "C", "D", "E", "F", "G", "H", "I"} )
),
New Column( "val2",
Character,
"Nominal",
Set Values( {"one", "two", "three", "one", "two", "three","one", "two", "three"} )
)
);
filterSelected = Function( {dt, values, index},
/*
Sorts displayed values in all list boxes based on selection
*/
columns = fq:filterColumns;
filters = fq:filters;
selectedColum = Remove From( columns, index )[1];
selctedFilter = Remove From( filters, index )[1];
rows = dt << Get rows where( Contains( values, as Column( dt, selectedColum ) ) );
// If nothing is selcted, all values should be chosen
If(Length(values)==0,
rows = dt << get rows where(!Ismissing(As Column(dt, selectedColum)))
);
// Set list items according to selection
Local( {j = 1},
For( j = 1, j <= N Items( filters ), j++,
filters[j] << Set items( Column( dt, columns[j] )[rows] )
)
);
);
getSelection = Function( {},
Local( {j =1},
For( j=1, j <= N Items(fq:filters), j++,
print(fq:filterColumns[j], fq:filters[j] << get items());
);
);
);
nestedFilters = Function( {filtercolumns},
fq:filtercolumns = filtercolumns;
dialog = New Window( "Fetch rows matching:",
Show Menu( 0 ),
show toolbars( 0 ),
Border Box( Top( 20 ), Bottom( 20 ), Left( 10 ), Right( 10 ),
V List Box(
Align( right ),
filter_boxes = V List Box(),
H List Box(
ok_button = Button Box( "OK" ),
cancel_button = Button Box( "Cancel", dialog << close window )
)
)
),
ok_button << Set function(
getSelection();
dialog << close window;
)
);
fq:filters = {};
fq:all_rows = {};
//for(i=1, i<=N Items(filtercolumns), i++,
filter_boxes << append( Text Box( fq:filtercolumns[1], <<SET font="" style=""></SET>Gracias de nuevo. Parece que me quedaré con eval(parse()) entonces, aunque parece un poco como un truco. Pero gracias de todos modos por tus conocimientos!
Si el valor i==4 está presente, debe haber una i que no se envolvió en expr().
Compensaciones de Parse vs EvalExpr:
- parse crea cadenas que no tienen la sintaxis resaltada en el editor, pero la próxima persona que mantenga el código probablemente lo entenderá. En su ejemplo, podría poner eval-parse dentro del ciclo si pudiera haber cientos de concatenaciones.
- evalexpr es probablemente más rápido que analizar, pero no hace una diferencia real para un pequeño ejemplo. Si estuviera construyendo una cadena de un millón de caracteres por concatenación, podría ser importante. Evalexpr necesita un comentario que le diga al siguiente mantenedor lo que está haciendo.
Hay otros enfoques para manipular expresiones que son más poderosos y más difíciles de explicar y mantener; Creo que cualquiera de estos es razonable para este ejemplo. (arg, narg, cabeza, insertar, sustituir, ... Tengo que volver a aprender esto cada vez.)
Lo que puedo hacer es esto, pero eso parece... Tonto supongo...
expression = "";
for( i = 1, i <= N Items( fq:filtercolumns ), i++,
expression = expression ||
"filter_boxes << append( Text Box( fq:filtercolumns[" || char(i) || "], <<SET font="" style=""></SET>¡Gracias por darle una oportunidad a esto! Desafortunadamente, tengo el mismo problema al que me había enfrentado en el pasado: cuando hago una selección en la lista, se llama a la función filterSelected con el valor actual si i (es decir, 4), lo que genera un error de rango de subíndice.

Prueba esto
for( i = 1, i <= N Items( filtercolumns ), i++,
eval(
evalexpr(
filter_boxes << append( Text Box( fq:filtercolumns[Expr( i )], <<SET font="" style=""></SET>Usé el caso "1", cambié los 1 a expr (i), puse eso dentro de eval/evalexpr, dentro del bucle i.
editar: ¡y una pregunta bien presentada!