JavaFx : tab item does not fill the content - javafx

I have a TabPane declared like this :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TabPane?>
<TabPane fx:id="rootNode" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" stylesheets="#dark_theme.css" tabClosingPolicy="UNAVAILABLE" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.AppController" />
And I want to add tabs from my controller. So I do :
jsonConfig.getAvailableChannelIds().forEach( chId -> {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("tab_item.fxml"));
Tab item = fxmlLoader.load();
item.setText(String.format("%d", chId));
rootNode.getTabs().add(item);
}catch (Exception e) {
e.printStackTrace();
}
});
"tab_item.fxml" looks as follows :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.layout.VBox?>
<Tab xmlns:fx="http://www.w3.org/1999/XSL/Transform">
<VBox>
<fx:include source="test.fxml"/>
</VBox>
</Tab>
And finally "test.fxml" :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-background-color: red;" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" />
And here is what I have :
What am I missing to fill the Tab content with the red square ?

Most layout panes, such as VBox, will by default try to size their content to the preferred size, and will make every attempt to keep the sizes within the constraints specified as the minimum and maximum.
I recommend reading the old Oracle layout tutorial. It was written a long time ago (before Java 8), so the code style is a bit out of date, but the layout concepts are all still relevant. Also read the Javadocs for the layout package, and presumably you already read the Javadocs for any layout component you are using (if not, you should always read the docs for the classes you use).
You have
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity"
prefHeight="400.0" prefWidth="600.0"
style="-fx-background-color: red;"
xmlns="http://javafx.com/javafx/19"
xmlns:fx="http://javafx.com/fxml/1" />
which explicitly sets the preferred size to 600x400 pixels, and additionally sets the minimum and maximum sizes to -Infinity, which is the sentinel value Region.USE_PREF_SIZE. Therefore, the VBox will always size the content to 600x400 pixels (as long as there is enough space in the VBoxto do so).
Remove all those settings (I corrected the namespace too, though you don't really need it here):
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane style="-fx-background-color: red;"
xmlns:fx="http://javafx.com/fxml" />
Now the VBox will still attempt to set the content to its preferred size, which by default is computed from its own content. Since the anchor pane is empty, that preferred size will be computed as 0x0. However, since the max size is now unconstrained, you can tell the VBox to let it grow:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.layout.VBox?>
<Tab xmlns:fx="http://javafx.com/fxml/">
<VBox fillWidth="true">
<fx:include source="test.fxml" VBox.vgrow="ALWAYS" />
</VBox>
</Tab>
Now the content defined in test.fxml will fill the VBox. The behavior of a Tab is to let its content fill the entire region of the tab, so the VBox will fill the tab.
Of course, it's not really clear why you are wrapping test.fxml in a VBox in the first place. Since the tab will be filled by its content by default, why not just simplify to
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<Tab xmlns:fx="http://javafx.com/fxml/">
<fx:include source="test.fxml" />
</Tab>
Here is a complete example, with all the unnecessary hard-coded sizes and redundant layout panes removed:
HelloApplication.java:
package org.jamesd.examples.tab;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class HelloApplication extends Application {
#Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
hello-view.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TabPane?>
<TabPane fx:id="rootNode"
tabClosingPolicy="UNAVAILABLE"
xmlns:fx="http://javafx.com/fxml/"
fx:controller="org.jamesd.examples.tab.AppController" />
AppController.java:
package org.jamesd.examples.tab;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
public class AppController {
#FXML
private TabPane rootNode ;
public void initialize() {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("tab_item.fxml"));
Tab item = fxmlLoader.load();
item.setText(String.format("%d", 42));
rootNode.getTabs().add(item);
}catch (Exception e) {
e.printStackTrace();
}
}
}
tab-item.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<Tab xmlns:fx="http://javafx.com/fxml/">
<fx:include source="test.fxml" />
</Tab>
and test.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane style="-fx-background-color: red;"/>

