{"id":3241,"date":"2015-11-25T19:39:50","date_gmt":"2015-11-25T17:39:50","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=3241"},"modified":"2015-11-25T19:39:50","modified_gmt":"2015-11-25T17:39:50","slug":"inselraus-undo-unter-swing-durchfuehren","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2015\/11\/inselraus-undo-unter-swing-durchfuehren\/","title":{"rendered":"Inselraus: Undo unter Swing durchf\u00fchren"},"content":{"rendered":"<p>Gute Benutzerschnittstellen zeichnen sich dadurch aus, dass dem Benutzer Fehler unterlaufen d\u00fcrfen. Die \u00c4nderungen m\u00fcssen jedoch wieder zur\u00fcckgenommen werden k\u00f6nnen. Um dies in Java zu realisieren, gibt es Unterst\u00fctzung durch ein Paket javax.swing.undo. Mit ihm lassen sich Undo- und Redo-Operationen mit relativ wenig Aufwand realisieren. Unser Beispiel soll ein Textfeld zeigen, dessen \u00c4nderungen auf Knopfdruck r\u00fcckg\u00e4ngig gemacht werden. Zentrales Objekt ist dabei ein UndoManager. Dieser sammelt einzelne Aktionen, im Fall von Benutzereingaben jedes Zeichen. Die Anzahl der zu speichernden Aktionen ist beschr\u00e4nkt, l\u00e4sst sich aber anpassen. Wir wollen in einem Beispiel ein JTextField mit einem Standardtext erzeugen. Anschlie\u00dfend wird ein UndoManager mit dem Document-Objekt des Textfeldes verbunden. Das Document informiert den UndoManager \u00fcber \u00c4nderungen, der UndoManager speichert diese. Wenn eine Schaltfl\u00e4che aktiviert ist, wird dem UndoManager befohlen, die Aktion r\u00fcckg\u00e4ngig zu machen. Sichtbar wird dann wieder der Text, so wie er am Anfang in der Textbox stand:<\/p>\n<pre>package\u00a0com.tutego.insel.ui.undo;\r\n \r\n import\u00a0java.awt.BorderLayout;\r\n import\u00a0java.awt.event.*;\r\n import\u00a0javax.swing.*;\r\n import\u00a0javax.swing.event.UndoableEditEvent;\r\n import\u00a0javax.swing.undo.*;\r\n \r\n public\u00a0class\u00a0IComeUndone\u00a0{\r\n \u00a0\u00a0public\u00a0static\u00a0void\u00a0main(\u00a0String[]\u00a0args\u00a0)\u00a0{\r\n \u00a0\u00a0\u00a0\u00a0JFrame\u00a0f\u00a0=\u00a0new\u00a0JFrame();\r\n \u00a0\u00a0\u00a0\u00a0f.setDefaultCloseOperation(\u00a0JFrame.EXIT_ON_CLOSE\u00a0);\r\n \r\n \u00a0\u00a0\u00a0\u00a0final\u00a0JTextArea\u00a0textarea\u00a0=\u00a0new\u00a0JTextArea(\u00a020,\u00a040\u00a0);\r\n \u00a0\u00a0\u00a0\u00a0textarea.setText(\u00a0\"Hier\u00a0zur\u00fcck\"\u00a0);\r\n \u00a0\u00a0\u00a0\u00a0f.add(\u00a0new\u00a0JScrollPane(textarea)\u00a0);\r\n \r\n \u00a0\u00a0\u00a0\u00a0\/\/\u00a0\u00a0\u00a0\u00a0final\u00a0UndoManager\u00a0undomanager\u00a0=\u00a0new\u00a0MyUndoManager();\r\n \u00a0\u00a0\u00a0\u00a0final\u00a0UndoManager\u00a0undomanager\u00a0=\u00a0new\u00a0UndoManager();\r\n \u00a0\u00a0\u00a0\u00a0textarea.getDocument().addUndoableEditListener(\u00a0undomanager\u00a0);\r\n \u00a0\u00a0\u00a0\u00a0undomanager.setLimit(\u00a01000\u00a0);\r\n \r\n \u00a0\u00a0\u00a0\u00a0JButton\u00a0undoB\u00a0=\u00a0new\u00a0JButton(\u00a0\"Undo\"\u00a0);\r\n \u00a0\u00a0\u00a0\u00a0undoB.addActionListener(\u00a0new\u00a0ActionListener()\u00a0{\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0@Override\u00a0public\u00a0void\u00a0actionPerformed(\u00a0ActionEvent\u00a0e\u00a0)\u00a0{\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0undomanager.end();\r\n \r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(\u00a0undomanager.canUndo()\u00a0)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0undomanager.undo();\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0textarea.requestFocus();\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n \u00a0\u00a0\u00a0\u00a0}\u00a0);\r\n \r\n \u00a0\u00a0\u00a0\u00a0f.add(\u00a0undoB,\u00a0BorderLayout.PAGE_END\u00a0);\r\n \u00a0\u00a0\u00a0\u00a0f.pack();\r\n \u00a0\u00a0\u00a0\u00a0f.setVisible(\u00a0true\u00a0);\r\n \u00a0\u00a0}\r\n }<\/pre>\n<p>Um genauer zu sehen, was das UndoManager-Objekt r\u00fcckg\u00e4ngig macht, schreiben wir eine Unterklasse von UndoManager und \u00fcberschreiben die Methode undoableEditHappened(UndoableEdit-Event) (diese Methode implementiert UndoManager von der Schnittstelle UndoableEditListener). Geben wir in unserer Realisierung auf dem Bildschirm aus, was bei jeder Aktion in den UndoManager kommt:<\/p>\n<pre>class\u00a0MyUndoManager\u00a0extends\u00a0UndoManager\u00a0{\r\n \u00a0\u00a0@Override\r\n \u00a0\u00a0public\u00a0void\u00a0undoableEditHappened(\u00a0UndoableEditEvent\u00a0e\u00a0)\u00a0{\r\n \u00a0\u00a0\u00a0\u00a0UndoableEdit\u00a0ue\u00a0=\u00a0e.getEdit();\r\n \u00a0\u00a0\u00a0\u00a0System.out.println(\u00a0ue\u00a0);\r\n \u00a0\u00a0\u00a0\u00a0addEdit(\u00a0ue\u00a0);\r\n \u00a0\u00a0}\r\n }<\/pre>\n<p>Die Methode undoableEditHappened(UndoableEditEvent) bekommt ein Ereignisobjekt, in dem der Verweis auf eine zur\u00fccknehmbare Operation abgelegt ist. An diese kommen wir mit get-Edit(). Die R\u00fcckgabe ist ein UndoableEdit-Objekt, also genau eine Operation, die zu einem Undo und Redo f\u00e4hig ist. Der UndoManager speichert diese mit dem Aufruf von addEdit() in einer Datenstruktur ab. Wenn wir das UndoableEdit-Objekt auf dem Bildschirm ausgeben, sehen wir unsere durchgef\u00fchrte Operation, zum Beispiel bei einem Einf\u00fcgen:<\/p>\n<pre>[javax.swing.text.GapContent$InsertUndo@497934\u00a0hasBeenDone:\u00a0true\u00a0alive:\u00a0true]<\/pre>\n<p>Beim L\u00f6schen erkennen wir ein:<\/p>\n<pre>[javax.swing.text.GapContent$RemoveUndo@ca470\u00a0hasBeenDone:\u00a0true\u00a0alive:\u00a0true]<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Gute Benutzerschnittstellen zeichnen sich dadurch aus, dass dem Benutzer Fehler unterlaufen d\u00fcrfen. Die \u00c4nderungen m\u00fcssen jedoch wieder zur\u00fcckgenommen werden k\u00f6nnen. Um dies in Java zu realisieren, gibt es Unterst\u00fctzung durch ein Paket javax.swing.undo. Mit ihm lassen sich Undo- und Redo-Operationen mit relativ wenig Aufwand realisieren. Unser Beispiel soll ein Textfeld zeigen, dessen \u00c4nderungen auf Knopfdruck [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[1],"tags":[],"class_list":["post-3241","post","type-post","status-publish","format-standard","hentry","category-allgemein"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3241","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=3241"}],"version-history":[{"count":1,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3241\/revisions"}],"predecessor-version":[{"id":3242,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3241\/revisions\/3242"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=3241"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=3241"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=3241"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}