2016-12-21 73 views
2

如何使用JavaFX中的形狀邊框來改變其屬性之一 - 高度,寬度,半徑等。如何使用JavaFX中的邊框更改形狀屬性?

我試過用圓形在圓形上做它以便調整半徑的大小,但我想知道是否可以使用形狀的邊框來完成。

這是我的自定義Circle類:

public class NewCircle extends Circle { 


public NewCircle (double x, double y , double radius, Color colore){ 
    super(x,y,radius); 
    this.setFill(colore); 
    this.setOnMousePressed(circleOnMousePressedEventHandler); 
    this.setOnMouseDragged(circleOnMouseDraggedEventHandler); 
    } 

double orgSceneX, orgSceneY; 
double orgTranslateX, orgTranslateY; 

EventHandler<MouseEvent> circleOnMouseClickedEventHandler = new EventHandler<MouseEvent>(){ 
    @Override 
    public void handle(MouseEvent t){ 


    } 

}; 


EventHandler<MouseEvent> circleOnMousePressedEventHandler = new EventHandler<MouseEvent>(){ 
    @Override 
    public void handle(MouseEvent t){ 
     orgSceneX = t.getSceneX(); 
     orgSceneY = t.getSceneY(); 
     Node source = (Node) t.getSource(); 
     orgTranslateX = ((Circle) (t.getSource())).getTranslateX(); 
     orgTranslateY = ((Circle) (t.getSource())).getTranslateY();  
     ((Circle)t.getSource()).toFront();; 
    } 
}; 

EventHandler<MouseEvent> circleOnMouseDraggedEventHandler 
= new EventHandler<MouseEvent>() { 


    @Override 
    public void handle(MouseEvent t) { 
     Node source = (Node) t.getSource(); 
     Bounds sceneBounds = source.getScene().getRoot().getLayoutBounds(); 
     Bounds localBounds = source.getBoundsInLocal(); 

     double offsetX = t.getSceneX() - orgSceneX; 
     double offsetY = t.getSceneY() - orgSceneY; 

     double newTranslateX = orgTranslateX + offsetX; 
     double newTranslateY = orgTranslateY + offsetY; 

     // restirct x movement to scene bounds 
     if (offsetX >= 0) { 
      if (localBounds.getMaxX() + newTranslateX > sceneBounds.getMaxX()) { 
       newTranslateX = sceneBounds.getMaxX() - localBounds.getMaxX(); 
      } 
     } else { 
      if (localBounds.getMinX() + newTranslateX < 0) { 
       newTranslateX = -localBounds.getMinX(); 
      } 
     } 

     // restrict y movement to scene bounds 
     if (offsetY >= 0) { 
      if (localBounds.getMaxY() + newTranslateY > sceneBounds.getMaxY()) { 
       newTranslateY = sceneBounds.getMaxY() - localBounds.getMaxY(); 
      } 
     } else { 
      if (localBounds.getMinY() + newTranslateY < 0) { 
       newTranslateY = -localBounds.getMinY(); 
      } 
     } 
     source.setTranslateX(newTranslateX); 
     source.setTranslateY(newTranslateY); 
    } 
    }; 

} 

回答

2

我所做的是把一對夫婦的形狀上的窗格,然後讓用戶點擊形狀來選擇它們。用邊界框選擇形狀圍繞形狀的邊界(而不是邊界)。邊界框在其角落和側邊中心處具有錨點。用戶可以拖動邊界框來移動選定的形狀。用戶可以拖動錨點來調整選定的形狀。

這是一些代碼,因爲要完成它有一些工作要做。代碼可以稍微清理一下,但是現在可以相對確定。

resize

重新調整應用

import javafx.application.Application; 
import javafx.geometry.Bounds; 
import javafx.scene.*; 
import javafx.scene.layout.Pane; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Circle; 
import javafx.scene.shape.Ellipse; 
import javafx.scene.shape.Rectangle; 
import javafx.scene.shape.StrokeType; 
import javafx.stage.Stage; 

public class ResizingSample extends Application { 
    private Pane root; 
    private Node selectedNode; 

    public static void main(String[] args) throws Exception { 
     launch(args); 
    } 

