UndoableEditSupport Verstaendnisfrage?

Status
Nicht offen für weitere Antworten.
S

sirbender

Gast
Hallo,

Kann mir jemand an einem kleinen Beispiel erlaeutern wie man sinnvoll UndoableEditSupport.beginUpdate() und endUpdate() nutzt?

Danke,
sb
 

André Uhres

Top Contributor
Wie man sinnvoll UndoableEditSupport.beginUpdate() und endUpdate() nutzt
API-Erklärung durch ein Beispiel.
Die Grundlage für das Beispiel stammt von John Zukowski: UndoDrawing.htm

Damit wir das Beispiel auch sichtbar am Bildschirm verfolgen können,
machen wir uns erstmal eine Klasse "UndoableDrawingPanel".
Dort wird mit jedem Mausklick ein Punkt zu einem Polygon hinzugefügt und repaint() aufgerufen.
Das Polygon wird dann in paintComponent auf dem Panel dargestellt.
Gleichzeitig wird mit postEdit(..) ein UndoableEdit zum UndoableEditSupport geschickt.
"beginUpdate" machen wir bei updateLevel 0 und "endUpdate" nach jedem zweiten Mausklick.
Der Effekt ist, daß bei "undo" jeweils zwei Mausklicks rückgängig gemacht und bei "redo"
zwei wiederhergestellt werden:
Code:
/*
 * UndoableDrawingPanel.java
 */
package demo;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.undo.*;

class UndoableDrawingPanel extends JPanel {

    private UndoableEditSupport undoableEditSupport = new UndoableEditSupport(this);
    private Polygon polygon = new Polygon();

    public UndoableDrawingPanel() {
        MouseListener mouseListener = new MouseAdapter() {

            @Override
            public void mouseReleased(final MouseEvent mouseEvent) {
                if (undoableEditSupport.getUpdateLevel() == 0) {
                    undoableEditSupport.beginUpdate();
                }
                undoableEditSupport.postEdit(new UndoableDrawEdit(UndoableDrawingPanel.this));
                polygon.addPoint(mouseEvent.getX(), mouseEvent.getY());
                repaint();
                if (polygon.npoints % 2 == 0) {
                    undoableEditSupport.endUpdate();
                }
            }
        };
        addMouseListener(mouseListener);
    }

    public void addUndoableEditListener(final UndoableEditListener undoableEditListener) {
        undoableEditSupport.addUndoableEditListener(undoableEditListener);
    }

    public void removeUndoableEditListener(final UndoableEditListener undoableEditListener) {
        undoableEditSupport.removeUndoableEditListener(undoableEditListener);
    }

    public void setPolygon(final Polygon newValue) {
        polygon = newValue;
        repaint();
    }

    public Polygon getPolygon() {
        Polygon returnValue;
        if (polygon.npoints == 0) {
            returnValue = new Polygon();
        } else {
            returnValue = new Polygon(polygon.xpoints, polygon.ypoints, polygon.npoints);
        }
        return returnValue;
    }

    @Override
    protected void paintComponent(final Graphics g) {
        super.paintComponent(g);
        g.drawPolygon(polygon);
    }
}

Der UndoableEdit wird in unserer Klasse "UndoableDrawEdit" implementiert:
Code:
package demo;
/*
 * UndoableDrawEdit.java
 */

import java.awt.*;
import javax.swing.undo.*;

class UndoableDrawEdit extends AbstractUndoableEdit {

    UndoableDrawingPanel panel;
    Polygon polygon, savedPolygon;

    public UndoableDrawEdit(UndoableDrawingPanel panel) {
        this.panel = panel;
        polygon = panel.getPolygon();
    }

    @Override
    public String getPresentationName() {
        return "Polygon of size " + polygon.npoints;
    }

    @Override
    public void redo() throws CannotRedoException {
        super.redo();
        panel.setPolygon(savedPolygon);
        savedPolygon = null;
    }

    @Override
    public void undo() throws CannotUndoException {
        super.undo();
        savedPolygon = panel.getPolygon();
        panel.setPolygon(polygon);
    }
}

Unsere Klasse "UndoManagerHelper" dient lediglich dem Unterbringen der Actions für die Buttons:
Code:
package demo;
/*
 * UndoManagerHelper.java
 */

