I am a complete beginner, messing around with javafx. My first try:
[FXML]
<?import javafx.scene.web.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<AnchorPane fx:controller="sample.Controller" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" >
<children>
<Button fx:id="but0" layoutX="208.0" layoutY="146.0" mnemonicParsing="false" onAction="#Handle" text="Button" />
</children>
</AnchorPane>
And the controller class:
package sample;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class Controller {
#FXML
private Button but0;
#FXML
private void Handle(EventHandler e){
but0.setText("Bla");
}
}
which results in the following error:
Error resolving onAction='#Handle', either the event handler is not in the Namespace or there is an error in the script.
Although my Controller class is clearly set as controller for the parent AnchorPane.
The parameter of the handler method either needs to be a Event or it needs to be absent. The following 2 versions should both work:
#FXML
private void Handle(){
but0.setText("Bla");
}
#FXML
private void Handle(ActionEvent e){
but0.setText("Bla");
}
Your controller needs to implement Initializable, like so: (this is just the NetBeans default FXMLController, I'm assuming you load it with FXMLLoader.load() )
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
public class FXMLDocumentController implements Initializable { // notice this
#FXML
private Button but0;
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked the button!");
}
#Override // and this
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Also, methods should start with a lowercase letter, "handle" instead of "Handle" ;) while the second version works, too, it is not considered good style.
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.
I want to add a method to a button which is defined in my Controller class
in the console is only an error which tells me that it couldn't find the method
here is the code
sample.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" fx:controller="sample.Controller">
<children>
<Button layoutX="126" layoutY="90" text="lololol" onAction="#test" fx:id="button" />
</children>
</AnchorPane>
and the Controller.java
package sample;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import java.awt.event.ActionEvent;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable
{
#Override
public void initialize(URL url, ResourceBundle resourceBundle)
{
}
#FXML
private void test(ActionEvent event)
{
System.out.println("lollolol");
}
}
Replace:
import java.awt.event.ActionEvent;
with:
import javafx.event.ActionEvent;
i am new in JavaFX, and as any newcomer, i am flood with doubts.
So i have to populate an <AnchorPane> with children <Pane> like this FXML code:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<AnchorPane fx:id="anchor" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<!-- Add multiple Panels here-->
</children>
</AnchorPane>
My Controller looks like this:
package sample;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable {
#FXML javafx.scene.layout.AnchorPane anchor;
#FXML javafx.scene.layout.Pane pane;
#Override
public void initialize(URL location, ResourceBundle resources) {
pane.prefHeight(100);
pane.prefWidth(300);
pane.setStyle("-fx-background-color: aqua");
for(int i = 0; i < 3; i++) {
anchor.getChildren().add(pane);
pane.setLayoutY(i*100);
}
}
}
Hope someone can help me... Thank You!!
The solution for it is...
The FXML code:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<AnchorPane fx:id="anchor" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<ScrollPane prefHeight="400.0" prefWidth="300.0">
<content>
<GridPane fx:id="gridPane" prefHeight="410.0" prefWidth="294.0"></GridPane>
</content>
</ScrollPane>
</children>
</AnchorPane>
The Controller Class:
package sample;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable {
#FXML private GridPane gridPane;
private Pane paneContainer;
private Label paneLabel;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
for(int i = 0; i<4; i++) {
paneLabel = new Label();
paneLabel.setText("it is..." + i);
paneContainer = new Pane();
paneContainer.setStyle("-fx-background-color: aqua; -fx-border-style: solid; -fx-border-width: 1px; -fx-border-color:#000; ");
paneContainer.setPrefWidth(200);
paneContainer.setPrefHeight(100);
paneContainer.getChildren().add(paneLabel);
gridPane.add(paneContainer, 0, i);
}
}
}
Use GridPane is the easiest way to do it!
I want to add a method to a button which is defined in my Controller class
in the console is only an error which tells me that it couldn't find the method
here is the code
sample.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" fx:controller="sample.Controller">
<children>
<Button layoutX="126" layoutY="90" text="lololol" onAction="#test" fx:id="button" />
</children>
</AnchorPane>
and the Controller.java
package sample;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import java.awt.event.ActionEvent;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable
{
#Override
public void initialize(URL url, ResourceBundle resourceBundle)
{
}
#FXML
private void test(ActionEvent event)
{
System.out.println("lollolol");
}
}
Replace:
import java.awt.event.ActionEvent;
with:
import javafx.event.ActionEvent;
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.