I have Label on my fxml file:
<children>
<Label fx:id="lblTest" text="Label" />
</children>
How can i change the text from "Label" to "Hello" from the main/controller java file?
I just started to learn the basics of JavaFX and i am not sure if it possible
Problem
You want to set the text on a label that is part of FXML/Controller/MainApp
Solution
Normally you have three files:
FXML-Document
FXML-Controller
Class that extends Application and overrides the start method
A little Example:
LabelText.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class LabelText extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
FXMLDocument.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40" fx:controller="labeltext.FXMLDocumentController">
<children>
<Label fx:id="lblTest" layoutX="126.0" layoutY="92.0" minHeight="16" minWidth="69" />
</children>
</AnchorPane>
FXMLDocumentController.java
package labeltext;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class FXMLDocumentController {
#FXML
private Label lblTest;
#FXML
private void initialize() {
lblTest.setText("I'm a Label.");
}
}
And that's it.
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Label lblData = (Label) root.lookup("#lblTest");
if (lblData!=null) lblData.setText("bye");
Related
I made a custom control CustomControl in JavaFX.
The CustomControl is basically just a button and a text field. It is made of a CustomControl.fxml and a controller CustomControl.java.
I also have a view TestView.fxml which includes the CustomControl with a controller TestController.java. The TestView.fxml has a button. When that button is pressed it calls the method 'OnButtonPress' from the TestController.java. Now in that method I would like to call the method setText from the controller CustomControl.java.
Now I'm facing two problems.
First: I'm getting the exception 'Root hasn't been set. Use method setRoot() before load.'
Second: I don't know how to call the method setText from my custom control.
Here's the code:
TestView.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:controller="controller.TestController" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1">
<children>
<fx:include source="../custom_control.fxml" fx:id="custom_control"/>
<Button onAction="#OnButtonPress" fx:id="button" layoutX="148.0" layoutY="117.0" mnemonicParsing="false" text="Button" />
</children>
</AnchorPane>
TestController.java:
package controller;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
public class TestController {
#FXML
private Button button;
#FXML
private VBox custom_control;
public TestController() {
}
#FXML
private void OnButtonPress() {
// that is the method I would like to call
custom_control.setText("This is the new text");
}
}
CustomControl.java:
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
public class CustomControl extends VBox {
#FXML private TextField textField;
public CustomControl() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("custom_control.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public void setText(String text){
textField.textProperty().set(text);
}
#FXML
protected void doSomething() {
textField.textProperty().set("The button was clicked");
}
}
CustomControl.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root type="javafx.scene.layout.VBox" xmlns:fx="http://javafx.com/fxml">
<TextField fx:id="textField"/>
<Button text="Click Me" onAction="#doSomething"/>
</fx:root>
Okey so I figured out why I didn't work so I though I'd share what problems I had.
the name's of the packages have to start with a lower case letter not upper case
The names of the Classes as well as the views (FXML files) have to start with a upper case letter.
instead of <fx:include> you should use the actual tag of the control (in my case <CustomControl>) and import the FXML file
When doing all that it finally worked.
Currently, I'm making a client-side anime streamer, and currently learning JavaFX. I've created a static thumbnail, and I need to change the value of the static content. So, how do you change the value of a text element already defined in a .fxml file in JavaFX?
For reference, here's the code.
videoThumbnail.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<AnchorPane prefHeight="387.0" prefWidth="243.0" style="-fx-background-color: #000000;" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="test.gui.Controller">
<children>
<ImageView fitHeight="266.0" fitWidth="184.0" layoutX="36.0" layoutY="26.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../images/mL0215_1024x1024.png" />
</image>
</ImageView>
<Label layoutX="36.0" layoutY="308.0" style="-fx-background-color: #000000;" text="My Hero Acadamia" textFill="WHITE">
<font>
<Font name="System Bold" size="17.0" />
</font>
</Label>
</children>
</AnchorPane>
main.java
#Override
public void start(Stage primaryStage) throws Exception {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/videoThumbnail.fxml"));
Pane root = (Pane) loader.load();
Scene scene = new Scene(new Group(root));
primaryStage.setTitle("test");
primaryStage.setScene(scene);
primaryStage.show();
letterbox(scene, root);
primaryStage.setFullScreen(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
Controller.java
package test.gui;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
public class Controller {
}
First you need to assign an id attribute to the relevant tag. For example, if you wanted to reference the AnchorPane in the above FXML file, you would use this:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<AnchorPane fx:id="anchorPane" prefHeight="387.0" prefWidth="243.0" style="-fx-background-color: #000000;" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="test.gui.Controller">
...
</AnchorPane>
Note the addition of fx:id="anchorPane". That is the id attribute.
Now, you can reference it from the Controller by using the id as the variable name. Just add the AnchorPane as an instance variable using the #FXML annotation.
package test.gui;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
public class Controller {
#FXML
private AnchorPane anchorPane;
/*Rest of class*/
}
You can do this with any object in the FXML file, including the Labels. Just remember to add the id attribute.
Well, my question is simple.
I am building an application with Java Fx, and I have a TabPane.
When I open a new Tab, that Tab gets it's content by a fxml file.
tab.setContent((Node)FXMLLoader.load(this.getClass().getResource("/main/textEditor.fxml")))
Fine, that works well, it always loads the same file on all Tabs, so, all textarea on all tabs have the same id.
The problem is, with java, I can only get the information of the textarea of the first Tab.
How can i edit specifically the textarea of one tab in particular?
An example of what i want to do :
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class Main extends Application{
public static void main(String[] args) {
Application.launch(Main.class, args);
}
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/tabPane/test.fxml"));
Screen screen = Screen.getPrimary();
Rectangle2D bounds = screen.getVisualBounds();
stage.setScene(new Scene(root));
stage.show();
}
}
test.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.AnchorPane?>
<VBox prefHeight="400.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="tabPane.controller">
<children>
<MenuBar VBox.vgrow="NEVER">
<menus>
<Menu mnemonicParsing="false" onAction="#test" text="File">
<items>
<MenuItem fx:id="insert" mnemonicParsing="false" onAction="#test" text="Insert" />
</items>
</Menu>
</menus>
</MenuBar>
<AnchorPane maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
<children>
<Label alignment="CENTER" layoutX="155.0" layoutY="177.0" style="
" text="Drag components from Library hereā¦" textAlignment="CENTER" textFill="#9f9f9f" wrapText="false">
<font>
<Font size="18.0" />
</font>
</Label>
<TabPane fx:id="tabPane" prefHeight="375.0" prefWidth="640.0" tabClosingPolicy="UNAVAILABLE">
<tabs>
<Tab text="Untitled Tab 1">
<content>
<TextArea fx:id="textarea" prefHeight="200.0" prefWidth="200.0" text="a" />
</content>
</Tab>
<Tab text="Untitled Tab 2">
<content>
<TextArea fx:id="textarea1" prefHeight="200.0" prefWidth="200.0" text="a" />
</content>
</Tab>
</tabs>
</TabPane>
</children>
</AnchorPane>
</children>
<stylesheets>
<URL value="#../../../../BasicApplicatio11n_css/BasicApplication.css" />
controller.java
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextArea;
public class controller implements Initializable{
#FXML
private TextArea textarea;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
}
public void test(ActionEvent event){
textarea.appendText("Text");
}
}
There are two tabs on this example, when the button is pressed, I want to add the text on the current selected tab.
There are a few different ways to do this. One way is to let the controller for the tab content expose the textProperty from the text area. Then in your "main controller", create a StringProperty field. When you create a new tab, just observe its selected property and update the string property field to point to the one from the current controller. Then you can easily load text into the "current" pane.
Here's a simple example of this:
EditorController:
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
public class EditorController {
#FXML
private TextArea textArea ;
public StringProperty textProperty() {
return textArea.textProperty() ;
}
}
with textEditor.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.TextArea?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="EditorController">
<center>
<TextArea fx:id="textArea"/>
</center>
</BorderPane>
And then the MainController could look like:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.stage.FileChooser;
public class MainController {
#FXML
private TabPane tabPane ;
private StringProperty currentText ;
public void initialize() throws IOException {
// load an initial tab:
newTab();
}
#FXML
private void newTab() throws IOException {
Tab tab = new Tab("Untitled text");
FXMLLoader loader = new FXMLLoader(getClass().getResource("textEditor.fxml"));
tab.setContent(loader.load());
EditorController controller = loader.getController() ;
tab.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
currentText = controller.textProperty();
}
});
tabPane.getTabs().add(tab);
tabPane.getSelectionModel().select(tab);
}
#FXML
private void load() {
FileChooser chooser = new FileChooser();
File file = chooser.showOpenDialog(tabPane.getScene().getWindow());
if (file != null) {
Path path = file.toPath();
try {
currentText.set(String.join("\n", Files.readAllLines(path)));
} catch (IOException e) {
Alert alert = new Alert(AlertType.ERROR);
alert.setContentText("Unable to load file "+path);
alert.setTitle("Load error");
alert.showAndWait();
}
tabPane.getSelectionModel().getSelectedItem().setText(path.getFileName().toString());
}
}
}
with main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="MainController">
<center>
<TabPane fx:id="tabPane"/>
</center>
<bottom>
<HBox alignment="CENTER" spacing="5">
<padding>
<Insets top="5" right="5" left="5" bottom="5" />
</padding>
<Button text="Load..." onAction="#load" />
<Button text="New" onAction="#newTab"/>
</HBox>
</bottom>
</BorderPane>
For completeness, a simple application class:
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("main.fxml"));
Scene scene = new Scene(root, 800, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
There are other approaches, e.g. you could just change the button's onAction property when the tab selection changes, etc.
I am learning to write FXML custom components for use with JavaFX 8 and Scene Builder.
I wrote the FXML file shown below but Scene Builder will not open it, giving me the message "Open operation has failed" due to the exception:
java.io.IOException: javafx.fxml.LoadException: mycustomcomponent.TicoTeco is not a valid type.
/C:/Users/xxxxx/Documents/NetBeansProjects/MyCustomComponent/src/mycustomcomponent/TicoTeco.fxml:9
at com.oracle.javafx.scenebuilder.kit.fxom.FXOMLoader.load(FXOMLoader.java:92)
at com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument.(FXOMDocument.java:80)
at com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument.(FXOMDocument.java:95)
...
Why am I getting this exception?
Here's the FXML file:
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root type="mycustomcomponent.TicoTeco" prefHeight="93.0" prefWidth="304.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<BorderPane layoutX="61.0" prefHeight="115.0" prefWidth="200.0">
<left>
<Button fx:id="tico" mnemonicParsing="false" text="Tico" BorderPane.alignment="CENTER" />
</left>
<right>
<Button fx:id="teco" mnemonicParsing="false" text="Teco" BorderPane.alignment="CENTER" />
</right>
</BorderPane>
</children>
</fx:root>
And here are the Java files for TicoTeco.java and Main.java:
package mycustomcomponent;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
public class TicoTeco extends AnchorPane {
#FXML
Button tico;
#FXML
Button teco;
public TicoTeco() throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(TicoTeco.class.getResource("TicoTeco.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
fxmlLoader.load();
}
#FXML
public void initialize() {
final EventHandler<ActionEvent> onAction =
event -> System.out.println("Hi, I'm " + (event.getSource() == tico? "Tico" : "Teco") + "!");
tico.setOnAction(onAction);
teco.setOnAction(onAction);
}
}
package mycustomcomponent;
import java.io.IOException;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
Scene scene = new Scene(new TicoTeco());
primaryStage.setTitle("Here are Tico and Teco!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
It's a bit tricky. So your fxml have a little mistake:
Your custom class is extending AnchorPane, so this should be the root in your fxml:
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root type="AnchorPane" prefHeight="93.0" prefWidth="304.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<BorderPane layoutX="61.0" prefHeight="115.0" prefWidth="200.0">
<left>
<Button fx:id="tico" mnemonicParsing="false" text="Tico" BorderPane.alignment="CENTER" />
</left>
<right>
<Button fx:id="teco" mnemonicParsing="false" text="Teco" BorderPane.alignment="CENTER" />
</right>
</BorderPane>
</children>
</fx:root>
After that, you have to make a jar of it, because you have a fxml and a java class. This is the tricky part in Netbeans, so follow up:
First: Create an own Library Project for the component that looks like this with your copied source files:
Second: Delete the copied Main (where the main method is in) file
Third: Do a "Clean and Build" at the project. The generated .jar file will be in the subfolder "dist" in your Project directory.
Fourth: Open Scene Builder and import your CustomComponent .jar file like this:
Now you are able to use the component as you want. But be aware of changes to the component are not dynamicaly refresh the imported jar, you have to do the whole thing again.
I have this controller:
package cz.vutbr.feec.bmds.cv2;
import java.awt.Button;
import java.awt.TextField;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Slider;
public class TestGuiController {
private int buttonPressed = 0;
#FXML
private Button tlacitko;
#FXML
private TextField textovePole;
#FXML
private Slider slider;
public void buttonPressed(ActionEvent e) {
buttonPressed++;
textovePole.setText(Integer.toString(buttonPressed));
}
}
this fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>
<AnchorPane prefHeight="200.0" prefWidth="200.0" xmlns:fx="http://javafx.com/fxml" fx:controller="cz.vutbr.feec.bmds.cv2.TestGuiController">
<children>
<Button fx:id="tlacitko" layoutX="30.0" layoutY="40.0" mnemonicParsing="false" onTouchPressed="#buttonPressed" text="Button" />
<Slider fx:id="slider" layoutX="157.0" layoutY="17.0" orientation="VERTICAL" />
<TextField fx:id="textovePole" layoutX="14.0" layoutY="89.0" prefWidth="134.0" />
</children>
</AnchorPane>
and this is my main class:
package cz.vutbr.feec.bmds.cv2;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("TestGui.fxml"));
primaryStage.setTitle("Titulek");
primaryStage.setScene(new Scene(root,300,275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
When I run this through ant I get message box with error (exception during running application). I tried simple fxml without controller and it works so I am guesing I do something wrong with controller. What I must change to have it working?
I must answer my own question. Problem was in TestGuiController where I used java.awt.Button and java.awt.TextField instead of javafx.scene.control.Button and javafx.scene.control.TextField.
I'm not 100% sure but try:
in FXML: Button: onAction instead of onTouchPressed
Please provide the exact Exception message.