2014-10-10 1 views
2

С помощью следующего кода (благодаря нескольким сообщениям здесь) я рисую прямоугольник, который я хочу изменить и подвижным. Два анкера (верхний левый и правый нижний) выполняют то, что я хочу, а последний (нижний срез) перемещает прямоугольник, но два первых якоря не следуют за прямоугольником.изменяемый размер и подвижный прямоугольник

Когда я их перемещаю, слушатель из них изменяет размер прямоугольника.

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

В качестве общей стратегии, я бы связать позиции кругов на позицию прямоугольника - таким образом окружности всегда будут находиться в правильном положении относительно прямоугольника. В обработчиках перетаскивания измените свойства только прямоугольника, и круги будут следовать из-за привязки. Вы действительно должны очистить код, который вы разместили, там есть избыточные переменные, и при перетаскивании вы получаете исключения. Пересчет сцены не нужен. –

+0

Во-первых, я не знаю, как привязать круги к прямоугольнику, поэтому я разместил здесь. И за ошибки, не знаю, как их очистить. Спасибо за ваш совет –

ответ

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

Большое вам спасибо. Именно то, что мне нужно! –

+0

Добро пожаловать. Я рекомендую вам внимательно прочитать его и убедиться, что вы понимаете, как это работает. –

+0

Я просто делаю это. Очень интересно. Я должен понять это, потому что я хочу, чтобы прямоугольник был прозрачным, чтобы видеть рабочий стол позади (не сцена/сцена) –