Changing Label text JavaFX FXML - java

There is my main class:
public class Main extends Application {
private static Stage primaryStage;
public static BorderPane mainLayout;
#Override
public void start(Stage primaryStage) {
this.setPrimaryStage(primaryStage);
primaryStage.setTitle("Project");
try {
mainLayout =
FXMLLoader.load(Main.class.getResource("/main/view/MainPage.fxml"));
} catch (IOException e) {
e.printStackTrace();
}
Scene scene = new Scene(mainLayout);
primaryStage.setScene(scene);
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
System.exit(0);
}
});
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public static Stage getPrimaryStage() {
return primaryStage;
}
public void setPrimaryStage(Stage primaryStage) {
Main.primaryStage = primaryStage;
}
}
This FXML of my window:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<BorderPane prefHeight="410.0" prefWidth="512.0"
xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="main.controller.MainController">
<center>
<VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0"
spacing="20.0" BorderPane.alignment="CENTER">
<children>
<Label fx:id="aaa" prefHeight="72.0" prefWidth="336.0"
text="Project" textAlignment="CENTER">
<font>
<Font name="Century Gothic" size="25.0" />
</font>
</Label>
</children>
<padding>
<Insets bottom="30.0" />
</padding>
</VBox>
</center>
</BorderPane>
This is Controller for this FXML:
public class MainController {
#FXML
private static Label aaa;
#FXML
public static void initialize(){
aaa.setText("AHOJ");
}
}
I want to call method initialize() from another class ten times like this:
public class MyClass {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MainController.initialize();
}
}
}
But there is NullPointerException. Can someone help me?

Just remove statics for field and method, then run your application by main() in Main class:
public class MainController {
#FXML
private Label aaa;
#FXML
public void initialize(){
aaa.setText("AHOJ");
}
}

Related

Image is clickable but invisible in javafx

I need to load and display some images at runtime in javafx, I managed to load one of them up, I create the ImageView passing that image as param but then the image doesn't show up. I discovered that the image is clickable (it recognizes on mouse events) but I can't display it
The controller
public class fx extends Application {
#FXML
// The reference of inputText will be injected by the FXML loader
private TextField inputUsername;
#FXML
private TextField inputUrl;
#FXML
private ComboBox inputConnectionType;
#FXML
private ComboBox inputColour;
#FXML
private Button submit;
#FXML
private ImageView imageView;
#FXML
private AnchorPane anchor;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Image image = new Image("/AD_weapons_IT_0211.png");
imageView = new ImageView(image);
Parent root = FXMLLoader.load(getClass().getResource("/fxml/form.fxml"));
Scene scene = new Scene(root);
stage.setWidth(415);
stage.setHeight(200);
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
public void submit()
{
System.out.println(inputUsername.getText()+"\n");
System.out.println(inputColour.getValue().toString()+"\n");
System.out.println(inputConnectionType.getValue().toString()+"\n");
System.out.println(inputUrl.getText()+"\n");
}
public void press()
{
System.out.println("CLICKED");
}
}
The fxml file
<?xml version="1.0" encoding="UTF-8"?>
<?language JavaScript?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.image.Image?>
<TitledPane animated="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" text="untitled" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.172-ea" fx:controller="provaProj.fx">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<ImageView fx:id = "imageView" fitHeight="150.0" fitWidth="200.0" layoutX="199.0" layoutY="112.0" onMousePressed="#press" pickOnBounds="true" preserveRatio="false" />
</children></AnchorPane>
</content>
</TitledPane>
You should have 2 Classes and 1 fxml file for an FXML-Application:
Main Class:
public class TestApplication extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLTest.fxml"));
stage.setTitle("Application");
Scene scene = new Scene(root);
stage.setWidth(415);
stage.setHeight(200);
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
your fxml-File
and a Controller-Class:
public class Controller {
#FXML
// The reference of inputText will be injected by the FXML loader
private TextField inputUsername;
#FXML
private TextField inputUrl;
#FXML
private ComboBox inputConnectionType;
#FXML
private ComboBox inputColour;
#FXML
private Button submit;
#FXML
private ImageView imageView;
#FXML
private AnchorPane anchor;
public void submit()
{
System.out.println(inputUsername.getText()+"\n");
System.out.println(inputColour.getValue().toString()+"\n");
System.out.println(inputConnectionType.getValue().toString()+"\n");
System.out.println(inputUrl.getText()+"\n");
}
#FXML
public void press()
{
System.out.println("CLICKED");
Image img = new Image("yourURL");
imageView.setImage(img);
}
}
and you can then change your image in the Controller-Class..something like I made in the press method.

