如何在JavaFX中设置节点相对于另一个节点的位置?

时间:2017-09-19 11:18:07

标签: javafx

我的JavaFx应用程序中有两个控件 1. TextField 2. ListView

我想使用TextField的坐标将ListView放在TextField的正下方。 因为TextField的位置发生了变化。

详细信息:

我正在为我的项目创建自动建议文本字段,当用户在文本字段中输入内容时,需要弹出列表。该文本字段可能存在于场景中的任何位置,也可以在另一个列表视图中。所以我需要的是如何在屏幕上获取文本字段的坐标,以便我可以在文本字段的正下方放置列表视图。

3 个答案:

答案 0 :(得分:0)

我在这里看到多个选项:

  • 我认为你可能更善于使用ContextMenu。当您显示ContextMenu时,您可以定义一个视图,它应该相对于视图显示以及显示它的一侧。

  • 如果ContextMenu无法满足您的要求,我最简单的想法就是您将TextField替换为VBox并输入TextFieldListView中的VBox。这将使他们在一起,您可以像定位VBox一样定位TextField

  • 最后,如果您想自己布局,TextField包含layoutXlayoutY以及heightwidth等属性。使用这些可以计算ListView的位置(例如ListView的Y位置为textField.layoutY + textField.height)。为了使这个位置保持最新,我看到两个选项:

    • 要定位TextField您可能已覆盖某些layoutChildrens的{​​{1}}方法,因此您可以将此代码放在那里。
    • 如果没有,您还可以在这些属性上注册Parent,以便在他们更改并重新定位ListView时收到通知。

答案 1 :(得分:0)

要获取屏幕坐标中文本字段的位置,可以执行

Bounds boundsInScreen = textField.localToScreen(textField.getBoundsInLocal());

这将返回一个Bounds对象,您可以从中获取各种坐标,例如

Popup popup = ... ;
popup.setWidth(boundsInScreen.getWidth());
popup.show(textField, boundsInScreen.getMinX(), boundsInScreen.getMaxY());

答案 2 :(得分:0)

我创建了这个帮助类来做到这一点。

public class PositionUtils {

    public static void position(Region movable, Region reference, Anchor movableAnchor, Anchor referenceAnchor, float xOffset, float yOffset) {
        double x = reference.localToScene(reference.getBoundsInLocal()).getMaxX();
        double y = reference.localToScene(reference.getBoundsInLocal()).getMaxY();

        Point referencePoint = referenceAnchor.referencePoint;
        Point movablePoint = movableAnchor.movablePoint;

        x -= (0.5 * movable.getWidth()) * movablePoint.x;
        y += (0.5 * movable.getHeight()) * movablePoint.y;

        x += (0.5 * reference.getWidth()) * referencePoint.x;
        y -= (0.5 * reference.getHeight()) * referencePoint.y;

        movable.setLayoutX(x + xOffset);
        movable.setLayoutY(y + yOffset);
    }

    public static void position(Pane movable, Pane reference, Anchor movableAnchor, Anchor referenceAnchor) {
        position(movable, reference, movableAnchor, referenceAnchor, 0, 0);
    }

    public static void position(Pane movable, Pane reference, Side side) {
        position(movable, reference, side, 0, 0);
    }

    public static void position(Pane movable, Pane reference, Side side, float xOffset, float yOffset) {
        Anchor movableAnchor = null;
        Anchor referenceAnchor = null;
        switch (side) {
            case TOP:
                movableAnchor = Anchor.BOTTOM_CENTER;
                referenceAnchor = Anchor.TOP_CENTER;
                break;
            case BOTTOM:
                movableAnchor = Anchor.TOP_CENTER;
                referenceAnchor = Anchor.BOTTOM_CENTER;
                break;
            case RIGHT:
                movableAnchor = Anchor.CENTER_LEFT;
                referenceAnchor = Anchor.CENTER_RIGHT;
                break;
            case LEFT:
                movableAnchor = Anchor.CENTER_RIGHT;
                referenceAnchor = Anchor.CENTER_LEFT;
                break;
        }
        position(movable, reference, movableAnchor, referenceAnchor, xOffset, yOffset);
    }

    public enum Anchor {
        TOP_LEFT(new Point(0, 0), new Point(-2, 2)),
        TOP_CENTER(new Point(1, 0), new Point(-1, 2)),
        TOP_RIGHT(new Point(2, 0), new Point(0, 2)),
        CENTER_LEFT(new Point(0, -1), new Point(-2, 1)),
        CENTER(new Point(1, -1), new Point(-1, 1)),
        CENTER_RIGHT(new Point(1, -2), new Point(0, 1)),
        BOTTOM_LEFT(new Point(0, -2), new Point(-2, 0)),
        BOTTOM_CENTER(new Point(1, -2), new Point(-1, 0)),
        BOTTOM_RIGHT(new Point(2, -2), new Point(0, 0));

        public Point referencePoint;
        public Point movablePoint;

        Anchor(Point movablePoint, Point referencePoint) {
            this.referencePoint = referencePoint;
            this.movablePoint = movablePoint;
        }
    }

    public enum Side {
        TOP,
        BOTTOM,
        RIGHT,
        LEFT
    }
}