2012-09-09 19 views
8

Estoy escribiendo un editor gráfico para un "modelo" (es decir, una colección de cajas y líneas con algún tipo de semántica, como UML, los detalles de los cuales no importan aquí) . Así que quiero tener una estructura de datos que represente el modelo, y un diagrama donde una edición del diagrama cause un cambio correspondiente en el modelo. Entonces, si, por ejemplo, un elemento modelo tiene texto en un atributo y edito el texto en el diagrama, quiero que el elemento modelo se actualice.Cremallera estructura de datos para editor de modelo gráfico

El modelo probablemente se representará como un árbol, pero quiero que el editor de diagramas sepa tan poco sobre la representación del modelo como sea posible. (Estoy usando el marco diagrams, por lo que asociar información arbitraria con un elemento gráfico es fácil). Probablemente habrá una clase "modelo" para codificar la interfaz, si puedo descubrir qué debería ser.

Si estuviera haciendo esto en un lenguaje imperativo, sería sencillo: me gustaría tener una referencia del elemento gráfico en el diagrama de nuevo al elemento del modelo. En teoría, podría hacer esto construyendo el modelo a partir de una colección masiva de IORefs, pero eso sería escribir un programa Java en Haskell.

Claramente, cada elemento gráfico va a tener algún tipo de cookie asociada que permitirá la actualización del modelo. Una respuesta simple sería darle a cada elemento del modelo un identificador único y almacenar el modelo en una tabla de búsqueda de Data.Map. Pero eso requiere una importante contabilidad para garantizar que no haya dos elementos del modelo que tengan el mismo identificador. También me parece una solución "stringly typed"; tiene que manejar los casos en los que se borra un objeto, pero hay una referencia a él en otro lugar, y es difícil decir algo sobre la estructura interna del modelo en sus tipos.

Por otro lado Oleg's writings sobre cremalleras con múltiples orificios y cursores con claro intercambio transaccional suena como una mejor opción, si tan solo pudiera entenderlo. Obtengo la idea básica de cremalleras de lista y árbol y la diferenciación de una estructura de datos. ¿Sería posible que cada elemento de un diagrama mantenga un cursor en una cremallera del modelo? ¿De modo que si se realiza un cambio, se puede asignar a todos los demás cursores? ¿Incluidas las operaciones de árbol (como mover un subárbol de un lugar a otro)?

Me sería particularmente útil en este punto si hubiera algún tipo de tutorial sobre continuaciones delimitadas, y una explicación de cómo hacen que funcionen las cremalleras con múltiples cursores de Oleg, ¿eso es un poco menos pronunciado que las publicaciones de Oleg?

+1

¿Tal vez el blog de Chung-chieh Shan? : http://conway.rutgers.edu/~ccshan/wiki/blog/posts/WalkZip1/. Tenga en cuenta que Blobs (wxHaskell) es una biblioteca para escribir "editores de red": probablemente se haya descompuesto, pero puede que sea menos trabajo actualizarlo que volver a comenzar con Diagramas. –

+0

Gracias. Empecé a trabajar en eso. Te dejaré saber si te lleva a una respuesta. –

Respuesta

2

Creo que actualmente está trabajando desde un diseño en el que cada nodo en el árbol de modelos está representado por un widget gráfico separado, y cada uno de estos widgets puede actualizar el modelo de forma independiente. Si es así, no creo que una cremallera con orificios múltiples sea muy práctica. El problema es que la complejidad de la cremallera crece rápidamente con el número de agujeros que desea admitir. A medida que vayas más allá de 2 términos, el tamaño de la cremallera será bastante grande. Desde el punto de vista de la diferenciación, una cremallera de 2 agujeros es una cremallera sobre cremalleras de 1 agujero, por lo que la complejidad aumenta con la operación de la regla de la cadena.

En su lugar, puede tomar prestada una idea de MVC. Cada nodo todavía está asociado con un widget, pero no se comunican directamente. Más bien pasan por un controlador intermediario, que mantiene una sola cremallera. Cuando los widgets se actualizan, notifican al controlador, que serializa todas las actualizaciones y modifica la cremallera en consecuencia.

Los widgets seguirán necesitando algún tipo de identificador para hacer referencia a los nodos del modelo. Descubrí que a menudo es más fácil usar la ruta del nodo, p. [0] para la raíz, [1,0] para el segundo hijo de la raíz, etc. Esto tiene algunas ventajas. Es fácil determinar el nodo al que hace referencia una ruta, y también es fácil para una cremallera calcular la ruta más corta desde la ubicación actual a un nodo dado.Para una estructura de árbol, también son únicos hasta su eliminación y reinserción. Incluso eso no suele ser un problema porque, cuando se notifica al controlador que los nodos deben eliminarse, puede eliminar los widgets correspondientes y descartar cualquier actualización asociada. Siempre que la duración del widget esté ligada a la duración de cada nodo, la ruta será lo suficientemente única para identificar cualquier modificación.

Para operaciones de árbol, probablemente destruiría y luego volvería a crear widgets gráficos. Por ejemplo, tengo un código que does this sort of thing. En este modelo no hay widgets separados para cada nodo, sino que renderizo todo usando diagramas y luego consulto el diagrama en función de la posición del clic para obtener la ruta en el modelo de datos. Está lejos de ser completo, y no lo he visto por un tiempo, por lo que podría no compilarse, pero el código puede darte algunas ideas.

+0

Lo que pasa con la versión de las cremalleras de Oleg es que no implica diferenciar la estructura de datos, sino más bien utilizar las continuas para capturar una caminata parcial. –

+0

@PaulJohnson: incluso con las continuaciones que capturan una caminata parcial, todavía hay la misma cantidad de estados para representar, que es de donde viene la complejidad. Se maneja de forma diferente porque Oleg usa un orden explícito entre continuaciones, lo que significa que debe administrar la complejidad asegurándose de que las continuaciones se actualicen en el orden correcto. No estoy seguro de cuál es más simple en la práctica, pero espero que cualquier enfoque no sea trivial. –

Cuestiones relacionadas