Pregunta

Una parte de mi proyecto es escribir un editor de texto que se utiliza para escribir algunas reglas, la compilación de mi solicitud y ejecutarlo. Escribiendo compilador era extremo y lanzamiento de la versión beta. En la versión final hay que añadir deshacer y rehacer al editor de texto. Yo uso un archivo y guardarlo periódicamente para el editor de texto. Cómo diseñar deshacer y rehacer a mi editor de texto? Lo que se cambia en la estructura de la persistencia del archivo?

¿Fue útil?

Solución

Se puede modelar sus acciones como comandos , que se mantiene en dos pilas. Uno para deshacer, otro para rehacer. Puede componer sus comandos para crear más comandos de alto nivel, al igual que cuando se quiere deshacer el acciones de una macro, por ejemplo; o si desea agrupar las pulsaciones de teclas individuales de una sola palabra, o frase, en una sola acción.

Cada acción en el editor (o rehacer una acción) genera un nuevo comando de deshacer que se dedica a la pila de deshacer (y también borra la pila rehacer). Cada acción de deshacer genera el comando rehacer correspondiente que va a la pila rehacer.

También puede, como se ha mencionado en los comentarios por derekerdmann , se combinan ambos comandos deshacer y rehacer en un solo tipo de comando , que sabe cómo deshacer y rehacer su acción.

Otros consejos

Existen básicamente dos buenas maneras de ir sobre él:

  • el patrón de diseño "Comando"

  • Con solamente OO sobre los objetos inmutables, donde todo es sólo objetos inmutables hechas de objetos inmutables se hicieron de objetos inmutables (esto es menos común pero maravillosamente elegante cuando se hace correctamente)

La ventaja de utilizar OO sobre los objetos inmutables entrega el mando ingenuo o deshacer la ingenua / rehacer es que usted no necesita pensar mucho al respecto: no hay necesidad de "deshacer" el efecto de una acción y no hay necesidad de " Replay" todos los comandos. Todo lo que necesita es un puntero a una enorme lista de objetos inmutables.

Dado que los objetos son inmutables todos los "estados" puede ser increíblemente ligero porque se puede cache / reutilización mayoría de los objetos en cualquier estado.

"OO sobre los objetos inmutables" es una joya pura. Probablemente no va a convertirse en la corriente principal antes de otros 10 años que decían; )

P.S: OO haciendo más objetos inmutables también simplifica extraordinariamente la programación concurrente.

Si usted no quiere nada de fantasía, sólo puede agregar un UndoManager . Su Document se disparará una UndoableEdit cada vez que añada o quite el texto. Para deshacer y rehacer cada cambio, sólo tiene que llamar a los métodos de UndoManager.

La desventaja de esto es UndoManager añade una nueva edición cada vez que el usuario escribe algo en, por lo que escribir "manzana" le dejará con 5 ediciones, uno puede deshacer a la vez. Por mi editor de texto, escribí un contenedor para ediciones que almacena el momento en que se hizo, además de cambiar el texto y offset, así como un UndoableEditListener que concatena las nuevas ediciones a las anteriores si hay sólo un corto período de tiempo entre ellas ( 0,5 segundos funciona bien para mí).

Esto funciona bien para Editting general, pero causa problemas cuando una masiva reemplazar a que se hace. Si tenías un documento con 5000 casos de "manzana" y que quería reemplazar esto con "naranja", que iba a terminar con todas las ediciones 5000 almacenar "Apple", "naranja" y un desplazamiento. Para reducir la cantidad de memoria utilizada, he tratado esto como un caso separado a ediciones ordinarias y estoy almacenando en lugar de "manzana", "naranja" y una serie de compensaciones 5000. No he tenido tiempo de aplicación de esto todavía, pero sé que va a causar algunos dolores de cabeza cuando varias cadenas coinciden con la condición de búsqueda (por ejemplo, el caso de búsqueda. Insensible, búsqueda de expresiones regulares).

