2012-01-16 11 views
5

Para agregar un divisor entre filas en una cuadrícula, una forma en que sé cómo hacerlo es usando la opción Dividers. Pero esto se usa al final, y uno debe saber el número de fila al que un divisor debe estar por debajo. Entonces, para la grilla grande, me encuentro usando prueba y error hasta que encuentre el número de fila correcto. Luego, cuando cambie la grilla más tarde, tengo que volver a hacer la prueba y el error para colocar el divisor en el lugar correcto en caso de que se moviera después de mis cambios.cualquier truco para agregar un divisor dentro de una cuadrícula entre filas en el punto en que se necesita

En este ejemplo, hay una rejilla con 3 filas y quiero agregar el divisor debajo decir la segunda fila, por lo que se puede hacer esto:

Grid[{ 
    {1}, 
    {2}, 
    {3} 
    }, Frame -> True, Dividers -> {All, 3 -> True}] 

Otra forma, es poner False y True, en el orden correcto donde quiero un divisor, como este

Grid[{ 
    {1}, 
    {2}, 
    {3} 
    }, Frame -> True, Dividers -> {All, {True, False, True, True}}] 

sería bueno si pudiera hacer algo como esto (al igual que uno puede hacer para manipular) (por supuesto esto abajo no funciona aquí)

Grid[{ 
    {1}, 
    {2}, 
    Delimiter, 
    {3} 
    }, Frame -> True] 

o

Grid[{ 
    {1}, 
    {Item[2,Dividers->True]}, 
    {3} 
    }, Frame -> True] 

o tal cosa.

Facilitará el mantenimiento del código.

me observó el uso de punto y como para esto, pero no es capaz de entenderlo.

Cualquiera sabe de un truco para hacerlo?

edición:

por cierto, este truco si es posible, no sólo se aplica a los divisores. Pero sería útil poder hacer muchas de las otras opciones de cuadrícula, que ahora se realizan en el nivel de cuadrícula, también en el nivel de elemento. Por ejemplo, si deseo agregar un espacio extra después de una fila, será más fácil decirlo al ritmo que quería que se haga. Además, si quería cambiar el tamaño del artículo, es más fácil hacerlo en el lugar, lo mismo para los espacios, etc. De modo que cuando mueva/copie el código de una fila completa o artículo, este sea autocontenido y lo copie con todo su contenido. opciones juntas.

Creo que ahora esto podría requerir una nueva opción de añadir a Mathematica cuadrícula para que funcione bien y sea consistente con el sobre todo el diseño de la rejilla.

Esto es todo hasta que un constructor de interfaz gráfica de usuario está hecho para Mathematica.

me parece que me paso más del 60% de mi tiempo cuando escribo una demo conseguir la interfaz gráfica de usuario para adaptarse y buscar la derecha. Con un constructor de GUI, puedo pasar este tiempo trabajando en el algoritmo. Cuando uso Matlab GUIDE para hacer GUI, me toma menos del 5% de mi tiempo hacer una GUI similar.

Me gustaría que la IRG haría un constructor de interfaz gráfica de usuario para Mathematica, creo que esta será la aplicación asesina para Mathematica si me preguntas. Pero ningún cuerpo me :)

edición (2)

comentario sobre el Sr. Asistente buena solución por debajo preguntó.
Principalmente quería esta característica para las grillas que uso para controles de diseño para Manipulate. Aquí está un ejemplo sencillo:

Manipulate[x, 

Grid[{ 
    {Control[{{x, 0, "x"}, 0, 10, 1}]}, 
    {Control[{{y, 0, "y"}, 0, 10, 1}]} 
    }, Frame -> None, Dividers -> {None, {False, True, False}} 
    ] 
] 

enter image description here

(y tengo que usar Grid para configurar los controles). No puedo usar llamadas a funciones aquí. No puedo escribir, usando la solución de Asistente a continuación, lo siguiente:

