-1

this is going to be a second part to my first post about full screening.

Scaling start screen with full screen in JavaFX

With a little bit of tweaking the start screen scales when full screen but now, I can't seem to get the game itself to scale correctly.

package application.console;

import java.util.List;

import application.areas.startingArea.SA;
import application.areas.vanguardForest.VFCmds;
import application.areas.vanguardForest.VFNavi;
import application.areas.vanguardForest.VFPkups;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;

public class Console extends Region {

    public static double WIDTH = 990;
    public static double HEIGHT = 525;
    
    private final Font cinzel;
    
    private final BorderPane root;
    
    private final VBox console;
    private final ScrollPane scroll;
    
    private final HBox inputBar;
    private final TextField input;
    private final Text carrot;
    
    public Console() {
        this.root = new BorderPane();
        root.setStyle("-fx-background-color: #232323;");
        
        this.cinzel = Font.loadFont("file:fonts/static/Cinzel-Medium.ttf", 16);
        
        this.console = new VBox();
        console.setPrefWidth(WIDTH);
        console.setPrefHeight(HEIGHT);
        
        this.scroll = new ScrollPane();
        scroll.setContent(console);
        scroll.setStyle("-fx-background: #232323;"
                + "-fx-background-color: transparent;"
                + "-fx-border-color: #232323;"
                + "-fx-focus-color: #232323;");
        scroll.setHbarPolicy(ScrollBarPolicy.NEVER);
        scroll.setVbarPolicy(ScrollBarPolicy.NEVER);
        scroll.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, null, null)));
        
        console.setStyle("-fx-background-color: #232323;"
                + "-fx-focus-color: #232323;");
        
        console.heightProperty().addListener(new ChangeListener<Object>() {
            @Override
            public void changed(ObservableValue<?> observable, Object oldValue, Object newValue) {
                
                scroll.setVvalue((Double)newValue);
            }
            
        });
        
        this.inputBar = new HBox();
        inputBar.setPrefSize(WIDTH, 16);
        
        this.input = new TextField();
        input.setStyle("-fx-background-color: transparent;"
                + "-fx-text-fill: #FFFFFF;"
                + "-fx-highlight-fill: #FFFFFF;"
                + "-fx-highlight-text-fill: #232323;"
                );
        input.setFont(cinzel);
        input.setPrefWidth(WIDTH);
        
        this.carrot = new Text(" > ");
        carrot.setFont(Font.loadFont("file:fonts/static/Cinzel-Medium.ttf", 24));
        carrot.setFill(Color.WHITE);
        
        
        inputBar.getChildren().addAll(carrot, input);
        
        root.setMinSize(WIDTH, (HEIGHT - input.getHeight()));
        
        input.setOnAction(e -> {
            
            String s = (input.getText()).stripTrailing();
            
            
            if ((SA.isBuried || SA.inVF) && SS.gameStart) {
                Cmds.commands(s);   //has general functions
                VFCmds.commands(s); //doesn't have function until specific command 
                VFPkups.pickUp(s); //commands that allows pickups to be made within the game
                VFNavi.commands(s); //commands navigation for selected area
            } else {
                Cmds.commands(s);
            }

            input.clear();
        });
        
        root.getChildren().addAll(console, scroll, inputBar);
        root.setBottom(inputBar);
        
    }
    
    @Override 
    protected void layoutChildren() {
        double xScale = getWidth() / root.getWidth();
        double yScale = getHeight() / root.getHeight();
        double scale = Math.min(xScale, yScale);
        
        for (BorderPane bp : List.of(root)) {
            scaleAndCenter(bp, scale); 
        }
        
        for (VBox vb : List.of(console)) {
            scaleAndCenter(vb, scale);
        }
        
        for (HBox hb : List.of(inputBar)) {
            scaleAndCenter(hb, scale);
        }
        
        for (ScrollPane sp : List.of(scroll)) {
            scaleAndCenter(sp, scale); 
        }
        
        for (TextField tf : List.of(input)) {
            scaleAndCenter(tf, scale);
        }
        
        for (Text text : List.of(carrot)) {
            scaleAndCenter(text, scale); 
        }
    }

    private void scaleAndCenter(BorderPane root, double scale) {
        double w = scale * root.getWidth();
        double h = scale * root.getHeight();
        

        root.setPrefSize(w, h);
        root.relocate((getWidth() - w) / 2, (getHeight() - h) / 2);
    }
    
    private void scaleAndCenter(VBox vb, double scale) {
        double w = scale * vb.getWidth();
        double h = scale * vb.getHeight();
        
        vb.setPrefSize(w, h);
        vb.relocate((getWidth() - w) / 2, (getHeight() - h) / 2);
    }
    
    private void scaleAndCenter(HBox hb, double scale) {
        double w = scale * hb.getWidth();
        double h = scale * hb.getHeight();
        
        hb.setPrefSize(w, h);
        hb.relocate((getWidth() - w) / 2, (getHeight() - h) / 2);
    }
    
    private void scaleAndCenter(TextField input, double scale) {
        double w = scale * input.getWidth();
        double h = scale * input.getHeight();
        
        input.setPrefSize(w, 16);
        input.relocate((getWidth() - w) / 2, (getHeight() - h) / 2);

    }
    
    private void scaleAndCenter(ScrollPane scroll, double scale) {
        double w = scale * scroll.getWidth();
        double h = scale * scroll.getHeight();
        
        scroll.setPrefSize(w, h);
        scroll.relocate((getWidth() - w) / 2, (getHeight() - h) / 2);
    }
    
    private void scaleAndCenter(Text text, double scale) {
        double w = scale * text.getLayoutBounds().getWidth();
        double h = scale * text.getLayoutBounds().getHeight();
        double size = scale * text.getFont().getSize();
        
        text.setFont(Font.font(
                text.getFont().getFamily(),
                size));
        text.relocate((getWidth() - w) / 2, (getHeight() - h) / 2);
    }
}