    @Override 
    public void start(final Stage stage) throws Exception { 
     Ellipse ellipse = new Ellipse(100, 100, 50, 50); 
     ellipse.setFill(Color.AQUAMARINE); 

     Rectangle rectangle = new Rectangle(200, 250, 100, 100); 
     rectangle.setFill(Color.PALEGREEN); 

     root = new Pane(
       ellipse, 
       rectangle 
     ); 
     stage.setScene(
       new Scene(
         root, 
         400, 400, Color.ALICEBLUE 
       ) 
     ); 
     stage.show(); 

     root.setOnMouseClicked(event -> { 
      final Parent parentNode = ((Node) event.getTarget()).getParent(); 
      if (selectedNode != null && !(parentNode instanceof ResizingControl)) { 
       root.getChildren().removeIf(candidate -> candidate instanceof ResizingControl); 
       selectedNode = null; 
      } 
     }); 

     makeSelectable(ellipse, rectangle); 
    } 

    private void makeSelectable(Node... nodes) { 
     for (Node node: nodes) { 
      node.setOnMouseClicked(event -> { 
       if (selectedNode != node) { 
        root.getChildren().removeIf(candidate -> candidate instanceof ResizingControl); 
        selectedNode = node; 

        node.toFront(); 
        ResizingControl resizingControl = new ResizingControl(node); 
        root.getChildren().add(resizingControl); 
       } 

       event.consume(); 
      }); 
     } 
    } 
} 

class ResizingControl extends Group { 
    private Node targetNode = null; 
    private final Rectangle boundary = new Rectangle(); 

    private Anchor topLeft = new Anchor(Color.GOLD, true, true, (oldX, oldY, newX, newY) -> { 
     double newWidth = boundary.getWidth() - (newX - oldX); 
     if (newWidth > 0) { 
      boundary.setX(newX); 
      boundary.setWidth(newWidth); 
     } 
     double newHeight = boundary.getHeight() - (newY - oldY); 
     if (newHeight > 0) { 
      boundary.setY(newY); 
      boundary.setHeight(newHeight); 
     } 

     updateAnchorPositions(); 
     resizeTargetNode(); 
    }); 
    private Anchor topCenter = new Anchor(Color.GOLD, false, true, (oldX, oldY, newX, newY) -> { 
     double newHeight = boundary.getHeight() - (newY - oldY); 
     if (newHeight > 0) { 
      boundary.setY(newY); 
      boundary.setHeight(newHeight); 
     } 

     updateAnchorPositions(); 
     resizeTargetNode(); 
    }); 
    private Anchor topRight = new Anchor(Color.GOLD, true, true, (oldX, oldY, newX, newY) -> { 
     double newWidth = boundary.getWidth() + (newX - oldX); 
     if (newWidth > 0) { 
      boundary.setWidth(newWidth); 
     } 
     double newHeight = boundary.getHeight() - (newY - oldY); 
     if (newHeight > 0) { 
      boundary.setY(newY); 
      boundary.setHeight(newHeight); 
     } 

     updateAnchorPositions(); 
     resizeTargetNode(); 
    }); 
    private Anchor rightCenter = new Anchor(Color.GOLD, true, false, (oldX, oldY, newX, newY) -> { 
     double newWidth = boundary.getWidth() + (newX - oldX); 
     if (newWidth > 0) { 
      boundary.setWidth(newWidth); 
     } 

     updateAnchorPositions(); 
     resizeTargetNode(); 
    }); 
    private Anchor bottomRight = new Anchor(Color.GOLD, true, true, (oldX, oldY, newX, newY) -> { 
     double newWidth = boundary.getWidth() + (newX - oldX); 
     if (newWidth > 0) { 
      boundary.setWidth(newWidth); 
     } 
     double newHeight = boundary.getHeight() + (newY - oldY); 
     if (newHeight > 0) { 
      boundary.setHeight(newHeight); 
     } 

     updateAnchorPositions(); 
     resizeTargetNode(); 
    }); 
    private Anchor bottomCenter = new Anchor(Color.GOLD, false, true, (oldX, oldY, newX, newY) -> { 
     double newHeight = boundary.getHeight() + (newY - oldY); 
     if (newHeight > 0) { 
      boundary.setHeight(newHeight); 
     } 

     updateAnchorPositions(); 
     resizeTargetNode(); 
    }); 
    private Anchor bottomLeft = new Anchor(Color.GOLD, true, true, (oldX, oldY, newX, newY) -> { 
     double newWidth = boundary.getWidth() - (newX - oldX); 
     if (newWidth > 0) { 
      boundary.setX(newX); 
      boundary.setWidth(newWidth); 
     } 
     double newHeight = boundary.getHeight() + (newY - oldY); 
     if (newHeight > 0) { 
      boundary.setHeight(newHeight); 
     } 

     updateAnchorPositions(); 
     resizeTargetNode(); 
    }); 
    private Anchor leftCenter = new Anchor(Color.GOLD, true, false, (oldX, oldY, newX, newY) -> { 
     double newWidth = boundary.getWidth() - (newX - oldX); 
     if (newWidth > 0) { 
      boundary.setX(newX); 
      boundary.setWidth(newWidth); 
     } 

     updateAnchorPositions(); 
     resizeTargetNode(); 
    }); 

