Domanda

Una parte del mio progetto è quello di scrivere un editor di testo che viene utilizzato per la tipizzazione delle regole, compilare la mia applicazione ed eseguirlo. Scrivendo compilatore era alla fine e il rilascio versione beta. Nella versione finale bisogna aggiungere undo e redo per l'editor di testo. Io uso un file e salvarlo periodicamente per l'editor di testo. Come progettare Undo e Redo al mio editor di testo? Cosa è cambiato nella struttura del persistente di file?

È stato utile?

Soluzione

È possibile modellare le vostre azioni come comandi , che si tiene in due pile. Uno per undo, un altro per rifare. Puoi composizione i comandi per la creazione di più comandi di alto livello, come quando si vuole annullare la azioni di una macro, per esempio; oppure se si desidera raggruppare le singole battute di una sola parola, o una frase, in una sola azione.

Ogni azione nel vostro editor (o un'azione redo) genera un nuovo comando undo che va in stack di annullamento (e cancella anche lo stack Redo). Ogni azione di annullamento genera il comando redo corrispondente che entra nello stack di ripetizione.

Si può anche, come accennato nei commenti da derekerdmann , combinare entrambi i comandi Annulla e Ripeti in un tipo di comando , che sa di annullamento e ripristino la sua azione.

Altri suggerimenti

Ci sono fondamentalmente due buoni modi per andare su di esso:

  • "Command" modello di progettazione

  • con solo OO su oggetti immutabili, dove tutto è solo oggetti immutabili fatte di oggetti immutabili stessi fatti di oggetti immutabili (questo è meno comune, ma meravigliosamente elegante quando fatto correttamente)

Il vantaggio di usare OO sugli oggetti immutabili oltre il comando ingenui o l'annullamento ingenuo / redo è che non c'è bisogno di pensare molto su di esso: non c'è bisogno di "annullare" l'effetto di un'azione e non c'è bisogno di " Replay" tutti i comandi. Tutto ciò che serve è un puntatore ad una lista enorme di oggetti immutabili.

Poiché gli oggetti sono immutabili tutti gli "stati" può essere incredibilmente leggero perché si può cache / riuso maggior parte degli oggetti in qualsiasi stato.

"OO su oggetti immutabili" è un gioiello puro. Probabilmente non succederà prima di diventare mainstream altri 10 anni che dicono; )

P.S: facendo OO su oggetti immutabili anche semplifica incredibilmente programmazione concorrente.

Se non si desidera niente di eccezionale, si può semplicemente aggiungere un UndoManager . Il tuo Document sparerà un UndoableEdit ogni volta che si aggiungono o rimuovono testo. Per annullare e ripetere ogni modifica, è sufficiente chiamare quei metodi in UndoManager.

Il rovescio della medaglia è UndoManager aggiunge una nuova modifica ogni volta che l'utente digita qualcosa dentro, in modo digitazione "mela" vi lascerà con 5 modifiche, uno annullabile alla volta. Per il mio editor di testo, ho scritto un wrapper per i contributi che memorizza il tempo è stato fatto, oltre al cambiamento del testo e offset, così come un UndoableEditListener che concatena nuove modifiche alle precedenti se c'è solo un breve periodo di tempo tra di loro ( 0,5 secondi funziona bene per me).

Questo funziona bene per editting generale, ma causa problemi quando una massiccia sostituzione è fatto. Se tu avessi un documento con 5000 istanze di "mela" e si voleva sostituirlo con "orange", che ci si finisce con 5000 modifiche tutta la memorizzazione di "Apple", "Orange" e un offset. Per abbassare la quantità di memoria utilizzata, ho trattato questo come un caso a parte per le modifiche ordinarie e sono invece l'archiviazione "mela", "arancia" e una serie di 5000 offset. Non ho ottenuto intorno ad applicare questo ancora, ma so che sarà causa qualche mal di testa quando più stringhe corrispondono la condizione di ricerca (ad es. Caso ricerca maiuscole, di ricerca regex).

Wow, che conicidence - ho letteralmente nelle ultime ore implementato undo / redo nel mio editor di testo WYSIWYG:

