2014-10-10 74 views
2

用下面的代碼(感謝這裏的幾個帖子),我畫了一個矩形,我想要可調整大小和移動。 兩個錨點(左上角和右下角)按照我的意願做,而最後一個(下中下)移動矩形,但是兩個錨點不跟隨矩形。resizable和可移動的矩形

當我讓它們移動時,它們的監聽器調整矩形的大小。

package application; 

import javafx.application.Application; 
import javafx.beans.property.DoubleProperty; 
import javafx.beans.property.SimpleDoubleProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.event.EventHandler; 
import javafx.scene.Cursor; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Circle; 
import javafx.scene.shape.Rectangle; 
import javafx.scene.shape.Shape; 
import javafx.scene.shape.StrokeType; 
import javafx.stage.Stage; 
import javafx.stage.StageStyle; 

public class Main extends Application { 

    private Rectangle rectangle; 
    private Group group; 
    private Scene scene; 
    private Stage primaryStage; 
    private ObservableList<Double> Coins; 

    public static void main(String[] args) { 
    Application.launch(args); 
    } 

    @Override 
    public void start(Stage primaryStage) { 
     group = new Group();   
     rectangle = new Rectangle(200,200,400,300); 


     Coins = FXCollections.observableArrayList(); 
     //UpperLeft 
     Coins.add(rectangle.getX()); 
     Coins.add(rectangle.getY()); 
     //LowerRight 
     Coins.add(rectangle.getX() + rectangle.getWidth()); 
     Coins.add(rectangle.getY()+ rectangle.getHeight()); 
     //Moving 
     Coins.add(rectangle.getX() + (rectangle.getWidth()/2)); 
     Coins.add(rectangle.getY()+ (rectangle.getHeight())); 


     group.getChildren().addAll(createControlAnchorsFor(Coins)); 
     group.getChildren().add(rectangle); 
     scene = new Scene(group,800,800); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 


//@return a list of anchors which can be dragged around to modify points in the format [x1, y1, x2, y2...] 
private ObservableList<Anchor> createControlAnchorsFor(final ObservableList<Double> points) { 
    ObservableList<Anchor> anchors = FXCollections.observableArrayList(); 

    //Coin GaucheHaut 
    DoubleProperty xProperty = new SimpleDoubleProperty(points.get(0)); 
    DoubleProperty yProperty = new SimpleDoubleProperty(points.get(1)); 

    xProperty.addListener(new ChangeListener<Number>() { 
     @Override public void changed(ObservableValue<? extends Number> ov, Number oldX, Number x) { 
      System.out.println(oldX + " et " + x); 
      rectangle.setX((double) x); 
      rectangle.setWidth((double) rectangle.getWidth() -((double) x- (double) oldX)); 
      anchors.get(2).setCenterX((double) x + rectangle.getWidth()/2); 
     } 
    }); 

    yProperty.addListener(new ChangeListener<Number>() { 
     @Override public void changed(ObservableValue<? extends Number> ov, Number oldY, Number y) { 
      rectangle.setY((double) y); 
      rectangle.setHeight((double) rectangle.getHeight() -((double) y- (double) oldY)); 
     } 
    }); 
    anchors.add(new Anchor(Color.GOLD, xProperty, yProperty)); 

    //Coin DroiteBas 
    DoubleProperty xProperty2 = new SimpleDoubleProperty(points.get(2)); 
    DoubleProperty yProperty2 = new SimpleDoubleProperty(points.get(3)); 

    xProperty2.addListener(new ChangeListener<Number>() { 
     @Override public void changed(ObservableValue<? extends Number> ov, Number oldX, Number x) { 
      rectangle.setWidth((double) rectangle.getWidth() -((double) oldX- (double) x)); 
      anchors.get(2).setCenterX((double) x - rectangle.getWidth()/2); 
     } 
     }); 

     yProperty2.addListener(new ChangeListener<Number>() { 
     @Override public void changed(ObservableValue<? extends Number> ov, Number oldY, Number y) { 
      rectangle.setHeight((double) rectangle.getHeight() -((double) oldY- (double) y)); 
      anchors.get(2).setCenterY((double) y); 
     } 
     }); 
     anchors.add(new Anchor(Color.GOLD, xProperty2, yProperty2)); 

     //Moving 
     DoubleProperty xPropertyM = new SimpleDoubleProperty(points.get(4)); 
     DoubleProperty yPropertyM = new SimpleDoubleProperty(points.get(5)); 
     xPropertyM.addListener(new ChangeListener<Number>() { 
      @Override public void changed(ObservableValue<? extends Number> ov, Number oldX, Number x) { 
       rectangle.setX((double) x - rectangle.getWidth()/2); 
       //anchors.get(0).setCenterX((double) x- rectangle.getWidth()/2); 
       //anchors.get(0).setVisible(false); 
      } 
     }); 

     yPropertyM.addListener(new ChangeListener<Number>() { 
      @Override public void changed(ObservableValue<? extends Number> ov, Number oldY, Number y) { 
       rectangle.setY((double) y - rectangle.getHeight()); 
       Coins.set(1, (double) y); 
      } 
     }); 
     anchors.add(new Anchor(Color.GOLD, xPropertyM, yPropertyM)); 

    return anchors; 
} 

//a draggable anchor displayed around a point. 
class Anchor extends Circle { 
    private final DoubleProperty x, y; 

    Anchor(Color color, DoubleProperty x, DoubleProperty y) { 
    super(x.get(), y.get(), 20); 
    setFill(color.deriveColor(1, 1, 1, 0.5)); 
    setStroke(color); 
    setStrokeWidth(2); 
    setStrokeType(StrokeType.OUTSIDE); 

    this.x = x; 
    this.y = y; 

    x.bind(centerXProperty()); 
    y.bind(centerYProperty()); 
    enableDrag(); 
    } 

//make a node movable by dragging it around with the mouse. 
    private void enableDrag() { 
    final Delta dragDelta = new Delta(); 
    setOnMousePressed(new EventHandler<MouseEvent>() { 
     @Override public void handle(MouseEvent mouseEvent) { 
     // record a delta distance for the drag and drop operation. 
     dragDelta.x = getCenterX() - mouseEvent.getX(); 
     dragDelta.y = getCenterY() - mouseEvent.getY(); 
     getScene().setCursor(Cursor.MOVE); 
     } 
    }); 
    setOnMouseReleased(new EventHandler<MouseEvent>() { 
     @Override public void handle(MouseEvent mouseEvent) { 
     getScene().setCursor(Cursor.HAND); 

     } 
    }); 
    setOnMouseDragged(new EventHandler<MouseEvent>() { 
     @Override public void handle(MouseEvent mouseEvent) { 
     double newX = mouseEvent.getX() + dragDelta.x; 
     if (newX > 0 && newX < getScene().getWidth()) { 
      setCenterX(newX); 
     } 
     double newY = mouseEvent.getY() + dragDelta.y; 
     if (newY > 0 && newY < getScene().getHeight()) { 
      setCenterY(newY); 
     } 

     //Recompute screen; 
     group.getChildren().add(rectangle); 
     scene = new Scene(group,800,800);; 
     primaryStage.setScene(scene); 
     } 
    }); 
    setOnMouseEntered(new EventHandler<MouseEvent>() { 
     @Override public void handle(MouseEvent mouseEvent) { 
     if (!mouseEvent.isPrimaryButtonDown()) { 
      getScene().setCursor(Cursor.HAND); 
     } 
     } 
    }); 
    setOnMouseExited(new EventHandler<MouseEvent>() { 
     @Override public void handle(MouseEvent mouseEvent) { 
     if (!mouseEvent.isPrimaryButtonDown()) { 
      getScene().setCursor(Cursor.DEFAULT); 
     } 
     } 
    }); 
    } 
//records relative x and y co-ordinates. 
    private class Delta { double x, y; } 

} 
} 

任何想法,什麼和在哪裏我應該添加的東西?

+0

作爲一般的策略,我想圓的位置綁定到矩形的位置相對於矩形。在拖動處理程序中,僅更改矩形的屬性,並且由於綁定,圓圈將跟隨。你應該清理你發佈的代碼 - 這裏有多餘的變量,當你拖動時會拋出異常。重新計算場景是不必要的。 – 2014-10-10 12:55:34

+0

首先,我不知道如何將圓圈綁定到矩形,這就是我在這裏發佈的原因。對於錯誤,不知道如何清理它。感謝您的建議 – 2014-10-10 12:57:26

回答

13

由於「手柄」總是在相對於矩形的相同位置,我會將它們的位置綁定到矩形的位置。您可以通過

circle.centerXProperty().bind(...); 
circle.centerYProperty().bind(...); 

其中參數是ObservableValue<Number>

然後在拖動處理程序中,只需根據需要移動Rectangle(計算稍微複雜但不能太差)。由於圓的位置是綁定的,它們將跟隨矩形。

下面是一個使用這種策略的一種可能實現: - 這樣的圈總是會在正確的位置

import java.util.Arrays; 

import javafx.application.Application; 
import javafx.geometry.Point2D; 
import javafx.scene.Cursor; 
import javafx.scene.Scene; 
import javafx.scene.layout.Pane; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Circle; 
import javafx.scene.shape.Rectangle; 
import javafx.stage.Stage; 

public class DraggingRectangle extends Application { 

