2010-07-14 15 views
6

Estoy escribiendo una aplicación de pintura/gráficos Java para un teléfono móvil (por lo que la memoria es limitada). El estado de la aplicación es esencialmente tres 1000x500 bitmaps (es decir, capas de una pintura). La carga de tres mapas de bits lleva aproximadamente 2 o 3 segundos.Deshacer/rehacer rápidamente con el patrón memento/command?

Estoy tratando de escribir un motor de deshacer pero no puedo encontrar una buena manera de hacerlo. Los enfoques típicos son:

  • utilizar el patrón de comando: Al deshacer, volver a cargar el estado del archivo inicial y luego reproducir todos los comandos procesados ​​hasta el momento a excepción de la última. Hacer esto ingenuamente significa esperar 2 o 3 segundos para cargar el estado inicial que es demasiado lento. Tampoco hay suficiente memoria para almacenar el estado inicial en la memoria.

  • Utilice el patrón memento: cuando deshace, reemplaza la parte del estado actual que se cambió con el estado anterior. Esto significa que cada acción necesita guardar bitmaps del estado anterior en el disco porque simplemente no hay suficiente memoria en un dispositivo móvil para almacenar esto en la memoria. Como el ahorro de mapas de bits lleva tiempo, ¿cómo puedo enfrentarlo si el usuario decide, p. pintar muchas pinceladas en rápida sucesión? No puedo hacerlos esperar.

Todas mis soluciones implican complejos híbridos de los patrones anteriores.

¿Alguien puede sugerir una solución que me permita tener un proceso de deshacer/rehacer razonablemente rápido para mi aplicación?

+0

¿No hay más sugerencias? Hubiera pensado que mis preguntas eran fundamentales para implementar cualquiera de estos patrones en un proyecto real. – BobDuck

+0

Posible duplicado de [¿Cómo implemento un simple deshacer/rehacer para acciones en java?] (Https: // stackoverflow.com/questions/11530276/how-do-i-implement-a-simple-undo-redo-for-actions-in-java) –

Respuesta

7

Hay un tercer método común para deshacer deshacer. Eso es para almacenar las diferencias entre los dos estados dentro del objeto Deshacer. Puede hacer esto como diferencias reales (es decir, a qué píxeles han cambiado y a qué han cambiado), pero probablemente sea una pérdida de memoria tan importante como almacenar el mapa de bits en cada etapa.

Como alternativa, puede utilizar el método de comando, pero en lugar de volver a ejecutar los comandos al deshacer, almacena el inverso del comando, es decir, si el usuario aumentó el valor rojo en diez, el comando deshacer es disminuirlo por diez. Para deshacer, simplemente ejecuta el comando inverso. Es difícil encontrar un comando inverso para algunos comandos, como "convertir a blanco y negro", pero al mezclar un mapa de bits subyacente con una cantidad de filtros que se activan o desactivan mediante un comando, probablemente puedas hacerlo.

Como otra sugerencia más, use el enfoque de comando que mencionó pero mantenga un mapa de bits para el paso anterior. Cuando el usuario lo hace, inmediatamente muestra el mapa de bits almacenado en caché del paso anterior (n-1) y luego comienza a calcular el mapa de bits para n-2 para que esté listo para cuando presione deshacer nuevamente.

+0

También es perfectamente aceptable tener comandos que no se pueden deshacer, como "convertir a blanco y negro ", siempre y cuando le solicite al usuario que ese sea el caso antes de que lo haga. – StrixVaria

+0

@StrixVaria: He pensado en esto, pero preferiría evitar esto, ya que no es algo que los usuarios esperan en una aplicación de pintura. Las buenas aplicaciones de iphone tienen un deshacer decente, creo. – BobDuck

+0

Gracias. Almacenar las diferencias parece ser una optimización en el patrón de recuerdo. Mis acciones principales son cosas como 1) dibujar 50 manchas de pintura azul en estos lugares 2) cambiar la saturación al 20%; como dices, almacenar las diferencias o escribir acciones inversas no ayudará mucho aquí. Me gusta tu última sugerencia Una variante de esta idea es que cuando el usuario está dibujando, la máquina se abre camino a través de la lista de comandos de almacenamiento en caché de deshacer mapas de bits. Sin embargo, tengo que pensar en las preocupaciones sobre el uso de la CPU y la batería. – BobDuck

2

Acerca de Utilice el patrón de comando punto: Comenzando desde el estado inicial y nuevamente ejecutando comandos no son necesarios en absoluto. Cada clase de comando debe representar una pequeña acción del usuario y debe tener un mecanismo para deshacer lo que hace en su método execute(), si se va a admitir la operación de deshacer. Mantenemos una pila de *** Objetos de comando. Cuando el usuario deshace algo, un objeto Command se saca de la pila y se llama a su método undo().

No veo ninguna motivación para usar el patrón de recuerdo en su caso ya que las acciones de deshacer estarán en orden FIFO. El usuario no tiene permitido deshacer las acciones como le plazca, supongo.

Cuestiones relacionadas