Vaya, qué conicidence - Tengo literalmente en la última hora en práctica de deshacer / rehacer en mi editor de texto WYSIWYG:

La idea básica es bien guardar todo el contenido del editor de texto en una matriz, o la diferencia entre la última edición.

Actualizar esta matriz en puntos significativos, es decir, cada pocos caracteres (comprobar la longitud del contenido de cada pulsación de tecla, si sus más de digamos 20 caracteres diferentes a continuación, hacer un punto de guardado). También en los cambios en el estilo (si texto enriquecido), la adición de imágenes (si lo permite), pegar texto, etc. También es necesario un puntero (solo una variable int) al punto en el que elemento de la matriz es el estado actual de la editor)

Hacer la matriz tiene una longitud establecida. Cada vez que añada un punto de guardado, agregarlo al inicio de la matriz, y mover todos los demás puntos de datos por uno. (El último elemento de la matriz será olvidado una vez que tenga tantos puntos de guardado)

Cuando el usuario presiona el botón de deshacer, comprobar para ver si el contenido actual del editor son los mismos que la última parada (si no es así, entonces el usuario ha realizado cambios desde el último punto de guardado, así que guardar la corriente contenido del editor (lo que puede ser rehacer-ed), que el editor igual al último punto de guardado, y hacer que la variable puntero = 1 (segundo elemento de matriz). Si ellos son iguales, entonces no se han hecho cambios desde el último punto de guardado, por lo que necesita para deshacer hasta el punto de que antes. para hacer esto, incremente el valor del puntero + 1, y hacer que el contenido del editor = el valor del puntero.

Para rehacer simplemente disminuir el valor del puntero en 1 y cargar el contenido de la matriz (asegúrese de comprobar si se ha alcanzado el final de la matriz).

Si el usuario hace cambios después de deshacer, a continuación, pasar la célula valor de matriz punta hacia arriba a la celda 0, y se mueven el resto por la misma cantidad (que no quiero volver a hacer a otras cosas, una vez que han hecho diferentes ediciones).

Una otra importante punto de intersección - Asegúrese de que sólo añade un punto de guardado, si el contenido del editor de texto han cambiado de hecho (de lo contrario get duplicado puntos de guardado y parecerá que deshacer no está haciendo nada para el usuario

No puedo ayudarle con aspectos específicos de Java, pero estoy feliz de responder a cualquier otra pregunta que tenga,

Nico

Puede hacerlo de dos maneras:

  • mantener una lista de estados editor y un puntero en la lista; deshacer mueve la parte de atrás del puntero y restaura el estado ahí, de rehacer se mueve hacia adelante en lugar, haciendo algo tira a la basura todo más allá de la aguja y se inserta el estado como nuevo elemento superior;
  • no mantener estados, pero las acciones, lo que requiere que para cada acción tiene una acción contraria a deshacer los efectos de que la acción

En mi editor (diagrama), hay cuatro niveles de cambios de estado:

  • fragmentos de acción: estos son parte de una acción más grande y no se puede deshacer separado o redoable (Por ejemplo, mover el ratón)
  • acciones: uno o más fragmentos de acción que forman un cambio significativo, que se puede deshacer o rehacer, pero que no se reflejan en el documento editado tan cambiado en el disco (Por ejemplo, elementos de selección)
  • cambios del documento: una o más acciones que cambian el documento editado, ya que se guarda en el disco (Por ejemplo, cambiar, añadir o borrar elementos)
  • documento salva: el estado actual del documento se guarda de forma explícita en el disco - en este punto mi editor tira a la basura el historial de deshacer, por lo que no se puede deshacer un pasado Guardar

Este es un trabajo para el patrón de comandos .

Aquí hay un fragmento que muestra la forma en SWT soporta operaciones de deshacer / rehacer. Tomarlo como ejemplo práctico (o utilizarlo directamente, si el editor está basado en SWT):

SWT Deshacer Rehacer

Design Patterns: Elements of reutilizable Object-Oriented Software . Por lo que yo recuerdo, no es un ejemplo bastante bueno.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top