    public static void main(String[] args) { 
     Application.launch(args); 
    } 

    @Override 
    public void start(Stage primaryStage) { 

     Pane root = new Pane(); 

     Rectangle rect = createDraggableRectangle(200, 200, 400, 300); 
     rect.setFill(Color.NAVY); 

     root.getChildren().add(rect); 


     Scene scene = new Scene(root, 800, 800); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    private Rectangle createDraggableRectangle(double x, double y, double width, double height) { 
     final double handleRadius = 10 ; 

     Rectangle rect = new Rectangle(x, y, width, height); 

     // top left resize handle: 
     Circle resizeHandleNW = new Circle(handleRadius, Color.GOLD); 
     // bind to top left corner of Rectangle: 
     resizeHandleNW.centerXProperty().bind(rect.xProperty()); 
     resizeHandleNW.centerYProperty().bind(rect.yProperty()); 

     // bottom right resize handle: 
     Circle resizeHandleSE = new Circle(handleRadius, Color.GOLD); 
     // bind to bottom right corner of Rectangle: 
     resizeHandleSE.centerXProperty().bind(rect.xProperty().add(rect.widthProperty())); 
     resizeHandleSE.centerYProperty().bind(rect.yProperty().add(rect.heightProperty())); 

     // move handle: 
     Circle moveHandle = new Circle(handleRadius, Color.GOLD); 
     // bind to bottom center of Rectangle: 
     moveHandle.centerXProperty().bind(rect.xProperty().add(rect.widthProperty().divide(2))); 
     moveHandle.centerYProperty().bind(rect.yProperty().add(rect.heightProperty())); 

     // force circles to live in same parent as rectangle: 
     rect.parentProperty().addListener((obs, oldParent, newParent) -> { 
      for (Circle c : Arrays.asList(resizeHandleNW, resizeHandleSE, moveHandle)) { 
       Pane currentParent = (Pane)c.getParent(); 
       if (currentParent != null) { 
        currentParent.getChildren().remove(c); 
       } 
       ((Pane)newParent).getChildren().add(c); 
      } 
     }); 

     Wrapper<Point2D> mouseLocation = new Wrapper<>(); 

     setUpDragging(resizeHandleNW, mouseLocation) ; 
     setUpDragging(resizeHandleSE, mouseLocation) ; 
     setUpDragging(moveHandle, mouseLocation) ; 

     resizeHandleNW.setOnMouseDragged(event -> { 
      if (mouseLocation.value != null) { 
       double deltaX = event.getSceneX() - mouseLocation.value.getX(); 
       double deltaY = event.getSceneY() - mouseLocation.value.getY(); 
       double newX = rect.getX() + deltaX ; 
       if (newX >= handleRadius 
         && newX <= rect.getX() + rect.getWidth() - handleRadius) { 
        rect.setX(newX); 
        rect.setWidth(rect.getWidth() - deltaX); 
       } 
       double newY = rect.getY() + deltaY ; 
       if (newY >= handleRadius 
         && newY <= rect.getY() + rect.getHeight() - handleRadius) { 
        rect.setY(newY); 
        rect.setHeight(rect.getHeight() - deltaY); 
       } 
       mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY()); 
      } 
     }); 

     resizeHandleSE.setOnMouseDragged(event -> { 
      if (mouseLocation.value != null) { 
       double deltaX = event.getSceneX() - mouseLocation.value.getX(); 
       double deltaY = event.getSceneY() - mouseLocation.value.getY(); 
       double newMaxX = rect.getX() + rect.getWidth() + deltaX ; 
       if (newMaxX >= rect.getX() 
         && newMaxX <= rect.getParent().getBoundsInLocal().getWidth() - handleRadius) { 
        rect.setWidth(rect.getWidth() + deltaX); 
       } 
       double newMaxY = rect.getY() + rect.getHeight() + deltaY ; 
       if (newMaxY >= rect.getY() 
         && newMaxY <= rect.getParent().getBoundsInLocal().getHeight() - handleRadius) { 
        rect.setHeight(rect.getHeight() + deltaY); 
       } 
       mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY()); 
      } 
     }); 