    ResizingControl(Node targetNode) { 
     this.targetNode = targetNode; 

     attachBoundingRectangle(targetNode); 
     attachAnchors(); 

     boundary.toBack(); 
    } 

    private void attachBoundingRectangle(Node node) { 
     Bounds bounds = node.getBoundsInParent(); 

     boundary.setStyle(
       "-fx-stroke: forestgreen; " + 
       "-fx-stroke-width: 2px; " + 
       "-fx-stroke-dash-array: 12 2 4 2; " + 
       "-fx-stroke-dash-offset: 6; " + 
       "-fx-stroke-line-cap: butt; " + 
       "-fx-fill: rgba(255, 228, 118, .5);" 
     ); 

     boundary.setX(bounds.getMinX()); 
     boundary.setY(bounds.getMinY()); 
     boundary.setWidth(bounds.getWidth()); 
     boundary.setHeight(bounds.getHeight()); 

     Util.makeDraggable(boundary, (oldX, oldY, newX, newY) -> { 
      updateAnchorPositions(); 

      relocateTargetNode(newX, newY); 
     }); 

     getChildren().add(boundary); 
    } 

    private void relocateTargetNode(double newX, double newY) { 
     if (targetNode instanceof Ellipse) { 
      Ellipse ellipse = (Ellipse) targetNode; 
      ellipse.setCenterX(newX + ellipse.getRadiusX()); 
      ellipse.setCenterY(newY + ellipse.getRadiusY()); 
     } else if (targetNode instanceof Rectangle) { 
      Rectangle rectangle = (Rectangle) targetNode; 
      rectangle.setX(newX); 
      rectangle.setY(newY); 
     } 
    } 

    private void resizeTargetNode() { 
     if (targetNode instanceof Ellipse) { 
      Ellipse ellipse = (Ellipse) targetNode; 
      ellipse.setRadiusX(boundary.getWidth()/2); 
      ellipse.setRadiusY(boundary.getHeight()/2); 

      relocateTargetNode(boundary.getX(), boundary.getY()); 
     } else if (targetNode instanceof Rectangle) { 
      Rectangle rectangle = (Rectangle) targetNode; 
      rectangle.setWidth(boundary.getWidth()); 
      rectangle.setHeight(boundary.getHeight()); 

      relocateTargetNode(boundary.getX(), boundary.getY()); 
     } 
    } 

    private void attachAnchors() { 
     updateAnchorPositions(); 

     getChildren().addAll(
       topLeft, 
       topCenter, 
       topRight, 
       rightCenter, 
       bottomRight, 
       bottomCenter, 
       bottomLeft, 
       leftCenter 
     ); 
    } 

    private void updateAnchorPositions() { 
     topLeft.setCenterX(boundary.getX()); 
     topLeft.setCenterY(boundary.getY()); 
     topCenter.setCenterX(boundary.getX() + boundary.getWidth()/2); 
     topCenter.setCenterY(boundary.getY()); 
     topRight.setCenterX(boundary.getX() + boundary.getWidth()); 
     topRight.setCenterY(boundary.getY()); 
     rightCenter.setCenterX(boundary.getX() + boundary.getWidth()); 
     rightCenter.setCenterY(boundary.getY() + boundary.getHeight()/2); 
     bottomRight.setCenterX(boundary.getX() + boundary.getWidth()); 
     bottomRight.setCenterY(boundary.getY() + boundary.getHeight()); 
     bottomCenter.setCenterX(boundary.getX() + boundary.getWidth()/2); 
     bottomCenter.setCenterY(boundary.getY() + boundary.getHeight()); 
     bottomLeft.setCenterX(boundary.getX()); 
     bottomLeft.setCenterY(boundary.getY() + boundary.getHeight()); 
     leftCenter.setCenterX(boundary.getX()); 
     leftCenter.setCenterY(boundary.getY() + boundary.getHeight()/2); 
    } 
} 

interface DragHandler { 
    void handle(double oldX, double oldY, double newX, double newY); 
} 

