Accessing button made in FXML (using scene builder) in Controller class [duplicate] - java

This question already has answers here:
Is #FXML needed for every declaration?
(3 answers)
Closed 4 years ago.
This is part of my fxml code
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.DatePicker?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.Rectangle?>
<?import javafx.scene.text.Font?>
<AnchorPane id="AnchorPane" prefHeight="467.0" prefWidth="1024.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="teacherattendencesystem.FXMLDocumentController">
<children>
<Label fx:id="header" layoutX="217.0" layoutY="14.0" minHeight="16" minWidth="69" text="UOS Teacher Attendance System">
<font>
<Font name="System Bold" size="36.0" />
</font>
</Label>
<Button fx:id="j1" layoutX="22.0" layoutY="166.0" mnemonicParsing="false" onAction="#marked" prefHeight="30.0" prefWidth="141.0" text="Eisha Tir Razia 1">
<font>
<Font name="System Bold" size="14.0" />
</font>
</Button>
This is part of my controller class
import java.net.URL;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
public class FXMLDocumentController implements Initializable {
#FXML
private Label dayHeading;
private Button j1,j2,j3,j4,j5,j6,j7,j8,j9;
private boolean isSelected = false;
List<Button> room = new ArrayList();
#FXML
private void loadButtons(){
j1.setText("Room 1");
}
private String getDay(){
DayOfWeek dayOfWeek = DayOfWeek.from(LocalDate.now());
return (String) dayOfWeek.name();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
dayHeading.setText(getDay());
loadButtons();
}
}
But when I run the code I basically get a null pointer exception i.e j1 has nothing in it. I've been trying to find the reason for it for almost an hour now but I have no idea what I'm doing wrong.
Assign fx:id to component
declare component in controller class
use component
Now, while I am able to manipulate the Label I am unable to manipulate the Button. Why is that?

Just add the #FXML annotation to the button:
#FXML
private Button j1;
Each variable that is injected by the FXML loader must be indicated as such with the annotation.

Related

Cannot resolve method 'setCellValueFactory' in 'TableColumn'