Ok, so I found at least a workaround here -> just wrap fx:include with AnchorsPane and it works :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.layout.AnchorPane?>
<Tab xmlns:fx="http://www.w3.org/1999/XSL/Transform">
<content>
<AnchorPane>
<fx:include source="test.fxml" AnchorPane.topAnchor="0" AnchorPane.rightAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.bottomAnchor="0"/>
</AnchorPane>
</content>
</Tab>

Related

JavaFX: Original layout of GridPane altered after switching scenes using getChildren().setAll()

To summarize, I have various FXML files and various corresponding controllers, and to switch between them I am using the following code:
#FXML
public void openInputPane() throws IOException {
BorderPane inputMenu = FXMLLoader.load(getClass().getResource("inputSection/firstPage/inputEquationMenu.fxml"));
mainBorderPane.getChildren().setAll(inputMenu);
}
My main fxml file is a GridPane and the rest are BorderPanes, and this method of using .getChildren().setAll(anotherPane) works perfectly until I try to return to the main GridPane:
public void goToMainMenu() throws IOException {
URL url = new File("C:\\Users\\Luisa" +
"\\IdeaProjects\\IA\\src\\sample\\mainmenu.fxml").toURI().toURL();
GridPane mainMenu = FXMLLoader.load(url);
successMessageBorderPane.getChildren().setAll(mainMenu);
}
The above code does display the original main menu, but messes up the formatting, attached are pictures of the main menu when I first open the programme and the main menu after returning to it.
after returning to main
main at the start of the programme
My question is, what is messing up the formatting when I go back to the main page, and what do I have to do to fix it?
For more details I'm attaching the fxml file for the main GridPane and the last BorderPane (the one where a button is clicked to return to the main GridPane) and their respective controllers.
mainmenu.fxml
<?import javafx.scene.control.Button?> <?import javafx.scene.control.Label?> <?import javafx.scene.layout.GridPane?> <?import javafx.scene.text.Font?> <?import javafx.scene.layout.HBox?>
<GridPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml"
stylesheets="#resources/styles.css" fx:id="mainBorderPane" prefHeight="400" prefWidth="500" vgap="20"
hgap="20" alignment="CENTER">
<HBox GridPane.columnIndex="0" GridPane.rowIndex="0">
<Label text="Physics Formula Storage">
<font>
<Font size="40"/>
</font>
</Label>
</HBox>
<HBox GridPane.rowIndex="1" spacing="35">
<Button text="Insert Equations" onAction="#openInputPane"/>
<Button text="Use Equations"/>
</HBox>
<HBox GridPane.rowIndex="2" spacing="20"
prefWidth="340">
<Label text="Input new equations along with their properties into the storage system" prefWidth="150"
style= "-fx-font-size: 14"/>
<Label text="Find and use equations already in the storage system" prefWidth="150" style= "-fx-font-size: 14"/>
</HBox>
</GridPane>
Controller
package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import java.io.IOException;
public class Controller {
#FXML
GridPane mainBorderPane;
// switching to the input pane if the button is clicked
#FXML
public void openInputPane() throws IOException {
BorderPane inputMenu = FXMLLoader.load(getClass().getResource("inputSection/firstPage/inputEquationMenu.fxml"));
mainBorderPane.getChildren().setAll(inputMenu);
}
}
successMessageMenu.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Line?>
<?import javafx.scene.text.Font?>
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="sample.inputSection.thirdPage.SuccessMessageController"
prefHeight="400.0" prefWidth="600.0" stylesheets="#../../resources/styles.css"
fx:id="successMessageBorderPane">
<padding>
<Insets top="30" right="50" bottom="30" left="50"/>
</padding>
<top>
<VBox prefHeight="50">
<Label alignment="BOTTOM_LEFT" text="Equation added successfully">
<font>
<Font size="17"/>
</font>
</Label>
<Line startX="50" startY="50" endX="550" endY="50"/>
</VBox>
</top>
<center>
<VBox prefHeight="300" alignment="CENTER">
<Label text="Equation has been added successfully" style="-fx-font-style: italic">
<font>
<Font size="40"/>
</font>
</Label>
</VBox>
</center>
<bottom>
<VBox alignment="BOTTOM_CENTER" prefHeight="50">
<Button text="Return to main menu" fx:id="mainMenuButton"
onAction="#goToMainMenu"/>
</VBox>
</bottom>
</BorderPane>
successMenuController
public class SuccessMessageController {
#FXML
Button mainMenuButton;
#FXML
BorderPane successMessageBorderPane;
public void goToMainMenu() throws IOException {
URL url = new File("C:\\Users\\Luisa" +
"\\IdeaProjects\\IA\\src\\sample\\mainmenu.fxml").toURI().toURL();
GridPane mainMenu = FXMLLoader.load(url);
successMessageBorderPane.getChildren().setAll(mainMenu);
}
}
(it is my first time asking a question, do tell me if I need to add anymore code, thank you!)