// a draggable anchor displayed around a point. 
class Anchor extends Circle { 
    Anchor(Color color, boolean canDragX, boolean canDragY, DragHandler dragHandler) { 
     super(0, 0, 5); 
     setFill(color.deriveColor(1, 1, 1, 0.5)); 
     setStroke(color); 
     setStrokeWidth(2); 
     setStrokeType(StrokeType.OUTSIDE); 

     Util.enableDrag(this, canDragX, canDragY, dragHandler); 
    } 
} 

class Util { 
    // make a targetNode movable by dragging it around with the mouse. 
    static void enableDrag(Circle node, boolean canDragX, boolean canDragY, DragHandler dragHandler) { 
     final Delta dragDelta = new Delta(); 
     node.setOnMousePressed(mouseEvent -> { 
      // record a delta distance for the drag and drop operation. 
      dragDelta.x = node.getCenterX() - mouseEvent.getX(); 
      dragDelta.y = node.getCenterY() - mouseEvent.getY(); 
      node.getScene().setCursor(Cursor.MOVE); 
     }); 
     node.setOnMouseReleased(mouseEvent -> { 
      node.getScene().setCursor(Cursor.HAND); 
     }); 
     node.setOnMouseDragged(mouseEvent -> { 
      double oldX = node.getCenterX(); 
      double oldY = node.getCenterY(); 

      double newX = mouseEvent.getX() + dragDelta.x; 
      if (canDragX && newX > 0 && newX < node.getScene().getWidth()) { 
       node.setCenterX(newX); 
      } 

      double newY = mouseEvent.getY() + dragDelta.y; 
      if (canDragY && newY > 0 && newY < node.getScene().getHeight()) { 
       node.setCenterY(newY); 
      } 

      newX = node.getCenterX(); 
      newY = node.getCenterY(); 

      if (dragHandler != null && (newX != oldX || newY != oldY)) { 
       dragHandler.handle(oldX, oldY, newX, newY); 
      } 
     }); 
     node.setOnMouseEntered(mouseEvent -> { 
      if (!mouseEvent.isPrimaryButtonDown()) { 
       node.getScene().setCursor(Cursor.HAND); 
      } 
     }); 
     node.setOnMouseExited(mouseEvent -> { 
      if (!mouseEvent.isPrimaryButtonDown()) { 
       node.getScene().setCursor(Cursor.DEFAULT); 
      } 
     }); 
    } 

    // make a targetNode movable by dragging it around with the mouse. 
    static void makeDraggable(Rectangle node, DragHandler dragHandler) { 
     final Delta dragDelta = new Delta(); 

     node.setOnMouseEntered(me -> { 
      if (!me.isPrimaryButtonDown()) { 
       node.getScene().setCursor(Cursor.HAND); 
      } 
     }); 
     node.setOnMouseExited(me -> { 
      if (!me.isPrimaryButtonDown()) { 
       node.getScene().setCursor(Cursor.DEFAULT); 
      } 
     }); 
     node.setOnMousePressed(me -> { 
      if (me.isPrimaryButtonDown()) { 
       node.getScene().setCursor(Cursor.DEFAULT); 
      } 
      dragDelta.x = me.getX() - node.getX(); 
      dragDelta.y = me.getY() - node.getY(); 
      node.getScene().setCursor(Cursor.MOVE); 
     }); 
     node.setOnMouseReleased(me -> { 
      if (!me.isPrimaryButtonDown()) { 
       node.getScene().setCursor(Cursor.DEFAULT); 
      } 
     }); 
     node.setOnMouseDragged(me -> { 
      double oldX = node.getX(); 
      double oldY = node.getY(); 

      node.setX(me.getX() - dragDelta.x); 
      node.setY(me.getY() - dragDelta.y); 

      double newX = node.getX(); 
      double newY = node.getY(); 

      if (dragHandler != null && (newX != oldX || newY != oldY)) { 
       dragHandler.handle(oldX, oldY, newX, newY); 
      } 
     }); 
    } 

    // records relative x and y co-ordinates. 
    private static class Delta { 
     double x, y; 
    } 
} 
+0

很抱歉,如果我現在纔回復,非常感謝幫助:)我可以問一個問題嗎?我試圖用上面相同的代碼將圖形的移動限制到場景的邊緣,但向右和向下的移動不應該如其應該那樣工作。我錯在哪裏? –

+0

它看起來像形狀使場景寬度「大跳」。 –