This question already has answers here:
Passing Parameters JavaFX FXML
(10 answers)
Closed 4 years ago.
I'd like to ask if it is possible to pass a Variable through a JavaFX Class what extends Application to my JavaFx Controller? I am very new to JavaFx and only may need a little kick.
The goal is to pass a Id from MyClass to MyController.
My Application class:
public class MyClass extends Application {
private String myVariable="Anything";
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
URL location = getClass().getResource("MyGui.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(location);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
Parent root = FXMLLoader.load(location);
Scene scene = new Scene(root);
stage.setTitle(title);
stage.setScene(scene);
stage.show();
}
}
My Controller:
public class Controller extends Group implements Binding {
public void initialize(Map<String, Object> namespace, URL location, Resources resources) {
// HERE I'D LIKE TO GET MY VARIABLE LIKE
System.out.println(myVariable);
}
#Override
public List<Handler> getHandlerChain() {
return null;
}
#Override
public void setHandlerChain(List<Handler> chain) {
}
#Override
public String getBindingID() {
return null;
}
}
First you will have to add the setter and getter in the MyClass (as the var is private) and change it to static:
private static String myVariable;
public String getMyVariable() {
return myVariable;
}
public void setMyVariable(String myVariable) {
this.myVariable = myVariable;
}
Then, as the MyClass is static can do:
System.out.println(MyClass.getMyVariable());
Working example:
MyClass.java
import java.net.URL;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.fxml.JavaFXBuilderFactory;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MyClass extends Application {
private static String myVariable;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
setMyVariable("Anything");
URL location = getClass().getResource("MyGui.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(location);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
Parent root = FXMLLoader.load(location);
Scene scene = new Scene(root);
stage.setTitle("Hello Word");
stage.setScene(scene);
stage.show();
}
public static String getMyVariable() {
return myVariable;
}
public static void setMyVariable(String myVariable) {
MyClass.myVariable = myVariable;
}
}
MyController.java
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
public class MyController implements Initializable{
#FXML Label labelVar;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
labelVar.setText(labelVar.getText() + MyClass.getMyVariable());
}
}
MyGui.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="110.0" prefWidth="305.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="MyController">
<children>
<Label fx:id="labelVar" layoutX="24.0" layoutY="32.0" prefHeight="17.0" prefWidth="129.0" text="MyVariable = " />
</children>
</Pane>
Related
I made a simple FX program to replicate the problem I am seeing. I have a TestController that extends AbstractBar which extends AbstractFoo. After calling the initialize() method, a simple GUI displays with a button. I am expecting a "Hello World!" message to print to the console when the button is pressed, but I am getting a null value instead. Why does this happen and how do I fix this?
Expected result: Hello World!
Button result: null
Button result: null
Main.java
package com.test.main;
import com.test.gui.TestController;
import javafx.embed.swing.JFXPanel;
public class Main {
private static TestController controller;
public static void main(String[] args) {
String fxml = "/gui/Simple.fxml";
String content = "Hello World!";
new JFXPanel();
controller = new TestController();
controller.initialize(fxml, content);
System.out.println("Expected result: " + controller.getContent());
}
}
TestController.java
package com.test.gui;
import javafx.fxml.FXML;
public class TestController extends AbstractBar {
#FXML
private void testButton() {
System.out.println("Button result: " + super.getContent());
}
}
AbstractBar.java
package com.test.gui;
public abstract class AbstractBar extends AbstractFoo {
#Override
public void initialize(String fxml, String content) {
// Do stuff.
super.initialize(fxml, content);
}
}
AbstractFoo.java
package com.test.gui;
import java.io.IOException;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public abstract class AbstractFoo {
protected String fxml;
protected String content;
protected Stage stage;
protected Parent root;
public void initialize(String fxml, String content) {
this.fxml = fxml;
this.content = content;
Platform.runLater(() -> {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(this.getClass().getResource(fxml));
try {
this.root = loader.load();
} catch (IOException e) {
e.printStackTrace();
}
this.stage = new Stage();
this.stage.setScene(new Scene(root));
this.stage.show();
});
}
public String getContent() {
return this.content;
}
}
Simple.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.Button?>
<BorderPane fx:id="root" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/15.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.test.gui.TestController">
<center>
<Button fx:id="button" text="Click me!" onAction="#testButton" />
</center>
</BorderPane>
As pointed out by the comments, it is correct that the FXMLLoader is not using the same controller instance I am expecting. The simple fix is to remove the fx:controller attribute from the fxml file. and add loader.setController(this) to AbstractFoo. Now everything works as expected, what a big oversight...
com.test.gui.TestController#568bf312
Expected result: Hello World!
com.test.gui.TestController#568bf312
Button result: Hello World!
Simple.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.Button?>
<BorderPane fx:id="root" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/15.0.1" xmlns:fx="http://javafx.com/fxml/1" >
<center>
<Button fx:id="button" text="Click me!" onAction="#testButton" />
</center>
</BorderPane>
AbstractFoo.java
package com.test.gui;
import java.io.IOException;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public abstract class AbstractFoo {
protected String fxml;
protected String content;
protected Stage stage;
protected Parent root;
public void initialize(String fxml, String content) {
this.fxml = fxml;
this.content = content;
Platform.runLater(() -> {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(this.getClass().getResource(fxml));
loader.setController(this);
try {
this.root = loader.load();
} catch (IOException e) {
e.printStackTrace();
}
this.stage = new Stage();
this.stage.setScene(new Scene(root));
this.stage.show();
});
}
public String getContent() {
return this.content;
}
}
Is there a way to bind an object's field to a TreeItem so that when the field is changed, the TreeItem is automatically updated in the TreeView?
I have objects with several fields that are set in TreeItems in a TreeView. The objects fields are updated sometimes at 5 to 10 times per second via their setters and I would like the TreeItems to update on the fly as the fields change. Any help on this would be greatly appreciated. I can't seem to find a way to do this other than reloading the entire TreeView.
Edit: Here is the existing code...
The list listener sets up the treeview for the player list. If the number of objects in the list changes, the tree is redrawn. That is all fine. What I want is, if you were to place code in the handle button click method that continuously changes player attributes(in a loop, maybe 2-10 times per second), that should be reflected in the treeview as those attributes change.(Just a simulation, I cant get into how those attributes are really being changed at that rate). An example of how to do this would be great.
package application;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import viewcontroller.PlayerViewController;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
public class Main extends Application {
private Stage mainStage;
#FXML
private AnchorPane mainView;
#Override
public void start(Stage mainStage) {
this.mainStage = mainStage;
PlayerList.playerListListener();
this.showMainLayout();
}
/**
* shows the main screen
*/
public void showMainLayout() {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/viewcontroller/playerView.fxml"));
try {
mainView = (AnchorPane) loader.load();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Scene scene = new Scene(mainView);
mainStage.sizeToScene();
mainStage.setScene(scene);
mainStage.show();
PlayerViewController controller = loader.getController();
controller.setMainApp(this);
}
public static void main(String[] args) {
launch(args);
}
}
package model;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Player {
private StringProperty str1 = new SimpleStringProperty();
private StringProperty str2 = new SimpleStringProperty();
private StringProperty str3 = new SimpleStringProperty();
public Player() {
}
public Player(String str1, String str2, String str3) {
super();
this.str1 = new SimpleStringProperty(str1);
this.str2 = new SimpleStringProperty(str2);
this.str3 = new SimpleStringProperty(str3);
}
public StringProperty str1() {
return str1;
}
public String getStr1() {
return str1.get();
}
public void setStr1(String str1) {
this.str1.set(str1);
}
public StringProperty str2() {
return str2;
}
public String getStr2() {
return str2.get();
}
public void setStr2(String str2) {
this.str2.set(str2);
}
public StringProperty str3() {
return str3;
}
public String getStr3() {
return str3.get();
}
public void setStr3(String str3) {
this.str3.set(str3);
}
}
package application;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
import model.Player;
public class PlayerList {
private final ObservableList<Player> playerList = FXCollections.observableArrayList();
private static PlayerList instance = new PlayerList();
public static TreeItem<String> rootNode = new TreeItem<String>("Root");
private PlayerList() {}
public ObservableList<Player> getPlayerList() {
return playerList;
}
public static PlayerList getInstance() {
return instance;
}
public static void playerListListener() {
//adds a list listener which reloads tree if objects are added or removed
PlayerList.getInstance().getPlayerList().addListener((ListChangeListener<? super Player>) new ListChangeListener<Player>() {
#SuppressWarnings("unchecked")
public void onChanged(Change<? extends Player> change) {
//re-sort list
//System.out.println("List changed");
rootNode.getChildren().clear();//clear tree before reloading on list change
for(Player p: PlayerList.getInstance().getPlayerList()) {
//Parent Node
TreeItem<String> playerName = new TreeItem<String>(p.getStr1());
//Items
TreeItem<String> attr1 = new TreeItem<String>(p.getStr2());
TreeItem<String> attr2 = new TreeItem<String>(p.getStr3());
playerName.getChildren().addAll(attr1, attr2);
playerName.setExpanded(true);
rootNode.getChildren().add(playerName);
rootNode.setExpanded(true);
}
}
});
}
}
package viewcontroller;
import java.net.URL;
import java.util.ResourceBundle;
import application.Main;
import application.PlayerList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TreeView;
import javafx.scene.layout.VBox;
import model.Player;
public class PlayerViewController implements Initializable {
#FXML
private VBox vbox;
private TreeView<String> treeView;
public void setMainApp(Main main) {
// TODO Auto-generated method stub
}
#Override
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
Player p1 = new Player("Name1", "Attr1", "Attr2");
Player p2 = new Player("Name2", "Attr1", "Attr2");
Player p3 = new Player("Name3", "Attr1", "Attr2");
PlayerList.getInstance().getPlayerList().addAll(p1, p2, p3);//add players to list
treeView = new TreeView<String>(PlayerList.rootNode);
treeView.setShowRoot(false);
vbox.getChildren().add(treeView);//add tree view to GUI
}
#FXML
private void handleButtonClick() {
/*this method can hold code that would run in a loop, continuously setting new values
on p1, p2, and p3 attributes and would show the tree items updating automatically*/
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:id="mainView" prefHeight="400.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="viewcontroller.PlayerViewController">
<children>
<VBox fx:id="vbox" layoutX="14.0" layoutY="14.0" prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Button mnemonicParsing="false" onAction="#handleButtonClick" text="Button" />
</children>
</VBox>
</children>
</AnchorPane>
I have 2 fxml file. Example A.fxml. B.fxml. I have 2 controller. AController (A.fxml) BController (B.fxml). A fxml and B fxml have change button changing Scene or fxml. This is button code;
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/infoLibrary/view/A.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
Stage stage = (Stage)((Node)event.getSource()).getScene().getWindow();
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
Same code in BContrroller change button. When i click change button scane changing. But everytime init method and controller contructers working too. When user change fxml javafx everytime using new constructor. How can i change windows without new controller constructor?
Use a view model:
public class ViewModel {
public enum View {A, B}
private final ObjectProperty<View> currentView = new SimpleObjectProperty<>(View.A);
public ObjectProperty<View> currentViewProperty() {
return currentView ;
}
public final View getCurrentView() {
return currentViewProperty().get();
}
public final View setCurrentView(View view) {
currentViewProperty().set(view);
}
}
Now in your AController do:
public class AController {
private ViewModel viewModel ;
public void setViewModel(ViewModel viewModel) {
this.viewModel = viewModel ;
}
// button handler:
#FXML
private void goToB(ActionEvent event) {
viewModel.setCurrentView(ViewModel.View.B);
}
}
and BController is similar.
Finally, you set everything up with something like the following, which is executed only once (e.g. in your start() method, or somewhere similar):
Stage stage = ... ; // maybe it's the primary stage in start...
Scene scene = new Scene();
ViewModel viewModel = new ViewModel();
FXMLLoader aLoader = new FXMLLoader(getClass().getResource("/infoLibrary/view/A.fxml"));
Parent a = aLoader.load();
AController aController = aLoader.getController();
aController.setViewModel(viewModel);
FXMLLoader bLoader = new FXMLLoader(getClass().getResource("/infoLibrary/view/B.fxml"));
Parent b = bLoader.load();
BController bController = bLoader.getController();
bController.setViewModel(viewModel);
scene.rootProperty().bind(Bindings.createObjectBinding(() -> {
if (viewModel.getCurrentView() == ViewModel.View.A) {
return a ;
} else if (viewModel.getCurrentView() == ViewModel.View.B) {
return b ;
} else {
return null ;
}
}, viewModel.currentViewProperty());
stage.setScene(scene);
stage.show();
Now the two FXML files are only loaded once (so the controllers are only created once, and their initialize() methods called only once). The switching is managed by changing the state of the ViewModel and observing that state, so the scene's root is changed when the model state changes.
Here is a complete SSCCE:
ViewModel.java:
package sceneswitcher;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
public class ViewModel {
public enum View {A, B}
private final ObjectProperty<View> currentView = new SimpleObjectProperty<>(View.A);
public ObjectProperty<View> currentViewProperty() {
return currentView ;
}
public final View getCurrentView() {
return currentViewProperty().get();
}
public final void setCurrentView(View view) {
currentViewProperty().set(view);
}
}
AController.java:
package sceneswitcher;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class AController {
private ViewModel viewModel ;
#FXML
private TextField textField ;
public void setViewModel(ViewModel viewModel) {
this.viewModel = viewModel ;
}
// button handler:
#FXML
private void goToB(ActionEvent event) {
viewModel.setCurrentView(ViewModel.View.B);
}
public String getText() {
return textField.getText();
}
}
A.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.Button?>
<VBox fx:controller="sceneswitcher.AController" spacing="5" alignment="CENTER"
xmlns:fx="http://javafx.com/fxml/1">
<Label text='This is view A'/>
<TextField fx:id="textField" />
<Button onAction="#goToB" text="Go to view B"/>
</VBox>
BController.java:
package sceneswitcher;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
public class BController {
private ViewModel viewModel ;
#FXML
private TextArea textArea ;
public void setViewModel(ViewModel viewModel) {
this.viewModel = viewModel ;
}
// button handler:
#FXML
private void goToA(ActionEvent event) {
viewModel.setCurrentView(ViewModel.View.A);
}
public String getText() {
return textArea.getText();
}
}
B.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.Button?>
<VBox fx:controller="sceneswitcher.BController" spacing="5" alignment="CENTER"
xmlns:fx="http://javafx.com/fxml/1">
<Label text="This is view B"/>
<TextArea fx:id="textArea" />
<Button onAction="#goToA" text="Go to View A"/>
</VBox>
Main.java:
package sceneswitcher;
import java.io.IOException;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
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 {
ViewModel viewModel = new ViewModel();
FXMLLoader aLoader = new FXMLLoader(getClass().getResource("A.fxml"));
Parent a = aLoader.load();
AController aController = aLoader.getController();
aController.setViewModel(viewModel);
FXMLLoader bLoader = new FXMLLoader(getClass().getResource("B.fxml"));
Parent b = bLoader.load();
BController bController = bLoader.getController();
bController.setViewModel(viewModel);
Scene scene = new Scene(a, 400, 400);
scene.rootProperty().bind(Bindings.createObjectBinding(() -> {
if (viewModel.getCurrentView() == ViewModel.View.A) {
return a ;
} else if (viewModel.getCurrentView() == ViewModel.View.B) {
return b ;
} else {
return null ;
}
}, viewModel.currentViewProperty()));
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I'm trying to populate the value of a text field in Java FX.
I have the Main Class,the controller and the fxml.I have bind the fxml file with controller and the appropriate field in it. When i try to set its value, it fails.
Main.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class Main extends Application {
private Stage primaryStage;
private FlowPane rootLayout;
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("test.fxml"));
rootLayout = (FlowPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
testController.java
package application;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class testController {
#FXML
private TextField t1;
public testController() {
System.out.println("hi");
t1 = new TextField("j");
t1.setText("hi");
}
}
FXML file:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.FlowPane?>
<FlowPane prefHeight="200.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.testController">
<children>
<TextField fx:id="t1" />
</children>
</FlowPane>
You are doing it in the wrong place! If you need to play around with your controls just before your fxml is loaded, you need to do it in the initialize(). For this your controller should implement the Initializable
So your controller becomes :
public class testController implements Initializable{
#FXML
private TextField t1;
public void initialize() {
System.out.println("hi");
//You should not re-initialize your textfield
//t1 = new TextField("j");
t1.setText("hi");
}
}
What is an expected method of connecting view and model in JavaFX?
Binding?
Suppose I want to make positioning in database with the following controls:
I have data (recordset) object in memory and it's properties are bindable. I.e. they are notifying when current record changes and when the number of records changes.
I want user to be able position inside recordset both with slider and text field.
How to accomplish that? There is no numeric spin in JavaFX, so how to bind text, slider and recordset object (three ends) together? Is it possible?
I cannot give an authoritative answer since I don't work for Oracle nor am I some JavaFX-pert but I usually construct the controller with an instance of the model and in the initialize method of the controller I create the bindings between the controls' properties and the model's properties.
To your concrete problem I have a lame but working solution. Lame because I can't figure out how to use the low-level binding API and I use two properties on the model. Here's how :
FXML :
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.control.TextField?>
<GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<Slider GridPane.columnIndex="0" fx:id="slider" min="0" max="99"/>
<Label GridPane.columnIndex="1" text="Record" />
<TextField fx:id="textfield" GridPane.columnIndex="2"/>
</GridPane>
Main.java :
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import sample.Models.Model;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
final Model model = new Model();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("sample.fxml"));
loader.setControllerFactory(new Callback<Class<?>, Object>() {
#Override
public Object call(Class<?> aClass) {
return new Controller(model);
}
});
GridPane root = (GridPane) loader.load();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
}
Controller.java :
package sample;
import javafx.beans.binding.DoubleBinding;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import sample.Models.Model;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable {
private final Model model;
public Controller(Model model) {
this.model = model;
}
#FXML
public Slider slider;
#FXML
public TextField textfield;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
slider.valueProperty().bindBidirectional(model.pageProperty());
textfield.textProperty().bindBidirectional(model.pageTextProperty());
}
}
Model.java :
package sample.Models;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
public class Model {
private IntegerProperty pageProperty;
private StringProperty pageTextProperty;
public Model() {
pageProperty = new SimpleIntegerProperty(2);
pageProperty.addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2) {
int value = pageProperty.get();
//System.out.println("Page changed to " + value);
if (Integer.toString(value).equals(pageTextProperty.get())) return;
pageTextProperty.set(Integer.toString(value));
}
});
pageTextProperty = new SimpleStringProperty("2");
pageTextProperty.addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s2) {
try {
int parsedValue = Integer.parseInt(observableValue.getValue());
if (parsedValue == pageProperty.get()) return;
pageProperty().set(parsedValue);
} catch (NumberFormatException e) {
// too bad
}
}
});
}
public int getPage() {
return pageProperty.get();
}
public void setPage(int page) {
pageProperty.set(page);
}
public IntegerProperty pageProperty() {
return pageProperty;
}
public String getPageText() {
return pageTextProperty.get();
}
public void setPageText(String pageText) {
pageTextProperty.set(pageText);
}
public StringProperty pageTextProperty() {
return pageTextProperty;
}
}