Problems getting the width and height of a pane from a class object - Javafx

10,866

You are invoking getWidth() and getHeight() in the constructor, which is necessarily executed before the Pane is added to any live scene. Hence these are going to return 0 (because the pane hasn't been laid out yet).

Instead, bind the coordinates of the line to values based on the widthProperty and heightProperty:

line = new Line();
line.startXProperty().bind(widthProperty().divide(2));
line.startYProperty().bind(heightProperty().divide(2));
line.endXProperty().bind(widthProperty().divide(2));
line.endYProperty().bind(heightProperty().divide(2).subtract(lineLength));
Share:
10,866
John Conner
Author by

John Conner

Updated on June 14, 2022

Comments

  • John Conner
    John Conner almost 2 years

    Ok so I understand the binding principle on resizing objects in a pane as it is being resized, this problem is a bit different. I am confused, I am trying to create a class that extends Pane that creates in my main a line that has it's startX and startY coordinates bound to the center of a Pane. The problem is that when using getWidth() / 2 or getHeight() /2 the coordinate are being placed somewhere up and to the left of the starting coordinates (0, 0) when I press my arrow key's which when pressed creates another line that is drawn in the given direction pressed and starting from the end of the last line drawn.

    Like I said when I use getWidth() / 2 and getHeight / 2 as the startX and startY coordinates of my new line, in return the line gets placed in a negative coordinate, placing it off the screen above and to the left of the starting (0, 0) coordinates of the pane.

    Below is part of my code which contains the default constructor which I am having the problem with, on the non-default constructor I give the ability to manually enter the starting coordinates and when I do this, the line is placed exactly where I want it.

    public class LineDrawingObject extends Pane {
        // ArrayList to store the Line Object's
        ArrayList<Line> lines = new ArrayList<>();
        Line line;
        private Color lineColor;
        private double lineLength;
        private int lineCount = 0;
        private double startX;
        private double startY;
        private double endX;
        private double endY;
    
        /** Default Constructor */
        public LineDrawingObject() {
            this.lineLength = 20;
            line = new Line(this.getWidth() / 2, this.getHeight() / 2,
                (this.getWidth() / 2), (this.getHeight() / 2) - this.lineLength);
            this.lineColor = Color.BLACK;
            line.setStroke(this.lineColor);
            this.lineCount++;
            this.lines.add(line);
            getChildren().add(line);
        }
    

    Edit: Figured I might need to add more information

    also I wanted to add that my pane size is set in new Scene(pane, 250, 250) so the center coordinates would be (125, 125)....Would using the getWidth and getHeight methods on the pane return an invalid size if it hasn't yet been drawn? I tried setting the preferred size within my start method but it didn't seem to work. If that is the case how would I remedy this problem?

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.Pane;
    import javafx.scene.paint.Color;
    import javafx.stage.Stage;
    
    /**
     * Created by John on 7/24/2014.
     */
    public class DrawLines extends Application {
        @Override // Override the start method in the Application class
        public void start(Stage primaryStage) {
            // Create a pane
            Pane pane = new Pane();
    
            // Create object to draw lines upon KeyEvent
            LineDrawingObject lineDrawingObject = new LineDrawingObject(20, Color.BLACK,
                pane.getWidth() / 2, pane.getWidth() / 2);
            pane.getChildren().add(lineDrawingObject);
            lineDrawingObject.setOnKeyPressed(e -> {
                lineDrawingObject.paintLine(e.getCode());
            });
    
            // Create a scene and place it in the pane
            Scene scene = new Scene(pane, 250, 250);
            primaryStage.setTitle("DrawLines"); // Set the stage title
            primaryStage.setScene(scene); // Place the scene in the stage
            primaryStage.show(); // Display the stage
    
            // Allow object to receive key input
            lineDrawingObject.requestFocus();
        }
    }
    

    and here is the LineDrawing Object:

    import javafx.scene.input.KeyCode;
    import javafx.scene.layout.Pane;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Line;
    
    import java.util.ArrayList;
    
    /** This object will draw lines inside of a Pane when an arrow key is
     *  pressed and will draw it in that direction from the current line */
    public class LineDrawingObject extends Pane {
        // ArrayList to store the Line Object's
        ArrayList<Line> lines = new ArrayList<>();
        Line line;
        private Color lineColor;
        private double lineLength;
        private int lineCount = 0;
        private double startX;
        private double startY;
        private double endX;
        private double endY;
    
        /** Default Constructor */
        public LineDrawingObject() {
            this.lineLength = 20;
            line = new Line(this.getWidth() / 2, this.getHeight() / 2,
                (this.getWidth() / 2), (this.getHeight() / 2) - this.lineLength);
            this.lineColor = Color.BLACK;
            line.setStroke(this.lineColor);
            this.lineCount++;
            this.lines.add(line);
            getChildren().add(line);
        }
    
        /** Secondary Constructor, allows you to control the line length and color */
        public LineDrawingObject(double lineLength, Color lineColor, double startX, double startY) {
            this.lineLength = lineLength;
            line = new Line(startX, startY,
                    startX, startY - this.lineLength);
            this.lineColor = lineColor;
            line.setStroke(this.lineColor);
            this.lineCount++;
            this.lines.add(line);
            getChildren().add(line);
        }
    
        public ArrayList<Line> getLines() {
            return lines;
        }
    
        public void setLines(ArrayList<Line> lines) {
            this.lines = lines;
        }
    
        public Line getLine() {
            return this.line;
        }
    
        public void setLine(Line line) {
            this.line = line;
        }
    
        public Color getLineColor() {
            return this.lineColor;
        }
    
        public void setLineColor(Color lineColor) {
            this.lineColor = lineColor;
        }
    
        public double getLineLength() {
            return this.lineLength;
        }
    
        public void setLineLength(double lineLength) {
            this.lineLength = lineLength;
        }
    
        public int getLineCount() {
            return this.lineCount;
        }
    
        public void setLineCount(int lineCount) {
            this.lineCount = lineCount;
        }
    
        public double getStartX() {
            return this.startX;
        }
    
        public void setStartX(double startX) {
            this.startX = startX;
        }
    
        public double getStartY() {
            return this.startY;
        }
    
        public void setStartY(double startY) {
            this.startY = startY;
        }
    
        public double getEndX() {
            return this.endX;
        }
    
        public void setEndX(double endX) {
            this.endX = endX;
        }
    
        public double getEndY() {
            return this.endY;
        }
    
        public void setEndY(double endY) {
            this.endY = endY;
        }
    
        public void paintLine(KeyCode keyCode) {
            // Set line start coordinates to the end of the last line
            setStartX(line.getEndX());
            setStartY(line.getEndY());
    
            // Set line end coordinates
            switch (keyCode) {
                case UP: goUp(); break;
                case LEFT: goLeft(); break;
                case DOWN: goDown(); break;
                case RIGHT: goRight(); break;
            }
    
            // Create line
            line = new Line(getStartX(), getStartY(), getEndX(), getEndY());
            line.setStroke(lineColor);
            this.lines.add(line);
            getChildren().add(line);
        }
    
        public void goLeft() {
            setEndX(getStartX() - this.lineLength);
            setEndY(getStartY());
        }
    
        public void goRight() {
            setEndX(getStartX() + this.lineLength);
            setEndY(getStartY());
        }
    
        public void goUp() {
            setEndX(getStartX());
            setEndY(getStartY() - this.lineLength);
        }
    
        public void goDown() {
            setEndX(getStartX());
            setEndY(getStartY() + this.lineLength);
        }
    }
    

    Using Default Constructor Using Default Constructor

    Using Custom Coordinates Using Custom Coordinates

  • John Conner
    John Conner almost 10 years
    I tried this and thought for sure that it would work, but the problem is that as more lines are added the pane grows to fit it and therefore moves the center line every-time the width or height grows from an added line and it now starts the lines from (0,0) of the pane
  • John Conner
    John Conner almost 10 years
    Could the problem be that I am still performing this action before the pane is added to the scene?