import java.awt.event.*;
import javax.swing.*;
import javax.swing.undo.*;

class UndoManagerHelper {

    public static Action getUndoAction(UndoManager manager, String label) {
        return new UndoAction(manager, label);
    }

    public static Action getUndoAction(UndoManager manager) {
        return new UndoAction(manager, (String) UIManager.get("AbstractUndoableEdit.undoText"));
    }

    public static Action getRedoAction(UndoManager manager, String label) {
        return new RedoAction(manager, label);
    }

    public static Action getRedoAction(UndoManager manager) {
        return new RedoAction(manager, (String) UIManager.get("AbstractUndoableEdit.redoText"));
    }

    private abstract static class UndoRedoAction extends AbstractAction {

        UndoManager undoManager = new UndoManager();
        String errorMessage = "Cannot undo";
        String errorTitle = "Undo Problem";

        protected UndoRedoAction(UndoManager manager, String name) {
            super(name);
            undoManager = manager;
        }

        public void setErrorMessage(String newValue) {
            errorMessage = newValue;
        }

        public void setErrorTitle(String newValue) {
            errorTitle = newValue;
        }

        protected void showMessage(Object source) {
            System.err.println(errorMessage);
        }
    }

    public static class UndoAction extends UndoRedoAction {

        public UndoAction(UndoManager manager, String name) {
            super(manager, name);
            setErrorMessage("Cannot undo");
            setErrorTitle("Undo Problem");
        }

        public void actionPerformed(ActionEvent actionEvent) {
            try {
                undoManager.undo();
            } catch (CannotUndoException cannotUndoException) {
                showMessage(actionEvent.getSource());
            }
        }
    }

    public static class RedoAction extends UndoRedoAction {

        public RedoAction(UndoManager manager, String name) {
            super(manager, name);
            setErrorMessage("Cannot redo");
            setErrorTitle("Redo Problem");
        }

        public void actionPerformed(ActionEvent actionEvent) {
            try {
                undoManager.redo();
            } catch (CannotRedoException cannotRedoException) {
                showMessage(actionEvent.getSource());
            }
        }
    }
}

Fehlt nur noch unsere GUI Klasse "UndoDrawing", die alles in einem JFrame darstellt:
Code:
package demo;
/*
 * UndoDrawing.java
 */

import java.awt.*;
import javax.swing.*;
import javax.swing.undo.*;

public class UndoDrawing extends JFrame {

    private UndoableDrawingPanel drawingPanel;
    private UndoManager manager;
    private JToolBar toolbar;
    private JButton undoButton;
    private JButton redoButton;

    public UndoDrawing() {
        super("Drawing Sample");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 600);
        setLocationRelativeTo(null);
        drawingPanel = new UndoableDrawingPanel();
        manager = new UndoManager();
        drawingPanel.addUndoableEditListener(manager);
        toolbar = new JToolBar();
        undoButton = new JButton(UndoManagerHelper.getUndoAction(manager));
        toolbar.add(undoButton);
        redoButton = new JButton(UndoManagerHelper.getRedoAction(manager));
        toolbar.add(redoButton);
        add(toolbar, BorderLayout.NORTH);
        add(drawingPanel, BorderLayout.CENTER);
    }

    public static void main(final String[] args) {
        Runnable gui = new Runnable() {

            public void run() {
                new UndoDrawing().setVisible(true);
            }
        };
        //GUI must start on EventDispatchThread:
        SwingUtilities.invokeLater(gui);
    }
}
 
G

Guest

Gast
Danke.

Hmm...ich muss mir das mal Zeile fuer Zeile anschauen. Mit begin/end-update kann ich also ohne weiteren Aufwand sowas machen wie UndoableEvents zusammenfassen, bzw. das mehrere auf einmal rueckgaengig gemacht werden, richtig?

Ich muss nur noch herauskriegen wie dieser Vorgang genau funktioniert.
 

André Uhres

Top Contributor
Anonymous hat gesagt.:
Mit begin/end-update kann ich also ohne weiteren Aufwand sowas machen wie UndoableEvents zusammenfassen, bzw. das mehrere auf einmal rueckgaengig gemacht werden, richtig?
Richtig.
Falls du etwas nicht vestehst, stell ruhig Fragen.
Auch durch Experimentieren kann man so manches besser verstehen.
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Oben