Unable to sucessufly create an Gluon project whit Glisten Afterburner on Intelij

I attempted to create a Gluon Mobile application whit the Glisten Afterburner framework on Intelij, however once i create it i cannot even launch it.
If i try to run the program i get the following error:
If i try to use scene builder in any of the fxml files:
My fxml code is the one generated by default:
<?xml version="1.0" encoding="UTF-8"?>
<?import com.gluonhq.charm.glisten.control.Icon?>
<?import com.gluonhq.charm.glisten.mvc.View?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<View fx:id="primary" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="350.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.gluon.attempt.views.PrimaryPresenter">
<center>
<VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0" spacing="15.0" BorderPane.alignment="CENTER">
<children>
<Label fx:id="label" text="%label.text.1" />
<Button mnemonicParsing="false" onAction="#buttonClick" text="%button.text">
<graphic>
<Icon content="LANGUAGE" />
</graphic>
</Button>
</children>
</VBox>
</center>
</View>
StackTrace:
ApplicationCode:
package com.gluon.attempt;
import com.gluon.attempt.views.AppViewManager;
import com.gluonhq.charm.glisten.application.MobileApplication;
import com.gluonhq.charm.glisten.visual.Swatch;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
public class Attempt extends MobileApplication {
#Override
public void init() {
AppViewManager.registerViewsAndDrawer(this);
}
#Override
public void postInit(Scene scene) {
Swatch.BLUE.assignTo(scene);
((Stage) scene.getWindow()).getIcons().add(new Image(Attempt.class.getResourceAsStream("/icon.png")));
}
}

JavaFX: How to refer to another object with the same fxml file?

I have got an FXML file in which there is a custom component declared. This component has some logic that requires a reference to another component declared in the same fxml file. The FXML file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.layout.AnchorPane?>
<BorderPane xmlns:fx="http://javafx.com/fxml" prefWidth="800" prefHeight="400" fx:controller="test.MyController">
<top>
<HBox spacing="10">
<Label text="Test"/>
<TextField fx:id="testField"/>
</HBox>
</top>
<center>
<AnchorPane>
<children>
<VBox fx:id="customBox" visible="false" prefHeight="400" prefWidth="400"
VBox.vgrow="ALWAYS"
initiator="#testField"/>
</children>
</AnchorPane>
</center>
</BorderPane>
So, I need to set the initiator property of customBox. With this, I am getting Caused by: java.lang.IllegalArgumentException: Unable to coerce #testField to class javafx.scene.control.TextField. Any suggestions?
I don't have time to test this, but I think
<KontrollkoderVBox fx:id="customBox" visible="false" prefHeight="400" prefWidth="400"
VBox.vgrow="ALWAYS"
initiator="$testField"/>
will work. See "variable resolution" in the FXML documentation.
You can even do things like binding a StringProperty in KontrolkoderVBox to the TextField's textProperty() by referencing ${testField.text}.
You may set the id of textField (say id="testFieldId" which is different from fx:id) into initiator and do lookup:
// in VBox #customBox
TextField tf = (TextField) getScene().lookup(getInitiator());
where getInitiator() returns String = "#testFieldId".