L'idea di base è quella di uno salvare l'intero contenuto del editor di testo in un array, o la differenza tra l'ultima modifica.

Aggiornamento questo array in punti significativi, vale a dire ogni pochi caratteri (controllare la lunghezza del contenuto ogni pressione di tasto, se i suoi più di diciamo 20 caratteri diversi quindi non un punto di salvataggio). Anche a variazioni styling (se testo ricco), aggiungendo immagini (se permette), testo incollando, ecc È inoltre necessario un puntatore (solo una variabile int) per punto in cui elemento dell'array è lo stato attuale della Editor)

Crea l'array hanno una lunghezza prestabilita. Ogni volta che si aggiunge un punto di salvataggio, inserirlo per l'inizio della matrice, e spostare tutti gli altri punti di dati verso il basso per uno. (L'ultimo elemento della matrice verrà dimenticato una volta che hai così tanti punti di salvataggio)

Quando l'utente preme il pulsante Annulla, controllare per vedere se il contenuto corrente dell'editor sono le stesse come l'ultimo salvataggio (se non lo sono, allora l'utente ha apportato modifiche dall'ultimo salvataggio punto, in modo da salvare la corrente contenuto del l'editor (in modo che possa essere redo-ndr), rendere l'editor uguale all'ultimo punto di salvataggio, e rendere la variabile puntatore = 1 (2 ° elemento in array). Se sono essi stessi, quindi non sono state apportate modifiche dall'ultimo punto di salvataggio, quindi è necessario annullare il punto di prima. per fare questo, incrementare il valore del puntatore + 1, e rendere il contenuto del l'editor = il valore del puntatore.

Per ripetere semplicemente diminuire il valore del puntatore di 1 e caricare i contenuti della matrice (assicuratevi di controllare se avete raggiunto la fine della matrice).

Se l'utente effettua le modifiche dopo l'annullamento, quindi spostare la cella di matrice valore puntato fino alla cella 0, e spostare il resto dalla stessa quantità (non volete rifare ad altre cose, una volta che hanno fatto diverse modifiche).

Un altro punto di incontro importante - assicurarsi di aggiungere solo un punto di salvataggio, se il contenuto del editor di testo sono effettivamente cambiato (in caso contrario si ottiene duplicato punti di salvataggio e vi sembrerà di annullamento non sta facendo nulla per l'utente

non posso aiutare con le specifiche Java, ma io sono felice di rispondere a tutte le altre domande che avete,

Nico

Si può fare in due modi:

  • mantenere una lista di editor di Stati e un puntatore nella lista; undo sposta il puntatore indietro e ripristina lo stato lì, redo si muove in avanti, invece, a fare qualcosa butta via tutto ciò al di là del puntatore e gli inserti dello Stato come il nuovo elemento superiore;
  • non mantenere gli stati, ma le azioni, che richiede che per ogni azione si dispone di un contrasto per annullare gli effetti di tale azione

Nel mio (schema) editore, ci sono quattro livelli di cambiamenti di stato:

  • frammenti azione: sono parte di un'azione più ampia e non separatamente annullabile o ripristinabile (Per esempio spostando il mouse)
  • azioni: uno o più frammenti di azione che formano un cambiamento significativo che può essere annullata o rifatto, ma che non si riflettono nel documento pubblicato come modificata su disco (Ad esempio elementi di selezione)
  • le modifiche dei documenti: una o più azioni che modificano il documento modificato come sarebbe essere salvato su disco (Ad esempio cambiando, aggiungendo o eliminando elementi)
  • documento salva: lo stato attuale del documento è esplicitamente salvato su disco - a questo punto il mio editore butta via l'annullamento storia, quindi non è possibile annullare un passato Salva

Questo è un lavoro per il modello di comando .

Ecco un frammento che mostra come l'Altissimo supporta operazioni di undo / redo. Prendetelo come esempio pratico (o usarlo direttamente, se il vostro editor è basata su SWT):

SWT Annulla Ripristina

Leggi un libro Design Patterns: Elements of Reusable Object-Oriented Software . Per quanto mi ricordo, c'è un esempio piuttosto buona.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top