Doing it this way, I get an error saying

Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics@18.0.1/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
    at javafx.graphics@18.0.1/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.IllegalArgumentException: Children: duplicate children added: parent = BorderPane@56dca201

If I were to remove the BorderPane from the class, it'll just show up a white window.

package application.console;

import javafx.scene.Parent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;

public class game {

    public static Parent runGame() {
        
        Console c = new Console();
        AnchorPane anchor = new AnchorPane(c); 
        
        AnchorPane.setTopAnchor(c, 0.0);
        AnchorPane.setRightAnchor(c, 0.0);
        AnchorPane.setBottomAnchor(c, 0.0);
        AnchorPane.setLeftAnchor(c, 0.0);
        
        BorderPane root = new BorderPane();
        root.setCenter(anchor);
        
        return root;
    }
    
}

Reasoning onto why making it a Parent: It allows me to turn it into a scene.(though there could be many different ways to do that) How would I implement full screening to the console and get it to show?

jewelsea
  • 150,031
  • 14
  • 366
  • 406
Providence
  • 59
  • 5

1 Answers1

2

There is a lot of code in your question, most is irrelevant to your issue, so I won’t discuss it here. In particular your problem has nothing to do with scaling.

The error message tells you what you did wrong:

duplicate children added: parent = BorderPane

The code which caused that is this:

this.root = new BorderPane();
// . . .
root.getChildren().addAll(
    console, 
    scroll, 
    inputBar
);
root.setBottom(inputBar);

You added inputBar to the root BorderPane twice.

I don’t advise adding to the children of a border pane directly either. Instead, use the positional setters on the borderPane to set the positions of the children (those setters will internally add the set nodes as children). Study the BorderPane documentation.

jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • I understand where you're coming from. Maybe the title is inaccurate to the problem. What I'm getting is adding ```inputBar``` to both ```getChildren()``` and ```setBottom()``` is what's causing the duplicate error issue. So going deeper into this, the ```BorderPane``` is needed within the class just for it to function properly I'm guessing? thus having ```BorderPane``` in the actual ```Parent``` method causing the similar duplicate issue? – Providence Nov 20 '22 at 03:59
  • to add on to this, the console works when it's made as a ```Parent``` method. I'm getting size working for it as a class but the layout is the issue now as it only shows a white screen. – Providence Nov 20 '22 at 04:10
  • 2
    For this issue, there is nothing deeper. You can't add a node to the scene graph more than once. If you try to do so, sometimes the system will detect it and throw an exception, as you have seen in this question, sometimes it will silently remove the node from some place in the scene graph and move it somewhere else. This is documented in the node and [scene javadoc](https://openjfx.io/javadoc/19/javafx.graphics/javafx/scene/package-summary.html). – jewelsea Nov 20 '22 at 07:48
  • With regards to the remainder of your code in the question, as I noted, there is a lot of it and I won't discuss it here at this time, I just don't think I would be able to assist with it easily and stackoverflow isn't really setup for that. If you have further queries, my advice is that you can always ask new questions, if you do so, please keep them focused to a single specific question with a good title and provide a [mcve], which is minimal and replicates any issue via copy and paste (no addition). Doing so will allow you to get more higher quality answers. – jewelsea Nov 20 '22 at 07:51