JavaFX 2.2 How to enable SplitPane Vertical Orientation divider position

I have a SplitPane with two items: progress bar (top pane) and action buttons (e.g., ok/cancel) as the bottom pane.
When the page is load, both panes are displayed.
During initial load, I want to have the top pane hidden and the bottom pane displayed.
The top pane will be display when an action event occurs via button click.
How should I modify the code to be able to execute the described scenario
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import com.ngc.gs.dialogs.widgets.*?>
<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<AnchorPane fx:id="progressMainAnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="390.0002999999924" prefWidth="398.9998779296875" xmlns:fx="http://javafx.com/fxml" fx:controller="com.ngc.gs.dialogs.widgetexample.MyCheckBoxSelController">
<TreeView fx:id="localTreeView" prefHeight="181.0" prefWidth="363.0" AnchorPane.leftAnchor="15.0" AnchorPane.rightAnchor="21.0" AnchorPane.topAnchor="14.0" />
<SplitPane fx:id="progressSplitPane" focusTraversable="true" maxWidth="1.7976931348623157E308" orientation="VERTICAL" prefHeight="181.0" prefWidth="362.999755859375" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="15.0" AnchorPane.rightAnchor="21.0" AnchorPane.topAnchor="195.0">
<items>
<ProgressBarMessageConsoleWidget id="pBarConsoleWidget" fx:id="pBarConsoleWidget" minHeight="150.0" minWidth="0.0" prefHeight="150.0" prefWidth="361.0" />
<OkCancelButtonsWidget id="actionButtonsWidget" fx:id="actionButtonsWidget" minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0" />
</items>
</SplitPane>
<stylesheets>
<URL value="#../styles/dialogs.css" />
</stylesheets>
</AnchorPane>
Controller class snippet that sets the splitPane divider:
....
progressSplitPane.setDividerPosition(0, 0.0);
progressSplitPane.setResizableWithParent(progressMainAnchorPane, true);
actionButtonsWidget.getOkBtn().setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent evnt) {
// Show progress bar and message console
progressSplitPane.setDividerPosition(0, 0.75);
pBarConsoleWidget.showProgressConsole();
processCheckBoxSelections();
}
});
...
I resolved this by implementing a GridPane instead and adding listener to the property as described here...
JavaFX HBox hide item

javaFX: styleClass is not working in jar file

It's working fine while I am running the application directly from eclipse. but after building the application using ant, generated jar file it's not working.
However if I removed Styleclass="theme" from fxml it's working fine using jar file as well
Java File
public class MainClass extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().
getResource("/resources/fxmlDocument/Sample.fxml"));
stage.setTitle("SAMPLE");
Scene scene= new Scene(root);
scene.getStylesheets().add(getClass().getClassLoader().
getResource("resources/css/sample.css").toExternalForm());
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
}
Fxml File:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.collections.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" styleClass="theme" xmlns:fx="http://javafx.com/fxml" fx:controller="com.integra.test.MainClassController">
<children>
<Label layoutX="300.0" layoutY="184.0" text="Great..!" />
<Button fx:id="clickbutton" layoutX="207.0" layoutY="184.0" mnemonicParsing="false" text="clickme" />
<TextField fx:id="text1" layoutX="207.0" layoutY="220.0" prefWidth="200.0" />
<Button fx:id="closebutton" layoutX="459.0" layoutY="318.0" mnemonicParsing="false" onAction="#closeButtonAction" prefHeight="37.0" prefWidth="75.0" text="Close" />
</children>
</AnchorPane>
You also use this for adding Style sheets to the controls.
control.getStylesheets().add
(MainClass.class.getResource("Sample.css").toExternalForm());
make sure css file in the same package or specify source path.
Second way is to use scene builder and add css using scene builder. You will get tutorial for this.

Resources