I have no idea why I get this error message:
Cannot resolve method 'setCellValueFactory' in 'TableColumn'
But when I change to this code in initialize with a test variable, the error message get away:
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
javafx.scene.control.TableColumn kol2 = null;
kol2.setCellValueFactory(new PropertyValueFactory<Tabellmodell,String>("name"));
}
Does anyone know what the problem is with my original code?
package com.example.oppgave;
import javax.swing.table.TableColumn;
import com.example.oppgave.Modell.Ansatt;
import com.example.oppgave.Modell.Tabellmodell;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import java.net.URL;
import java.sql.*;
import java.util.ResourceBundle;
public class AnsattController implements Initializable {
#FXML
private Label tilbakemelding;
#FXML
private TextField innputNavn;
#FXML
private TextField innputId;
#FXML
private TableView<Tabellmodell> ansattTabell;
#FXML
private TableColumn kolname;
#FXML
private TableColumn kolid;
ObservableList<Tabellmodell> oblist= FXCollections.observableArrayList();
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
kolname.setCellValueFactory(new PropertyValueFactory<Tabellmodell,String>("name"));
}
private void listAnsatteTabell(){
int c;
try{
Db nyDb= new Db();
Connection tilkobling=nyDb.dbnyTilkobling();
Statement stmt=tilkobling.createStatement();
System.out.println("Connected to the database");
String sql = "SELECT id, navn from ansatt;";
ResultSet rs = stmt.executeQuery(sql);
while(rs.next()){
oblist.add(new Tabellmodell(rs.getString("id"),rs.getString("navn")));
}
ansattTabell.setItems(oblist);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.text.Font?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.oppgave.AnsattController">
<children>
<TextField fx:id="innputNavn" layoutX="61.0" layoutY="110.0" />
<TextField fx:id="innputId" layoutX="61.0" layoutY="156.0" />
<Label layoutX="26.0" layoutY="114.0" text="Navn" />
<Label layoutX="26.0" layoutY="160.0" text="Id" />
<Button fx:id="regAnsatt" layoutX="61.0" layoutY="200.0" mnemonicParsing="false" onAction="#regNyAnsatt" text="Registrer" />
<TableView fx:id="ansattTabell" editable="true" layoutX="306.0" layoutY="89.0" prefHeight="200.0" prefWidth="273.0">
<columns>
<TableColumn prefWidth="75.0" text="ID" fx:id="kolid"/>
<TableColumn prefWidth="191.0" text="Navn" fx:id="kolname"/>
</columns>
</TableView>
<Label fx:id="tilbakemelding" layoutX="26.0" layoutY="72.0" />
<Label layoutX="212.0" layoutY="39.0" text="Ansatt">
<font>
<Font size="27.0" />
</font>
</Label>
</children>
</Pane>
I also seem to get a error message when the #FXML variable and the x:id in the fxml is the same
You are trying to set attribute of null object. I think that may be the case. Test it out and reach out to me if it doesn't work.

How do you change the value of a text element already defined in a .fxml file in JavaFX?

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.

javafx fxml program error(no main method)

i'm fairly new to javafx and fxml. I'm trying to teach myself! However, when I was creating a program for a simple login GUI I came into an issue when I finally tried to run my program. It told me there was no main method in my class and I'm unsure of how to fix it. Any ideas?
My program creates a login screen and when you enter "test" for the username and password it'll take you to another scene.
Here is my Login.java
package com;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
/**
*
* #author Tyler
*/
public class Login extends Application{
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Login.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Login");
stage.show();
}
}
Here is my LoginController.java
package com;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
/**
* FXML Controller class
*
* #author Tyler
*/
public class LoginController implements Initializable {
#FXML
private Label lblMessage;
#FXML
private TextField txtUsername;
#FXML
private PasswordField txtPassword;
#FXML
private void btnLoginAction(ActionEvent event) throws Exception{
if(txtUsername.getText().equals("test") && txtPassword.getText().equals("test")){
((Node) (event.getSource())).getScene().getWindow().hide();
Parent parent = FXMLLoader.load(getClass().getResource("DateSelection.fxml"));
Stage stage = new Stage();
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.setTitle("Date Selection");
stage.show();
}else{
lblMessage.setText("Username or Password is invalid!");
}
}
/**
* Initializes the controller class.
* #param url
* #param rb
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Here is my Login.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" fx:id="lblMessage" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.LoginController">
<children>
<PasswordField fx:id="txtPassword" layoutX="200.0" layoutY="200.0" prefHeight="30.0" prefWidth="200.0" promptText="Password" />
<TextField fx:id="txtUsername" layoutX="200.0" layoutY="140.0" prefHeight="30.0" prefWidth="200.0" promptText="Username" />
<Button fx:id="btnLogin" layoutX="269.0" layoutY="251.0" mnemonicParsing="false" onAction="#btnLoginAction" prefHeight="30.0" text="Login">
<font>
<Font size="14.0" />
</font></Button>
<Label fx:id="lblMessage" layoutX="283.0" layoutY="71.0" text="Label" />
</children>
</AnchorPane>
Here is my DateSelectionController.java
package com;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
/**
* FXML Controller class
*
* #author Tyler
*/
public class DateSelectionController implements Initializable {
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Here is my DateSelection.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="com.DateSelectionController">
<children>
<Label layoutX="191.0" layoutY="164.0" text="Welcome">
<font>
<Font name="System Bold" size="50.0" />
</font>
</Label>
</children>
</AnchorPane>
From Oracle:
The main() method is not required for JavaFX applications when the JAR file for the application is created with the JavaFX Packager tool, which embeds the JavaFX Launcher in the JAR file. However, it is useful to include the main() method so you can run JAR files that were created without the JavaFX Launcher, such as when using an IDE in which the JavaFX tools are not fully integrated. Also, Swing applications that embed JavaFX code require the main() method.
So one solution is to make sure it's being built in a way that fully supports the JavaFX tools. The other solution is to add a main method to starts the application. That would avoid any potential problems like this, and doesn't cause any problems in the case where it's not needed.
Your main method should look like this:
public static void main(String[] args){
Application.launch(Login.class, args);
}
That will simply pass control on to JavaFX to handle like it would normally.

Java Fx, Edit the textarea of a specific tab

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.

JavaFX 8 - Layout swapping or similar/equivalent functionality to Qt's StackedWidget?

I've been asked to write a conversion program in JavaFX, but i need to allow the user to set different options depending on the conversion direction.
In reaction to swapping the conversion direction, I need to show two different (unique) sets of controls for options relating to the current direction only.
In one direction I need to display two TextFields, in the other direction, a pair of RadioButtons. I could show both at the same time and just enable/disable when needed, but I'm trying for a less cluttered approach first.
I'm looking for a solution that has similar layout-switching functionality to Qt's StackedWidget that I've used in C++, so i can swap out the TextFields for the RadioButtons and vice versa depending on the conversion direction.
It's important to note that this window has many other options that are common to both directions, so it's only a small part that needs to change according to the conversion direction. Thus I'd prefer it if I could easily access the swapped controls from within the same controller.
I don't want tabs or page numbers as the user controls the direction elsewhere, so TabPane and Pagination are out, unless those undesirable pieces of functionality can be disabled.
I've heard that there's something called a CardLayout in another Java framework (it's in awt if i heard right) which would do the job I want, what's the JavaFX 8 equivalent? Or is there another solution that i should be using instead?
I'm using SceneBuilder so ideally something i can implement in that, but I can use pure code if need be.
You can use any Pane subclass (e.g. a StackPane) and call pane.getChildren().setAll(textFieldDisplay); or pane.getChildren().setAll(radioButtonDisplay); as needed. The different displays can be any kind of Node, but since they hold other controls they would typically also be some subclass of Pane. In the example below I use a GridPane for one and a VBox for the other. In a real application, you might define each one in its own FXML file and load them independently, etc.
Complete example (using FXML):
Main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController"
alignment="CENTER">
<padding>
<Insets top="20" left="20" right="20" bottom="20" />
</padding>
<CheckBox text="Show Text Fields" fx:id="showTextFields" VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10" left="10" right="10" bottom="10"/>
</VBox.margin>
</CheckBox>
<StackPane fx:id="display" VBox.vgrow="ALWAYS" />
<Button text="OK" onAction="#submit" VBox.vgrow="NEVER" />
</VBox>
MainController.java:
package application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.StackPane;
public class MainController {
#FXML
private CheckBox showTextFields ;
#FXML
private StackPane display ;
private Node radioDisplay ;
private Node textFieldDisplay ;
private RadioButtonController radioButtonController ;
private TextFieldController textFieldController ;
public void initialize() throws Exception {
FXMLLoader radioDisplayLoader = new FXMLLoader(getClass().getResource("RadioDisplay.fxml"));
radioDisplay = radioDisplayLoader.load();
radioButtonController = radioDisplayLoader.getController();
FXMLLoader textFieldDisplayLoader = new FXMLLoader(getClass().getResource("TextFieldDisplay.fxml"));
textFieldDisplay = textFieldDisplayLoader.load();
textFieldController = textFieldDisplayLoader.getController();
showTextFields.selectedProperty().addListener((obs, wasSelected, isSelected) -> {
if (isSelected) {
display.getChildren().setAll(textFieldDisplay);
} else {
display.getChildren().setAll(radioDisplay);
}
});
display.getChildren().add(radioDisplay);
}
#FXML
private void submit() {
if (showTextFields.isSelected()) {
System.out.println("Value 1 is "+ textFieldController.getText1());
System.out.println("Value 2 is "+ textFieldController.getText2());
} else {
System.out.println("Chosen value is "+radioButtonController.getSelectedItem());
}
}
}
RadioDisplay.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.RadioButton?>
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.RadioButtonController"
alignment="TOP_CENTER" spacing="10">
<padding>
<Insets top="10" left="10" right="10" bottom="10"/>
</padding>
<RadioButton text="Choice 1" selected="true" fx:id="choice1"/>
<RadioButton text="Choice 2" fx:id="choice2"/>
</VBox>
RadioButtonController.java:
package application;
import javafx.fxml.FXML;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
public class RadioButtonController {
#FXML
private RadioButton choice1 ;
#FXML
private RadioButton choice2 ;
public void initialize() {
ToggleGroup toggleGroup = new ToggleGroup();
choice1.setToggleGroup(toggleGroup);
choice2.setToggleGroup(toggleGroup);
}
public String getSelectedItem() {
if (choice1.isSelected()) {
return "Choice 1";
} else if (choice2.isSelected()) {
return "Choice 2";
} else return "" ;
}
}
TextFieldDisplay.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<GridPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.TextFieldController"
hgap="10" vgap="10">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" halignment="RIGHT"/>
<ColumnConstraints hgrow="SOMETIMES" />
</columnConstraints>
<Label text="Value 1:" GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<Label text="Value 2:" GridPane.columnIndex="0" GridPane.rowIndex="1"/>
<TextField fx:id="textField1" GridPane.columnIndex="1" GridPane.rowIndex="0"/>
<TextField fx:id="textField2" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
</GridPane>
TextFieldController.java:
package application;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class TextFieldController {
#FXML
private TextField textField1 ;
#FXML
private TextField textField2 ;
public String getText1() {
return textField1.getText() ;
}
public String getText2() {
return textField2.getText();
}
}
Main.java:
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
VBox root = (VBox)FXMLLoader.load(getClass().getResource("Main.fxml"));
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
All the FXML files are in the same package (application) as the .java files.
Update
If you prefer not to "modularize" it to this extent, you can put everything in a single FXML with a single controller. In that case, Main.fxml looks like
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController"
alignment="CENTER">
<padding>
<Insets top="20" left="20" right="20" bottom="20" />
</padding>
<CheckBox text="Show Text Fields" fx:id="showTextFields" VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10" left="10" right="10" bottom="10"/>
</VBox.margin>
</CheckBox>
<StackPane fx:id="display" VBox.vgrow="ALWAYS">
<VBox fx:id="radioDisplay" alignment="TOP_CENTER" spacing="10">
<padding>
<Insets top="10" left="10" right="10" bottom="10" />
</padding>
<RadioButton text="Choice 1" selected="true" fx:id="choice1" />
<RadioButton text="Choice 2" fx:id="choice2" />
</VBox>
<fx:define>
<GridPane fx:id="textFieldDisplay" hgap="10" vgap="10">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" halignment="RIGHT" />
<ColumnConstraints hgrow="SOMETIMES" />
</columnConstraints>
<Label text="Value 1:" GridPane.columnIndex="0"
GridPane.rowIndex="0" />
<Label text="Value 2:" GridPane.columnIndex="0"
GridPane.rowIndex="1" />
<TextField fx:id="textField1" GridPane.columnIndex="1"
GridPane.rowIndex="0" />
<TextField fx:id="textField2" GridPane.columnIndex="1"
GridPane.rowIndex="1" />
</GridPane>
</fx:define>
</StackPane>
<Button text="OK" onAction="#submit" VBox.vgrow="NEVER" />
</VBox>
and the corresponding controller is
package application;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.StackPane;
public class MainController {
#FXML
private CheckBox showTextFields ;
#FXML
private StackPane display ;
#FXML
private Node radioDisplay ;
#FXML
private Node textFieldDisplay ;
#FXML
private TextField textField1 ;
#FXML
private TextField textField2 ;
#FXML
private RadioButton choice1 ;
#FXML
private RadioButton choice2 ;
public void initialize() throws Exception {
showTextFields.selectedProperty().addListener((obs, wasSelected, isSelected) -> {
if (isSelected) {
display.getChildren().setAll(textFieldDisplay);
} else {
display.getChildren().setAll(radioDisplay);
}
});
ToggleGroup toggleGroup = new ToggleGroup();
choice1.setToggleGroup(toggleGroup);
choice2.setToggleGroup(toggleGroup);
}
#FXML
private void submit() {
if (showTextFields.isSelected()) {
System.out.println("Value 1 is "+ textField1.getText());
System.out.println("Value 2 is "+ textField2.getText());
} else {
String chosenValue ;
if (choice1.isSelected()) {
chosenValue = "Choice 1";
} else if (choice2.isSelected()) {
chosenValue = "Choice 2";
} else {
chosenValue
= "None";
}
System.out.println("Chosen value is "+chosenValue);
}
}
}
(and in this case, remove the other two FXML files and their controllers).

Categories

Resources