JavaFXML + Scenebuilder: LineChart is not showing values

I've got a RootStage with some MenuItems and want to set the center of my Rootstage to an AnchorPane with a LineChart in the middle.
The chart got a CategoryAxis on the x-Axis and a NumberAxis on the y-Axis.
But now if I call the Controller for the Scene with the LineChart on it, I can see the LineChart but it has no values. Or at least doesn't show them.
Why is the LineChart not getting filled?
Or why doesn't it show the values?
MainController.class
public class MainController extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
#FXML
private MenuBar menuBar;
#FXML
private Menu menuAnsicht, menuOptionen;
#FXML
private MenuItem menuItemTag, menuItemWoche, menuItemAbout, menuItemCloseWindow;
#Override
public void init() {
}
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
initRootLayout();
}
private void initRootLayout() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/de/mgo/temperaturstatistics/view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
logger.debug("ERROR: " + e.getMessage());
e.printStackTrace();
}
}
#FXML
public void handleTagItem(ActionEvent event) {
try {
BorderPane nowLayout = (BorderPane) menuBar.getScene().getRoot();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/de/mgo/temperaturstatistics/view/DailyScene.fxml"));
nowLayout.setCenter(loader.load());
} catch (Exception e) {
logger.debug("ERROR: " + e.getMessage());
e.printStackTrace();
}
}
DailySceneController.class
public class DailySceneController extends Application {
#FXML
private Label titleDaily;
#FXML
private LineChart<String, Number> dailyChart;
#FXML
private CategoryAxis xDaily;
#FXML
private NumberAxis yDaily;
public int count = 0;
public DailySceneController() {
count++;
System.out.println(count);
}
#Override
public void init() {
this.setChartDaily();
}
#Override
public void start(Stage primaryStage) {
}
public void setChartDaily() {
LocalDate localDate = LocalDate.now().minusDays(0);
List<Temperaturen> listeNodemcu_JHL = MainController.getListeNodemcu_JHL();
this.xDaily.setAutoRanging(false);
this.yDaily.setAutoRanging(false);
this.dailyChart.setAnimated(false);
XYChart.Series<String, Number> seriesJHL = new XYChart.Series<String, Number>();
seriesJHL.setName("Nodemcu_JHL");
seriesJHL.getData().add(new XYChart.Data<String, Number>("Test", 15));
this.dailyChart.getData().add(seriesJHL);
}
}
DailyScene.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?package de.mgo.temperaturstatistics.controller.Controller?>
<?import javafx.scene.chart.CategoryAxis?>
<?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.text.Font?>
<BorderPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.mgo.temperaturstatistics.view.DailySceneController">
<top>
<Label fx:id="titleDaily" text="Temperatur-Statistik Tagesansicht" BorderPane.alignment="CENTER">
<font>
<Font name="System Bold" size="18.0" />
</font>
</Label>
</top>
<center>
<LineChart fx:id="dailyChart" prefHeight="300.0" prefWidth="500.0" BorderPane.alignment="CENTER">
<xAxis>
<CategoryAxis fx:id="xDaily" animated="false" label="Uhrzeit" side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis fx:id="yDaily" animated="false" autoRanging="false" label="Temperatur" lowerBound="10.0" side="LEFT" tickLabelGap="1.0" tickUnit="1.0" upperBound="30.0" />
</yAxis>
</LineChart>
</center>
</BorderPane>
You're extending Application with your controller class an expect it's lifecycle methods to be invoked for it. This is bad practice and also does not result in the invocation of the lifecycle methods.
If you want a method to be invoked, use Initializable.initialize or simply a parameterless initialize method:
#FXML
private void initialize() {
this.setChartDaily();
}