     moveHandle.setOnMouseDragged(event -> { 
      if (mouseLocation.value != null) { 
       double deltaX = event.getSceneX() - mouseLocation.value.getX(); 
       double deltaY = event.getSceneY() - mouseLocation.value.getY(); 
       double newX = rect.getX() + deltaX ; 
       double newMaxX = newX + rect.getWidth(); 
       if (newX >= handleRadius 
         && newMaxX <= rect.getParent().getBoundsInLocal().getWidth() - handleRadius) { 
        rect.setX(newX); 
       } 
       double newY = rect.getY() + deltaY ; 
       double newMaxY = newY + rect.getHeight(); 
       if (newY >= handleRadius 
         && newMaxY <= rect.getParent().getBoundsInLocal().getHeight() - handleRadius) { 
        rect.setY(newY); 
       } 
       mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY()); 
      } 

     }); 

     return rect ; 
    } 

    private void setUpDragging(Circle circle, Wrapper<Point2D> mouseLocation) { 

     circle.setOnDragDetected(event -> { 
      circle.getParent().setCursor(Cursor.CLOSED_HAND); 
      mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY()); 
     }); 

     circle.setOnMouseReleased(event -> { 
      circle.getParent().setCursor(Cursor.DEFAULT); 
      mouseLocation.value = null ; 
     }); 
    } 

    static class Wrapper<T> { T value ; } 


} 
+0

非常感謝。正是我需要的! – 2014-10-10 13:44:44

+0

不客氣。我建議你仔細閱讀,並確保你瞭解它是如何工作的。 – 2014-10-10 13:45:20

+0

我只是這麼做的。很有意思。我必須對它進行解釋,因爲我想現在矩形是透明的,以便看到桌面背後(而不是舞臺/場景) – 2014-10-10 14:00:09