0

I'm writing a funcion that allow to move the selected part of a canvas in another point, this is a part of a project which consist in the developing of a program like paint.

This is the class thath should allow the moving funciont

public class TraslationTool {

private Canvas canvas;
private GraphicsContext gc;
private List<Canvas> list;
private double x1;
private double y1;
private double x2;
private double y2;

public TraslationTool(List<Canvas> list, double x1, double y1, double x2, double y2) {
    canvas = list.get(list.size() - 1);
    gc = canvas.getGraphicsContext2D();
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    this.list = list;
}

public void traslate(double posX, double posY) {
    if (posX > 0 && posY > 0 && checkSelection()) {

        int width = (int) x2 - (int) x1;
        int height = (int) y2 - (int) y1;
        Rectangle2D bound = new Rectangle2D(x1, y1, width, height);

        SnapshotParameters params = new SnapshotParameters();
        params.setViewport(bound);
        params.setFill(Color.TRANSPARENT);
        WritableImage write = new WritableImage(width, height);
        Image image = canvas.snapshot(params, write);

        gc.clearRect(x1, y1, width, height);
        gc.drawImage(image, posX, posY);
    }
}

private boolean checkSelection() {
    if(this.x1 == 0 || this.y1 == 0 || this.x2 == 0 || this.y2 == 0) {
        return false;
    }
    if (this.x1 > this.x2) {
        double tempX = this.x1;
        this.x1 = this.x2;
        this.x2 = tempX;
    }
    if (this.y1 > this.y2) {
        double tempY = this.y1;
        this.y1 = this.y2;
        this.y2 = tempY;
    }
    return true;
} }

This is the portion of controller which handle the canvas

drawingCanvas.setOnMousePressed(event -> {
        Canvas c = new Canvas(drawingCanvasWidth, drawingCanvasHeight);
        c.setOnMousePressed(drawingCanvas.getOnMousePressed());
        c.setOnMouseDragged(drawingCanvas.getOnMouseDragged());
        c.setOnMouseReleased(drawingCanvas.getOnMouseReleased());
        c.setOnMouseMoved(drawingCanvas.getOnMouseMoved());
        c.setOnMouseExited(drawingCanvas.getOnMouseExited());

        try {
            if (list.contains(list.get(++counter))) {
                for (int i = list.size() - 1; i >= counter; i--) {
                    list.remove(i);
                }
            }
        } catch (IndexOutOfBoundsException e) {

        }

        list.add(c);
        anchorPane.getChildren().add(c);
        gc = c.getGraphicsContext2D();
        gc.setLineWidth(size);

        x1 = event.getX();
        y1 = event.getY();

        if (event.getButton() == MouseButton.PRIMARY) {
            gc.setStroke(primaryColor);
            shapeDrawer.setCanvas(c, primaryColor);
        } else if (event.getButton() == MouseButton.SECONDARY) {
            gc.setStroke(secondaryColor);
            shapeDrawer.setCanvas(c, secondaryColor);
        }

        Color wantedColor = (Color) gc.getStroke();

        if (toolIsPressed) {
            if (toolPressed == hboxRubber) {
                gc.setStroke(Color.WHITE);
            } else if (toolPressed == hboxPencil) {
                gc.setLineWidth(0.25 * size);
            } else if (toolPressed == hboxDropper) {
                DropperTool dropperTool = new DropperTool(list, (int) event.getX(), (int) event.getY());
                Color tempColor = dropperTool.getColor();
                shapeDrawer.setCanvas(c, tempColor);
                if (event.getButton() == MouseButton.PRIMARY) {
                    shapeDrawer.setCanvas(c, primaryColor);
                    primaryColor = tempColor;
                    defColor1.setStyle("-fx-border-color: gray; -fx-background-color: " + hexToRgb(tempColor));
                } else if (event.getButton() == MouseButton.SECONDARY) {
                    shapeDrawer.setCanvas(c, secondaryColor);
                    secondaryColor = tempColor;
                    defColor2.setStyle("-fx-border-color: gray; -fx-background-color: " + hexToRgb(tempColor));
                }
                gc.setStroke(tempColor);
            } else if (toolPressed == hboxPolygon) {
                if (!polygonIsFirst) {
                    x1 = x2;
                    y1 = y2;
                } else {
                    polyX = x1;
                    polyY = y1;
                }
            } else if (toolPressed == hboxBucket) {
                BucketTool bucketTool = new BucketTool(list, (int) event.getX(), (int) event.getY(), wantedColor);
                bucketTool.paint();
            }
        }

        gc.beginPath();
        gc.moveTo(x1, y1);
        changesMade = true;
    });

    //Logic for show/unshow the Drawing Grid 
    hboxGrid.setOnMousePressed(event -> {
        if (gridIsPressed) {
            gridIsPressed = false;
            grid.setGridLinesVisible(gridIsPressed);
        } else {
            gridIsPressed = true;
            grid.setGridLinesVisible(gridIsPressed);
        }
    });


    /*
     Handle shapes.
     */
    drawingCanvas.setOnMouseReleased(event -> {
        x2 = event.getX();
        y2 = event.getY();

        if (x1 == x2 && y1 == y2 && toolIsPressed) {
            return;
        }

        changesMade = true;

        double width = x2 - x1;
        double height = y2 - y1;

        if (toolPressed == hboxLine) {
            shapeDrawer.drawLine(x2, y2);
        } else if (toolPressed == hboxRectangle) {
            shapeDrawer.drawRectangle(x1, y1, width, height);
        } else if (toolPressed == hboxOval) {
            shapeDrawer.drawOval(x1, y1, width, height);
        } else if (toolPressed == hboxCircle) {
            shapeDrawer.drawCircle(x1, y1, width, height);
        } else if (toolPressed == hboxSquare) {
            shapeDrawer.drawSquare(x1, y1, width, height);
        } else if (toolPressed == hboxTriangle) {
            shapeDrawer.drawTriangle(x1, y1, x2, y2, width);
        } else if (toolPressed == hboxRoundRectangle) {
            shapeDrawer.drawRoundRectangle(x1, y1, width, height);
        } else if (toolPressed == hboxPolygon) {
            if (polygonIsFirst) {
                polygonIsFirst = false;
            }
            if (x2 >= polyX - 10 && x2 <= polyX + 10 && y2 <= polyY + 10 && y2 >= polyY - 10) {
                gc.lineTo(polyX, polyY);
                gc.stroke();
                polygonIsFirst = true;
                return;
            }
            gc.lineTo(x2, y2);
            gc.stroke();
        } else if (toolPressed == hboxMove) {
            TraslationTool move = new TraslationTool(list, x1, y1, x2, y2);
            move.traslate(50, 50);
        }
    });
}