Resizable BorderPane w/ Drawer in JavaFX

I am trying to make a resizable BorderPane with Drawer on the Left. I made a transition that shifts the "left AnchorPane" to the outside - but unfortunately the left place-holder for the BorderPane does not resize/ shift/ or collapse. I was hoping it would do one.
Anyways, here are some pics that better describes what is happening. Notice the white space in the first picture. That is the problem.
Drawer In
Drawer Out
Java
import java.io.IOException;
import com.jfoenix.controls.JFXHamburger;
import com.jfoenix.transitions.hamburger.HamburgerBasicCloseTransition;
import javafx.animation.TranslateTransition;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ResizeableBorderPane extends BorderPane {
#FXML
private BorderPane root;
#FXML
private AnchorPane topAnchor;
#FXML
private AnchorPane leftAnchor;
#FXML
private AnchorPane centerAnchor;
#FXML
private AnchorPane rightAnchor;
#FXML
private AnchorPane bottomAnchor;
#FXML
private JFXHamburger hamburger;
private Stage stage;
public ResizeableBorderPane(){
try {
FXMLLoader loader = new FXMLLoader(getClass()
.getResource("/application/prototypes/custom/resizableborderpane/ResizableBorderPaneView.fxml"));
loader.setController(this);
loader.setRoot(this);
loader.load();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
root.setPrefWidth(1000);
root.setPrefHeight(800);
setStage();
}
#FXML
public void initialize() {
leftAnchor.setPrefWidth(200);
topAnchor.setPrefHeight(50);
bottomAnchor.setPrefHeight(50);
final TranslateTransition translateLeftAnchor =
new TranslateTransition(Duration.millis(1000), leftAnchor);
translateLeftAnchor.setFromX(50);
translateLeftAnchor.setToX(-200 + 50);
translateLeftAnchor.play();
HamburgerBasicCloseTransition burgerTask = new HamburgerBasicCloseTransition(hamburger);
burgerTask.setRate(-1);
hamburger.addEventHandler(MouseEvent.MOUSE_PRESSED,(e)->{
if (burgerTask.getRate() == -1){
burgerTask.setRate(burgerTask.getRate()*-1);
burgerTask.play();
translateLeftAnchor.setFromX(-200 + 50);
translateLeftAnchor.setToX(0);
translateLeftAnchor.play();
} else {
burgerTask.setRate(burgerTask.getRate()*-1);
burgerTask.play();
translateLeftAnchor.setFromX(0);
translateLeftAnchor.setToX(-200 + 50);
translateLeftAnchor.play();
}
});
translateLeftAnchor.currentTimeProperty().addListener( e -> {
System.out.println("Layout X: " + leftAnchor.getTranslateX());
});
}
// =========== GETTERS AND SETTERS ===========
public Stage getStage(){
return (Stage) root.getScene().getWindow();
}
public void setStage(){
try{
this.stage = (Stage) root.getScene().getWindow();
} catch (NullPointerException n){
System.out.println("The stage is null!");
}
}
public BorderPane getRoot() {
return root;
}
public void setRoot(BorderPane root) {
this.root = root;
}
public AnchorPane getTopAnchor() {
return topAnchor;
}
public void setTopAnchor(AnchorPane topAnchor) {
this.topAnchor = topAnchor;
}
public AnchorPane getLeftAnchor() {
return leftAnchor;
}
public void setLeftAnchor(AnchorPane leftAnchor) {
this.leftAnchor = leftAnchor;
}
public AnchorPane getCenterAnchor() {
return centerAnchor;
}
public void setCenterAnchor(AnchorPane centerAnchor) {
this.centerAnchor = centerAnchor;
}
public AnchorPane getRightAnchor() {
return rightAnchor;
}
public void setRightAnchor(AnchorPane rightAnchor) {
this.rightAnchor = rightAnchor;
}
public AnchorPane getBottomAnchor() {
return bottomAnchor;
}
public void setBottomAnchor(AnchorPane bottomAnchor) {
this.bottomAnchor = bottomAnchor;
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXHamburger?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<fx:root fx:id="root" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" type="BorderPane" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
<top>
<AnchorPane fx:id="topAnchor" maxWidth="1.7976931348623157E308" style="-fx-background-color: #999999;" BorderPane.alignment="CENTER">
<children>
<JFXHamburger fx:id="hamburger" alignment="CENTER_LEFT" AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="5.0" />
</children></AnchorPane>
</top>
<left>
<AnchorPane fx:id="leftAnchor" maxHeight="1.7976931348623157E308" style="-fx-background-color: #FF0000;" BorderPane.alignment="CENTER" />
</left>
<center>
<AnchorPane fx:id="centerAnchor" focusTraversable="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="200.0" minWidth="200.0" style="-fx-background-color: #454545;" BorderPane.alignment="CENTER_LEFT" />
</center>
<right>
<AnchorPane fx:id="rightAnchor" maxHeight="1.7976931348623157E308" style="-fx-background-color: #00FF00;" BorderPane.alignment="CENTER" />
</right>
<bottom>
<AnchorPane fx:id="bottomAnchor" maxWidth="1.7976931348623157E308" style="-fx-background-color: #0000FF;" BorderPane.alignment="CENTER" />
</bottom>
</fx:root>
Any suggestions on how to fix the white space please? I am a little stuck.
UPDATE
I have it almost working by adding this line in the time property listener:
translateLeftAnchor.currentTimeProperty().addListener( e -> {
setMargin(leftAnchor, new Insets(0, leftAnchor.translateXProperty().doubleValue(), 0, 0));
});
However, when the drawer goes in - it moves a little faster than the "center" expands; thus, one can see a white line in between.
UPDATE 2
Used the translate property listener and it works fine
leftAnchor.translateXProperty().addListener( e -> {
setMargin(leftAnchor, new Insets(0, leftAnchor.translateXProperty().doubleValue(), 0, 0));
});
The solution above seems to work great for me. Enhance it as you wish. Here is my working example.
Java
package application.prototypes.custom.resizableborderpane;
import java.io.IOException;
import com.jfoenix.controls.JFXHamburger;
import com.jfoenix.transitions.hamburger.HamburgerBasicCloseTransition;
import javafx.animation.TranslateTransition;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ResizeableBorderPane extends BorderPane {
#FXML
private BorderPane root;
#FXML
private AnchorPane topAnchor;
#FXML
private AnchorPane leftAnchor;
#FXML
private AnchorPane centerAnchor;
#FXML
private AnchorPane rightAnchor;
#FXML
private AnchorPane bottomAnchor;
#FXML
private JFXHamburger hamburger;
private Stage stage;
public ResizeableBorderPane(){
try {
FXMLLoader loader = new FXMLLoader(getClass()
.getResource("/application/prototypes/custom/resizableborderpane/ResizableBorderPaneView.fxml"));
loader.setController(this);
loader.setRoot(this);
loader.load();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
root.setPrefWidth(1000);
root.setPrefHeight(600);
}
#FXML
public void initialize() {
leftAnchor.setPrefWidth(200);
leftAnchor.setTranslateX(-150);
setMargin(leftAnchor, new Insets(0, leftAnchor.translateXProperty().doubleValue(), 0, 0));
topAnchor.setPrefHeight(50);
bottomAnchor.setPrefHeight(50);
rightAnchor.setPrefWidth(50);
final TranslateTransition translateLeftAnchor =
new TranslateTransition(Duration.millis(500), leftAnchor);
HamburgerBasicCloseTransition burgerTask = new HamburgerBasicCloseTransition(hamburger);
burgerTask.setRate(-1);
hamburger.addEventHandler(MouseEvent.MOUSE_PRESSED,(e)->{
if (burgerTask.getRate() == -1){
burgerTask.setRate(burgerTask.getRate()*-1);
burgerTask.play();
translateLeftAnchor.setFromX(-200 + 50);
translateLeftAnchor.setToX(0);
translateLeftAnchor.play();
} else {
burgerTask.setRate(burgerTask.getRate()*-1);
burgerTask.play();
translateLeftAnchor.setFromX(0);
translateLeftAnchor.setToX(-200 + 50);
translateLeftAnchor.play();
}
});
leftAnchor.translateXProperty().addListener( e -> {
setMargin(leftAnchor, new Insets(0, leftAnchor.translateXProperty().doubleValue(), 0, 0));
});
}
// =========== GETTERS AND SETTERS ===========
public Stage getStage(){
return (Stage) root.getScene().getWindow();
}
public BorderPane getRoot() {
return root;
}
public AnchorPane getTopAnchor() {
return topAnchor;
}
public AnchorPane getLeftAnchor() {
return leftAnchor;
}
public AnchorPane getCenterAnchor() {
return centerAnchor;
}
public AnchorPane getRightAnchor() {
return rightAnchor;
}
public AnchorPane getBottomAnchor() {
return bottomAnchor;
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXHamburger?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<fx:root fx:id="root" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" type="BorderPane" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
<top>
<AnchorPane fx:id="topAnchor" maxWidth="1.7976931348623157E308" style="-fx-background-color: #999999;" BorderPane.alignment="CENTER">
<children>
<JFXHamburger fx:id="hamburger" alignment="CENTER_LEFT" AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="5.0" />
</children></AnchorPane>
</top>
<left>
<AnchorPane fx:id="leftAnchor" maxHeight="1.7976931348623157E308" style="-fx-background-color: #FF0000;" BorderPane.alignment="CENTER_LEFT" />
</left>
<center>
<AnchorPane fx:id="centerAnchor" focusTraversable="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="200.0" minWidth="200.0" style="-fx-background-color: #454545;" BorderPane.alignment="CENTER_LEFT" />
</center>
<right>
<AnchorPane fx:id="rightAnchor" maxHeight="1.7976931348623157E308" style="-fx-background-color: #00FF00;" BorderPane.alignment="CENTER" />
</right>
<bottom>
<AnchorPane fx:id="bottomAnchor" maxWidth="1.7976931348623157E308" style="-fx-background-color: #0000FF;" BorderPane.alignment="CENTER" />
</bottom>
</fx:root>

FXML StackPane doesn't align children correctly

I want a Rectangle and a Label to align in the StackPane, however my code doesn't achieve the desired result:
FXML:
<fx:root type="HBox" xmlns:fx="http://javafx.com/fxml">
<StackPane fx:id="pane">
<children>
<Rectangle fx:id="bubble" fill="#ffffff"></Rectangle>
<Label fx:id="message" style="-fx-border-color:black; -fx-border-width: 1; -fx-border-style: solid;"></Label>
</children>
</StackPane>
</fx:root>
Controller:
public class MessageBubble extends HBox implements Initializable {
#FXML
private StackPane pane;
#FXML
private Label message;
#FXML
private Rectangle bubble;
#Override
public void initialize(URL location, ResourceBundle resources) {
message.setText("message");
pane.setAlignment(Pos.CENTER);
bubble.setArcWidth(15.0);
bubble.setArcHeight(15.0);
bubble.setStroke(Color.BLACK);
message.widthProperty().add(10.0).addListener((observable, oldValue, newValue) -> {
bubble.setWidth(newValue.doubleValue());
pane.layout();
});
message.heightProperty().add(10.0).addListener((observable, oldValue, newValue) -> {
bubble.setHeight(newValue.doubleValue());
pane.layout();
});
}
public MessageBubble() {
FXMLLoader loader = new FXMLLoader(this.getClass().getResource("MessageBubble.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Update
If I do sizing programmatically, it aligns fine:
this.pane.getChildren().addAll(this.bubble, this.message);
bubble.setFill(Color.ALICEBLUE);
bubble.setArcWidth(15.0);
bubble.setArcHeight(15.0);
bubble.setStroke(Color.BLACK);
message.setStyle("-fx-border-color:black; -fx-border-width: 1; -fx-border-style: solid;");
message.setText("message");
message.setPrefWidth(60.0);
message.setPrefHeight(25.0);
bubble.setWidth(70.0);
bubble.setHeight(30.0);
But this way, I need to calculate the size myself.
Basically, if you need a Text or Label with colored backround, the easiest approach to use CSS for a single Label or Text, without any Rectangle objects.
Example to use Label with CSS
Main.java
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
HBox root = new HBox();
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
Label message = new Label();
TextArea textArea = new TextArea();
textArea.setPrefWidth(200);
textArea.setText("message");
message.textProperty().bind(textArea.textProperty());
message.getStyleClass().add("rounded-background-label");
root.getChildren().addAll(message, textArea);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
application.css
.rounded-background-label {
-fx-background-color: black, white;
-fx-background-insets: 0, 1;
-fx-padding: 10px;
-fx-background-radius: 12px;
}
The answer from #jewelsea on this question is really detailed:
JavaFX 2: resizable rectangle containing text
But if you want to stay with the Label+Rectangle solution
I fear it is related to this bug: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8137252
As workaround you can request the layout update of the StackPane, as you have tried in the listeners.
The only problem with your code is that you should replace:
pane.layout();
with
Platform.runLater(new Runnable() {
#Override
public void run() {
pane.requestLayout();
}
});
which will ensure that the layout will happen on the GUI Thread.
Example
LabelRectangleTest.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.*?>
<HBox prefHeight="100.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.LabelRectangleTestController">
<children>
<HBox prefHeight="100.0" prefWidth="200.0">
<children>
<StackPane fx:id="pane" minHeight="126.0" prefHeight="126.0" prefWidth="200.0" HBox.hgrow="ALWAYS">
<children>
<Rectangle fx:id="bubble" arcHeight="15.0" arcWidth="15.0" fill="WHITE" height="27.75" stroke="BLACK" strokeType="INSIDE" width="68.0" />
<Label fx:id="message" text="Label" />
</children>
</StackPane>
<TextArea fx:id="textArea" prefWidth="200.0" wrapText="true" />
</children>
</HBox>
</children>
</HBox>
LabelRectangleTestController.java
public class LabelRectangleTestController implements Initializable {
#FXML
private Label message;
#FXML
private Rectangle bubble;
#FXML
private StackPane pane;
#FXML
private TextArea textArea;
#Override
public void initialize(URL location, ResourceBundle resources) {
textArea.setText("message");
message.textProperty().bind(textArea.textProperty());
message.widthProperty().addListener((observable, oldValue, newValue) -> {
bubble.setWidth(newValue.intValue() + 10);
Platform.runLater(new Runnable() {
#Override
public void run() {
pane.requestLayout();
}
});
});
message.heightProperty().addListener((observable, oldValue, newValue) -> {
bubble.setHeight(newValue.doubleValue() + 10);
Platform.runLater(new Runnable() {
#Override
public void run() {
pane.requestLayout();
}
});
});
}
}
Main.java
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("LabelRectangleTest.fxml"));
HBox root = loader.load();
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}

Different Anchor Results in Scene Builder and Application

I generated the following FXML in Scene Builder. When I preview it in Scene Builder and resize the window the inner split view maintains the spacing between itself and the anchor view. However when I run the FXML in my application it does not. Any ideas? I am using javafx 2.2.51.
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane prefHeight="477.0" prefWidth="515.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="com.nm.haze.LibraryViewController">
<children>
<SplitPane dividerPositions="0.09484536082474226" focusTraversable="true" prefHeight="415.0" prefWidth="487.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="48.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<ListView prefHeight="371.0" prefWidth="425.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</items>
</SplitPane>
</children>
</AnchorPane>
And my controller code:
package com.nm.haze;
import java.net.URL;
import java.util.ResourceBundle;
public class LibraryViewController extends BaseController {
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
}
Main code
private static final String LIBRARY_SELECT = "LibrarySelect";
private static final String LIBRARY_VIEW = "LibraryView";
#Override
public void start(Stage primaryStage) throws IOException {
SceneController sceneController = new SceneController(primaryStage, new SettingsManager());
sceneController.loadScene(LIBRARY_SELECT);
sceneController.loadScene(LIBRARY_VIEW);
if (sceneController.setupNeeded()) {
sceneController.setScreen(LIBRARY_SELECT);
} else {
sceneController.setScreen(LIBRARY_VIEW);
}
Group root = new Group();
root.getChildren().addAll(sceneController);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
SceneController code:
public class SceneController extends StackPane {
Map<String, Node> scenes = new HashMap<>();
Stage stage;
SettingsManager settingsManager;
public SceneController(Stage stage, SettingsManager settingsManager) {
this.stage = stage;
this.settingsManager = settingsManager;
}
public void addScene(String name, Node scene) {
scenes.put(name, scene);
}
public void loadScene(String name) throws IOException {
FXMLLoader myLoader = new FXMLLoader(getClass().getResource(name + ".fxml"));
Parent loadScreen = (Parent)myLoader.load();
((BaseController)myLoader.getController()).setSceneController(this);
addScene(name, loadScreen);
}
public void setScreen(final String name) {
List<Node> children = getChildren();
Node scene = scenes.get(name);
if(scene != null) {
if (children.size() > 0) {
children.remove(0);
}
children.add(0, scene);
} else {
throw new IllegalArgumentException("Scene has not been loaded");
}
}
public Stage getStage() {
return stage;
}
public boolean setupNeeded() {
return settingsManager.setupNeeded();
}
}
Just to be clear about what the issue is, please see the before and after screenshots below. The distance between the ListView and the AnchorPane should stay the same (and does in Scene Builder).
`You just have to fix the minimum and maximum width of the part of the SplitPane, whose width you dont want to change on resizing your window !
Here I have fixed the left part, by setting the minWidth and maxWidth of AnchorPane on the left side. You can do the same for the right side as well, depending on your requirement.
abcFxml.fxml
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane prefHeight="477.0" prefWidth="515.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="bounty.LibraryViewController">
<children>
<SplitPane dividerPositions="0.09484536082474226" focusTraversable="true" prefHeight="415.0" prefWidth="487.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="48.0">
<items>
<AnchorPane minHeight="0.0" minWidth="100.0" prefHeight="160.0" prefWidth="100.0" maxHeight="160.0" maxWidth="100.0" />
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<ListView prefHeight="371.0" prefWidth="425.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</items>
</SplitPane>
</children>
</AnchorPane>
Controller
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class LibraryViewController extends Application
{
#Override
public void start(Stage arg0) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("abcFxml.fxml"));
AnchorPane pane = (AnchorPane) fxmlLoader.load();
Scene scene = new Scene(pane);
arg0.setScene(scene);
arg0.show();
}
public static void main(String args[])
{
launch(args);
}
}
Screenshots
Size1
Size 2
EDIT : As per user updation
The problem you are facing is because of the Group you are using. Group itself is not resizable ! Try to put the StackPane directly to your scene(like I did) or you can use any other container like VBOX / HBOX etc
#Override
public void start(Stage primaryStage) throws IOException {
SceneController sceneController = new SceneController(primaryStage, new SettingsManager());
sceneController.loadScene(LIBRARY_SELECT);
sceneController.loadScene(LIBRARY_VIEW);
if (sceneController.setupNeeded()) {
sceneController.setScreen(LIBRARY_SELECT);
} else {
sceneController.setScreen(LIBRARY_VIEW);
}
primaryStage.setScene(new Scene(sceneController));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}

Categories