JavaFx-调整矩形大小

JavaFx-调整矩形大小,javafx,drag,Javafx,Drag,我尝试允许用户在javafx中拖动/调整矩形大小。 javafx中的矩形使用TopLeft-X、Y、高度和宽度来绘制 我想做的是在矩形的每个角落有4个控制柄,允许用户拖动控制柄。这将导致调整矩形的大小 我的应用程序抛出一个stackoverflow异常,我知道这是由侦听器的递归调用引起的 我忘了什么吗?还是有一些不必要的倾听者 public class Handler extends Circle { private double deltaX; private double d

我尝试允许用户在javafx中拖动/调整矩形大小。 javafx中的矩形使用TopLeft-X、Y、高度和宽度来绘制

我想做的是在矩形的每个角落有4个控制柄,允许用户拖动控制柄。这将导致调整矩形的大小

我的应用程序抛出一个stackoverflow异常,我知道这是由侦听器的递归调用引起的

我忘了什么吗?还是有一些不必要的倾听者

public class Handler extends Circle
{
    private double deltaX;
    private double deltaY;

    private static final double DEFAULT_RADIUS = 10;
    private static final Color DEFAULT_COLOR = Color.GOLD;

    private DoubleProperty xProperty;
    private DoubleProperty yProperty;

    public Handler(DoubleProperty xProperty, DoubleProperty yProperty)
    {
        super(DEFAULT_RADIUS, DEFAULT_COLOR);

        this.xProperty = xProperty;
        this.yProperty = yProperty;

        init();
    }   

    private void init()
    {
        setFill(DEFAULT_COLOR.deriveColor(1, 1, 1, 0.5));
        setStroke(DEFAULT_COLOR);
        setStrokeWidth(2);
        setStrokeType(StrokeType.OUTSIDE);

        centerXProperty().bind(xProperty);
        centerYProperty().bind(yProperty);

        setOnMousePressed(new EventHandler<MouseEvent>()
        {
            @Override
            public void handle(MouseEvent mouseEvent)
            {
                mouseEvent.consume();

                deltaX = getCenterX() - mouseEvent.getX();
                deltaY = getCenterY() - mouseEvent.getY();

                getScene().setCursor(javafx.scene.Cursor.MOVE);
            }
        });

        setOnMouseReleased(new EventHandler<MouseEvent>()
        {
            @Override
            public void handle(MouseEvent mouseEvent)
            {
                getScene().setCursor(javafx.scene.Cursor.HAND);
            }
        });

        setOnMouseEntered(new EventHandler<MouseEvent>()
        {
            @Override
            public void handle(MouseEvent mouseEvent)
            {
                if (!mouseEvent.isPrimaryButtonDown())
                {
                    getScene().setCursor(javafx.scene.Cursor.HAND);
                }
            }
        });

        setOnMouseExited(new EventHandler<MouseEvent>()
        {
            @Override
            public void handle(MouseEvent mouseEvent)
            {
                if (!mouseEvent.isPrimaryButtonDown())
                {
                    getScene().setCursor(javafx.scene.Cursor.DEFAULT);
                }
            }
        });

        setOnMouseDragged(new EventHandler<MouseEvent>()
        {
            @Override
            public void handle(MouseEvent mouseEvent)
            {
                double newX = mouseEvent.getX() + deltaX;
                double newY = mouseEvent.getY() + deltaY;

                if (newX > 0 && newX < getScene().getWidth())
                {                   
                    xProperty.set(newX);
                }

                if (newY > 0 && newY < getScene().getHeight())
                {                   
                    yProperty.set(newY);
                }
            }
        });
    }

    //JavaFx Accessor and mutator
}


public class CustomRectangle extends Rectangle
{   
    private DoubleProperty topRightX;
    private DoubleProperty topRightY;

    private DoubleProperty btmLeftX;
    private DoubleProperty btmLeftY;

    private DoubleProperty btmRightX;
    private DoubleProperty btmRightY;

    private DoubleProperty customeWidth;
    private DoubleProperty customHeight;

    public CustomRectangle()
    {
        super();
        init();
    }

    public CustomRectangle(double x, double y, double width, double height)
    {
        super(x, y, width, height);
        init();
    }

    public CustomRectangle(double width, double height, Paint fill)
    {
        super(width, height, fill);
        init();
    }

    public CustomRectangle(double width, double height)
    {
        super(width, height);
        init();
    }

    private void init()
    {       
        topRightX = new SimpleDoubleProperty();
        topRightY = new SimpleDoubleProperty();

        btmLeftX = new SimpleDoubleProperty();
        btmLeftY = new SimpleDoubleProperty();

        btmRightX = new SimpleDoubleProperty();
        btmRightY = new SimpleDoubleProperty();

        topRightX.addListener((observable, oldValue, newValue) ->
        {
            this.setWidth(this.getWidth() + (newValue.doubleValue() - oldValue.doubleValue()));
        });

        topRightY.addListener((observable, oldValue, newValue) ->
        {
            this.setY(newValue.doubleValue());
            this.setHeight(this.getHeight() - (newValue.doubleValue() - oldValue.doubleValue()));
        });

        btmLeftX.addListener((observable, oldValue, newValue) ->
        {
            this.setX(newValue.doubleValue());
            this.setWidth(this.getWidth() - (newValue.doubleValue() - oldValue.doubleValue()));
        });

        btmLeftY.addListener((observable, oldValue, newValue) ->
        {
            this.setY(newValue.doubleValue());
            this.setHeight(this.getHeight() + (newValue.doubleValue() - oldValue.doubleValue()));
        });

        btmRightX.addListener((observable, oldValue, newValue) ->
        {
            this.setWidth(this.getWidth() + (newValue.doubleValue() - oldValue.doubleValue()));
        });

        btmRightY.addListener((observable, oldValue, newValue) ->
        {
            this.setHeight(this.getHeight() + (newValue.doubleValue() - oldValue.doubleValue()));
        });

        this.xProperty().addListener((observable, oldValue, newValue) ->
        {           
            btmLeftX.set(newValue.doubleValue());
            topRightX.set(newValue.doubleValue() + this.getWidth());
            btmRightX.set(newValue.doubleValue() + this.getWidth());
        });

        this.yProperty().addListener((observable, oldValue, newValue) ->
        {           
            btmLeftY.set(newValue.doubleValue() + this.getHeight());
            topRightY.set(newValue.doubleValue());
            btmRightY.set(newValue.doubleValue() + this.getHeight());
        });

        this.widthProperty().addListener((observable, oldValue, newValue) ->
        {
            topRightX.set(this.getX() + (newValue.doubleValue() - oldValue.doubleValue()));
            btmRightX.set(this.getX() + (newValue.doubleValue() - oldValue.doubleValue()));
        });

        this.heightProperty().addListener((observable, oldValue, newValue) ->
        {
            btmLeftY.set(this.getY() + (newValue.doubleValue() - oldValue.doubleValue()));
            btmRightY.set(this.getY() + (newValue.doubleValue() - oldValue.doubleValue()));
        });

    } 
    //JavaFx Accessor and Mutator
}

public class FeatureHelper
{   
    private static double orgSceneX;    
    private static double orgSceneY;

    private static double orgTranslateX;
    private static double orgTranslateY;

    public static CustomRectangle createDraggableRectangle(double x, double y, double width, double height,
            boolean resizeImage)
    {
        CustomRectangle rect = new CustomRectangle(x, y, width, height);

        // top left resize handle:
        Handler topLeftHandle = new Handler(rect.topLeftXProperty(), rect.topLeftYProperty());

        // top right resize handle:
        Handler topRightHandle = new Handler(rect.topRightXProperty(), rect.topRightYProperty());

        // bottom left resize handle:
        Handler btmLeftHandle = new Handler(rect.btmLeftXProperty(), rect.btmLeftYProperty());

        // bottom right resize handle:
        Handler btmRightHandle = new Handler(rect.btmRightXProperty(), rect.btmRightYProperty());

        // force circles to live in same parent as rectangle:
        rect.parentProperty().addListener((obs, oldParent, newParent) ->
        {
            for (Circle c : Arrays.asList(topLeftHandle, topRightHandle, btmLeftHandle, btmRightHandle))
            {
                if (newParent != null)
                {
                    ((Pane) newParent).getChildren().add(c);
                }
            }
        });

        rect.setOnMousePressed(event -> 
        {
            event.consume();

            orgSceneX = event.getSceneX();
            orgSceneY = event.getSceneY();

            Node p = ((Node) (event.getSource()));

            orgTranslateX = p.getTranslateX();
            orgTranslateY = p.getTranslateY();          
        });

        rect.setOnMouseDragged(event ->
        {
            double offsetX = event.getSceneX() - orgSceneX;
            double offsetY = event.getSceneY() - orgSceneY;

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

            Node p = ((Node) (event.getSource()));
            p.setTranslateX(newTranslateX);
            p.setTranslateY(newTranslateY);

            for(Circle circle : Arrays.asList(topLeftHandle, topRightHandle, btmLeftHandle, btmRightHandle))
            {
                circle.setTranslateX(newTranslateX);
                circle.setTranslateY(newTranslateY);
            }
        });

        return rect;
    }
}
公共类处理程序扩展了循环
{
私人双重征税;
私人双三角酒店;
专用静态最终双默认_半径=10;
私有静态最终颜色默认值_Color=Color.GOLD;
私有财产;
私有财产;
公共处理程序(DoubleProperty xProperty、DoubleProperty yProperty)
{
超级(默认半径、默认颜色);
this.xProperty=xProperty;
this.yProperty=yProperty;
init();
}   
私有void init()
{
setFill(默认颜色deriveColor(1,1,1,0.5));
设置行程(默认颜色);
设定行程宽度(2);
设置行程类型(行程类型外部);
centerXProperty().bind(xProperty);
centerYProperty().bind(yProperty);
setOnMousePressed(新的EventHandler()
{
@凌驾
公共无效句柄(MouseEvent MouseEvent)
{
mouseEvent.consume();
deltaX=getCenterX()-mouseEvent.getX();
deltaY=getCenterY()-mouseEvent.getY();
getScene().setCursor(javafx.scene.Cursor.MOVE);
}
});
setOnMouseReleased(新的EventHandler()
{
@凌驾
公共无效句柄(MouseEvent MouseEvent)
{
getScene().setCursor(javafx.scene.Cursor.HAND);
}
});
SetOnMouseCentered(新事件处理程序()
{
@凌驾
公共无效句柄(MouseEvent MouseEvent)
{
如果(!mouseEvent.isPrimaryButtonDown())
{
getScene().setCursor(javafx.scene.Cursor.HAND);
}
}
});
setOnMouseExited(新的EventHandler()
{
@凌驾
公共无效句柄(MouseEvent MouseEvent)
{
如果(!mouseEvent.isPrimaryButtonDown())
{
getScene().setCursor(javafx.scene.Cursor.DEFAULT);
}
}
});
SetOnMouseDrawed(新的EventHandler()
{
@凌驾
公共无效句柄(MouseEvent MouseEvent)
{
double newX=mouseEvent.getX()+deltaX;
double newY=mouseEvent.getY()+deltaY;
如果(newX>0&&newX0&&newY
{
this.setWidth(this.getWidth()+(newValue.doubleValue()-oldValue.doubleValue());
});
addListener((可观察、旧值、新值)->
{
this.setY(newValue.doubleValue());
this.setHeight(this.getHeight()-(newValue.doubleValue()-oldValue.doubleValue());
});
btmLeftX.addListener((可观察、旧值、新值)->
{
this.setX(newValue.doubleValue());
this.setWidth(this.getWidth()-(newValue.doubleValue()-oldValue.doubleValue());
});
btmLeftY.addListener((可观察、旧值、新值)->
{
this.setY(newValue.doubleValue());
this.setHeight(this.getHeight()+(newValue.doubleValue()-oldValue.doubleValue());
});
btmRightX.addListener((可观察、旧值、新值)->
{
this.setWidth(this.getWidth()+(newValue.doubleValue()-oldValue.doubleValue());
});
btmRightY.addListener((可观察、旧值、新值)->
{
this.setHeight(this.getHeight()+(newValue.doubleValue()-oldValue.doubleValue());
});
this.xProperty().addListener((可观察、旧值、新值)->
{           
btmLeftX.set(newValue.doubleValue());
set(newValue.doubleValue()+this.getWidth());
btmRightX.set(newValue.doubleValue()+this.getWidth());
});
this.yProperty().addListener((可观察、旧值、新值)->