I'm using a layered system of canvases to allow the function of Undo/Redo. To allow the move funciont I take a snapshot of the desired portion of Canvas and then write this snapshot in the desired coordinates. The problem is that when I execute the code, the call at the class TraslationTool creates only a new layer of Canvas and don't execute the funcion of moving. My idea is that something goes wrong in the creation of the new layer, but I can't understan what it is. Sorry for the long post, and thak you in advance.

tenser
  • 1
  • 3
  • Possible duplicate of [this](https://stackoverflow.com/q/55222189/230513). As suggested [here](https://stackoverflow.com/a/45685372/230513), a snapshot of the rendered view no longer has the information needed for this; instead of a `List`, let your application's model manage a notional `UndoManager` that associates an operation with a `List` representing the affected nodes. – trashgod Mar 20 '19 at 17:51
  • Thank you @trashgod, I've checked the solution that involves the use of the UndoManager that keeps track of the operation, and I've tried to write an example code that makes use of it, and is much easier to implement. – tenser Mar 21 '19 at 23:40
  • Note that you can [answer your own question](http://meta.stackoverflow.com/q/17463/163188). – trashgod Mar 21 '19 at 23:45

1 Answers1

0

I've resolved my problem with a change of approach. The issue of moving portion of canvas was due to the implementation of the Undo/Redo function (the layered system of canvases creates problem with the rendering of the WritableImage). I've changed the implementation of Undo/Redo function using This Solution, in this way the Class TraslationTool works.

This is the code I'm using for Translate a part of a Canvas:

public class MovingTool implements DrawOperation {

private final Canvas canvas;
private double x1;
private double y1;
private double x2;
private double y2;
private final double posX;
private final double posY;

public MovingTool(Canvas canvas, double x1, double y1, double x2, double y2, double posX, double posY) {
    this.canvas = canvas;
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    this.posX = posX;
    this.posY = posY;
}

@Override
public void draw(GraphicsContext gc) {
    if ((posX >= 0) && (posY >= 0)) {

        checkSelection();

        int width = (int) x2 - (int) x1;
        int height = (int) y2 - (int) y1;
        Rectangle2D bound = new Rectangle2D(x1, y1, width, height);

        SnapshotParameters params = new SnapshotParameters();
        params.setViewport(bound);
        params.setFill(Color.TRANSPARENT);
        WritableImage write = new WritableImage(width, height);
        Image image = canvas.snapshot(params, write);

        gc.clearRect(x1, y1, width, height);
        gc.drawImage(image, x1, y1);
    }
}

private void checkSelection() {
    if (this.x1 > this.x2) {
        double tempX = this.x1;
        this.x1 = this.x2;
        this.x2 = tempX;
    }
    if (this.y1 > this.y2) {
        double tempY = this.y1;
        this.y1 = this.y2;
        this.y2 = tempY;
    }
}}
tenser
  • 1
  • 3