Manipulate[x, 

myGrid[{ 
    {Control[{{x, 0, "x"}, 0, 10, 1}]}, 
    spec["Divider"], 
    {Control[{{y, 0, "y"}, 0, 10, 1}]} 
    }, Frame -> None 
    ], 

Initialization :> 
    { 
    specfunc["Divider", lst_] := Dividers -> {None, # -> True & /@ lst}; 

    myGrid[dat_, opts : OptionsPattern[]] := 
    Module[{x = 1}, 
    Grid[#, opts, Sequence @@ #2] & @@ 
     Reap[If[MatchQ[#, _spec], Sow[x, #[[1]]]; ## &[], x++; #] & /@ 
     dat, _, specfunc] 
    ] 

    } 
] 

Esto da un error, ya que Mathematica intenta leer primero el cuerpo de manipular para analizarlo, antes de leer y procesar la sección de inicialización.

Pero fuera de manipular, que será por supuesto trabajar:

myGrid[{ 
    {Control[{{x, 0, "x"}, 0, 10, 1}]}, 
    spec["Divider"], 
    {Control[{{y, 0, "y"}, 0, 10, 1}]} 
    }, Frame -> None 
] 

specfunc["Divider", lst_] := Dividers -> {None, # -> True & /@ lst}; 
myGrid[dat_, opts : OptionsPattern[]] := 
Module[{x = 1}, 
    Grid[#, opts, Sequence @@ #2] & @@ 
    Reap[If[MatchQ[#, _spec], Sow[x, #[[1]]]; ## &[], x++; #] & /@ 
    dat, _, specfunc] 
    ] 

enter image description here

tengo que pasar más tiempo en esto, para ver si puedo conseguir que funcione dentro de manipular.

Por cierto, conseguir cosas como esta para trabajar en el interior Manipular es muy difícil. El único truco que sé es el uso de macros con el patrón With[{},.... Grid....] que aprendí de Leonid.

Por ejemplo de este tipo de dificultades, vea esta pregunta mía

How to define constants for use with With[] in one place and then apply them later?

edición (3) mi se me hace algo malo, pero estoy consiguiendo algunos errores en el interior Manipular:

primer ejemplo:

Manipulate[x, 

[email protected][{ 
    {Control[{{x, 0, "x"}, 0, 10, 1}]} 
    } 
    ], 

Initialization :> 
    { 
    grid[tab_, opts___] := 
    Module[{divlocal, divglobal, div, pos}, 
     divglobal = (Dividers /. opts) /. Dividers -> {False, False}; 
     If[Depth[divglobal] == 1, divglobal = {divglobal, divglobal}]; 
     If[Length[divglobal] == 1, AppendTo[divglobal, False]]; 
     pos = Position[tab, Dividers -> _, 1]; 
     divlocal = 
     MapIndexed[# - #2[[1]] + 1 -> Dividers /. tab[[#]] &, 
     Flatten[pos]]; 
     divglobal[[2]] = {divglobal[[2]], divlocal}; 
     Grid[Delete[tab, pos], Dividers -> divglobal, opts]]; 


    } 
] 

gives erro R:

ReplaceAll::rmix: Elements of {False,{}} are a mixture of lists and nonlists. >> 

misma si se sustituye la anterior con

[email protected][{ 
    Dividers -> {Thick, Blue}, 
    {Control[{{x, 0, "x"}, 0, 10, 1}]} 
    } 
    ], 

Probado [email protected] en lugar de [email protected] sin suerte. puede ser pequeña solución es todo lo que se necesita? o no lo estoy usando bien?

+0

hola Mike. Sí, sé dónde quiero agregar el divisor, pero en una cuadrícula larga y complicada, es más fácil agregar un fragmento de código en el lugar donde quiero agregar el divisor, en lugar de poner el código en la parte inferior, y tengo que contar y hacer errores. Luego rehace, cuando cambia la cuadrícula. Ese es mi punto. Gracias – Nasser

+0

Todo el tema de un generador de interfaz gráfica de usuario vs codificación manual de la interfaz de usuario es algo bien discutido en muchos lugares en la red. Me gustaría hablar más sobre eso, pero no creo que este sea el lugar correcto para ello. Puede ser que cuando tengamos nuestro propio foro de Mathematica podamos hablar más sobre eso. Pero, según mi experiencia, el uso de un generador de GUI ahorra mucho tiempo al programador en la codificación manual. El análisis costo/tiempo favorece el uso del generador de GUI. El tiempo ahorrado se puede usar para otras cosas muy importantes. Por cierto, estoy hablando aquí de interfaces de usuario complejas grandes, no de uno o dos controles deslizantes y de una interfaz de usuario tipo botón y una gráfica. – Nasser

+1

Para hacer que 'Manipulate' en edit (2) funcione, podría reemplazar el control con 'Dynamic @ myGrid [...]'. – Heike

Respuesta

4

Estas soluciones deben permitirá combinar las especificaciones de los divisores entre las filas especificadas en la tabla con las especificadas utilizando la Dividers opción.

grid[tab_, opts___] := 
Module[{divlocal, divglobal, div, pos}, 

    (* extract option value of Dividers from opts to divglobal *) 
    (* default value is {False, False} *) 
    divglobal = (Dividers /. {opts}) /. Dividers -> {False, False}; 

    (* transform divglobal so that it is in the form {colspecs, rowspecs} *) 
    If[Head[divglobal] =!= List, divglobal = {divglobal, divglobal}]; 
    If[Length[divglobal] == 1, AppendTo[divglobal, False]]; 

    (* Extract positions of dividers between rows from tab *) 
    pos = Position[tab, Dividers -> _, 1]; 

    (* Build list of rules for divider specifications between rows *) 
    divlocal = MapIndexed[# - #2[[1]] + 1 -> Dividers /. tab[[#]] &, Flatten[pos]]; 

    (* Final settings for dividers are {colspecs, {rowspecs, divlocal}} *) 
    divglobal[[2]] = {divglobal[[2]], divlocal}; 
    Grid[Delete[tab, pos], Dividers -> divglobal, opts]] 

Para especificar un divisor entre las filas que necesita para insertar Dividers->spec en la posición deseada en la que spec es o bien False, True, o una directiva de gráficos (color, grosor, etc.). Por ejemplo

tab = {{1, 2, 3}, Dividers -> {Thick, Blue}, {4, 5, 6}, {7, 8, 9}, 
    Dividers -> False, {10, 11, 12}}; 

grid[tab, Dividers -> All] 

Mathematica graphics

Editar

He añadido algunos comentarios a mi código a petición del Sr. Asistente.

+0

+1, sin embargo, apreciaría alguna explicación para cada línea de código. –

+0

Además, creo que necesitas '/. {Opts}' –

+0

Heike, gracias. Pero estoy obteniendo algunos dificultad para hacer que esto funcione dentro de Manipulate. Intenté Dynamic @ y Evaluate @ pero recibí algunos errores. Mostraré ejemplos que intenté en mi edición (3). – Nasser

2

Propongo que utilice un nuevo cabezal que pueda contener instrucciones (spec a continuación), y una nueva función que procese estas instrucciones (specfunc a continuación) como se requiera individualmente. El beneficio es que esto se generaliza fácilmente para diferentes instrucciones intercaladas, y cada una se puede procesar de forma arbitraria.

specfunc["Divider", lst_] := Dividers -> {All, # -> True & /@ lst} 

myGrid[dat_, opts:OptionsPattern[]] := 
Module[{x = 1}, 
    Grid[#, opts, Sequence @@ #2] & @@ 
    Reap[ 
    If[MatchQ[#, _spec], Sow[x, #[[1]]]; ## &[], x++; #] & /@ dat, 
    _, 
    specfunc 
    ] 
] 

Uso:

dat = 
{ 
    {1, 2, 3}, 
    {4, 5, 6}, 
    spec["Divider"], 
    {7, 8, 9}, 
    spec["Divider"], 
    {"a", "b", "c"} 
}; 

myGrid[dat, Frame -> True] 

Mathematica graphics


Si cada instrucción puede ser una sola cadena como "Divider" y no tiene conflictos usando esta manera, se podría eliminar spec y use MatchQ[#, _String] y Sow[x, #].


Dirigiéndose a su pregunta actualizada, como he señalado en un comentario más abajo creo que tiene más sentido utilizar los elementos más básicos en su Manipulate objeto final, y escribir herramientas para ayudarle a generar este objeto con mayor facilidad. Creo que intentar hacer este tipo de personalización dentro del bloque Manipulate está condenado al fracaso, y probablemente de manera extraña y opaca.

Sin embargo, para este caso particular, esto parece funcionar, aunque lo dudo es robusto:

Manipulate[x, 
Evaluate[ 
    {specfunc["Divider", lst_] := Dividers -> {All, # -> True & /@ lst}; 
    myGrid[dat_, opts : OptionsPattern[]] := 
    Module[{x = 1}, 
    Grid[#, opts, Sequence @@ #2] & @@ 
     Reap[If[MatchQ[#, _spec], Sow[x, #[[1]]]; ## &[], x++; #] & /@ 
     dat, _, specfunc]]}; 
    myGrid[{{Control[{{x, 0, "x"}, 0, 10, 1}]}, 
    spec["Divider"], {Control[{{y, 0, "y"}, 0, 10, 1}]}}, 
    Frame -> True] 
    ] 
] 
+0

Gracias, esto es realmente bueno, y podría usarlo. Pero el uso principal que tengo para esta característica es en la construcción de controles para Manipular. Y no pude usarlo tal como está en ese contexto. Necesito pasar más tiempo para ver si puedo adaptarlo para eso. Estoy agregando edición (2) ahora para explicar mejor lo que quiero decir. El problema es que en el área de control Manipular, el ambiente es un poco más restrictivo y algo que funciona afuera, no funciona fácilmente allí. – Nasser

+1

@Nasser Lo siento, no construyo demos, y no sé cómo hacer todo dentro de un 'Manipulate' de la forma en que lo intentas. Solo puedo sugerir meta-programación, es decir, escribir herramientas fáciles de usar que generen el enrevesado objeto 'Manipular' que seguramente se requiere. En su caso 'Grid' funciona, entonces lo usaría; en su lugar crea una herramienta para escribir el objeto 'Grid' más fácilmente. ¿Esto ayuda en absoluto? –

+0

MrWizard, Heike acaba de señalar una solución simple. Solo necesitaba agregar Dynamics a todo el asunto. Debería haberlo intentado y me olvidé de hacerlo. Gracias por una muy buena solución. – Nasser

Cuestiones relacionadas