I have a desktop app that contains:
Main Class: that load the first fxml file -> SideBar.fxml
SideBar.fxml: contains BorderPane -> at the left of it, i create 2 buttons:
- the fist button: load sample fxml file
- the second button: load secondFxml file
sample.fxml: contains a tableView and a Button
secondFxml.fxml: contains a label
Controller: a class that control sample.fxml -> load random double values to a tableView
the issue is :
when i press the button (fill Table) in Pane 1 : it load the data to the tableView, untill now everything is going well
when i switch to the second pane and i return to the first pane the center border pane is reloaded again so the data of the tableView disappeared
what i want is when i return to the first pane the the table view stay as it was first
i try to hide the borderpane center but it doesn't work for me
i screenShot the issue:
Main:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("SideBar.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 700, 500));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
SideBarController:
public class SideBarController implements Initializable {
#FXML BorderPane borderPane;
public void openPane1(ActionEvent event) throws Exception {
loadScene("Sample.fxml");
}
public void openPane2(ActionEvent event) throws Exception {
loadScene("secondFxml.fxml");
}
private void loadScene(String sc) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource(sc));
borderPane.setCenter(root);
}
#Override
public void initialize(URL location, ResourceBundle resources) { }
}
Controller:
public class Controller implements Initializable {
double[][] data = new double[5][5];
Random random = new Random();
ObservableList<double[]> observableLists = FXCollections.observableArrayList();
#FXML
TableView<double []> tableView = new TableView<>(observableLists);
#FXML
public void fillTable(ActionEvent event) throws IOException {
//Random Values
for (int i = 0; i <data.length ; i++) {
for (int j = 0; j <data[0].length ; j++) {
data[i][j]= random.nextDouble();
}
}
//Add data to ObservableLists
for (int i = 0; i <data.length ; i++) {
observableLists.add(data[i]);
}
//Create Columns
for (int i = 0; i <data[0].length ; i++) {
TableColumn<double[], Double> column= null;
column = new TableColumn<>("column "+i);
int finalI = i;
column.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue()[finalI]));
tableView.getColumns().add(column);
}
// Fill TableView
tableView.setItems(observableLists);
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
}
SideBar.fxml
<BorderPane fx:id="borderPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.SideBarController">
<left>
<VBox prefHeight="400.0" prefWidth="173.0" style="-fx-background-color: black;" BorderPane.alignment="CENTER">
<children>
<Button mnemonicParsing="false" onAction="#openPane1" prefHeight="25.0" prefWidth="177.0" style="-fx-background-color: blue; -fx-border-color: white;" text="Pane 1" textFill="WHITE">
<VBox.margin>
<Insets top="50.0" />
</VBox.margin>
<font>
<Font name="System Bold" size="17.0" />
</font>
</Button>
<Button mnemonicParsing="false" onAction="#openPane2" prefHeight="25.0" prefWidth="176.0" style="-fx-background-color: blue; -fx-border-color: white;" text="Pane 2" textFill="WHITE">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
<font>
<Font name="System Bold" size="17.0" />
</font>
</Button>
</children>
</VBox>
</left>
<center>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<children>
<Label layoutX="163.0" layoutY="152.0" prefHeight="68.0" prefWidth="131.0" text="Home">
<font>
<Font size="46.0" />
</font>
</Label>
</children>
</Pane>
</center>
</BorderPane>
Sample.fxml
<Pane prefHeight="395.0" prefWidth="597.0" style="-fx-background-color: white;" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<TableView fx:id="tableView" layoutX="77.0" layoutY="47.0" prefHeight="266.0" prefWidth="461.0" />
<Button layoutX="257.0" layoutY="329.0" mnemonicParsing="false" onAction="#fillTable" text="fill Table" />
</children>
</Pane>
SecondFxml.fxml
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label layoutX="232.0" layoutY="153.0" text="Pane 2">
<font>
<Font size="46.0" />
</font>
</Label>
</children>
</Pane>
Do not reload from fxml when button is clicked. Do it once in initialize:
public class SideBarController implements Initializable {
#FXML BorderPane borderPane;
private Parent sample, secondFxml;
public void openPane1(ActionEvent event) throws Exception {
borderPane.setCenter(sample);
}
public void openPane2(ActionEvent event) throws Exception {
borderPane.setCenter(secondFxml);
}
private Parent loadScene(String sc) throws IOException {
return FXMLLoader.load(getClass().getResource(sc));
}
#Override
public void initialize(URL location, ResourceBundle resources) {
try {
sample = loadScene("Sample.fxml");
secondFxml = loadScene("secondFxml.fxml");
} catch (IOException ex) {
ex.printStackTrace();
};
}
}
Related
I have a TableView in my fxml. Within the controller this table is mapped with the #FXML annotation.
#FXML
TableView<BankMovement> table;
I also set, in fxml document, for table element
onMouseReleased = "#handleRowSelect"
finally always in the controller I have the following method
#FXML
private void handleRowSelect(MouseEvent event){
Document row = table.getSelectionModel().getSelectedItem();
if (row == null) return;
if(row != temp){
temp = row;
lastClickTime = new Date();
} else if(row == temp) {
Date now = new Date();
long diff = now.getTime() - lastClickTime.getTime();
if (diff < 300){
System.out.println("Edit dialog");
System.out.print(row.getDescription());
} else {
lastClickTime = new Date();
System.out.print(row.getFile());
}
}
}
here instead is where to bind the data to table
#Override
public void initializeTable() {
table.setItems(subList());
colId.setCellValueFactory(new PropertyValueFactory<>("idDocument"));
colIdCategory.setCellValueFactory(d -> new SimpleStringProperty(d.getValue().getCategory().getName()));
colIdCategoryChild.setCellValueFactory(d -> new SimpleStringProperty(d.getValue().getCategoryChild().getName()));
colIdDocument.setCellFactory(getFileCellFactory());
colIdDocument.setCellValueFactory(new PropertyValueFactory<>("file"));
colIdDescription.setCellValueFactory(new PropertyValueFactory<>("description"));
colIdDate.setCellValueFactory(d -> new SimpleStringProperty(Utils.localTimeToItalianDate(d.getValue().getDocumentDate())));
}
Even if I click on the table I never enter the handleRowSelect method.
I have the impression that when I click on the row the click on the cell is managed and not on the row. As if the event were not propagated.
This is fxml
<AnchorPane minWidth="-Infinity" prefHeight="900.0" prefWidth="1510.0" styleClass="background-white" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="MyController">
<children>
<VBox prefHeight="886.0" prefWidth="1465.0" style="-fx-min-width: 100%;" AnchorPane.bottomAnchor="4.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="330.0" AnchorPane.topAnchor="10.0">
<children>
<TitledPane animated="false" minHeight="-Infinity" minWidth="-Infinity" prefHeight="880.0" prefWidth="1465.0" text="%app.pane.document">
<content>
<VBox minWidth="-Infinity" prefHeight="815.0" prefWidth="1474.0">
<children>
<TableView onMouseReleased="#handleRowSelect" fx:id="table" minHeight="-Infinity" minWidth="-Infinity" prefHeight="746.0" prefWidth="1450.0">
.......
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</TableView>
<Pagination fx:id="pagination" prefHeight="73.0" prefWidth="1450.0" />
</children>
</VBox>
</content>
</TitledPane>
</children>
</VBox>
</children>
</AnchorPane>
I have an desktop application based on javafx.The only requirement is that it has to run continuously for 5-6 days.I am in testing phase.
UI component used in this:
6 Gauges (Medusa)
Line chart that is stacked on JFXDrawer and is controlled by a hamburger-button.
Out of 6 gauges 3 gauges and line chart has to be updated on a period of a sec. For this i have used a thread which update this component per second.
I have tested this application for almost 3 time:
For Three days
For 26 hours(In which graph is working fine and values are updating in the gauges but the gauge needle is stuck at a particular value)
For 24 hours now the gauge needle is moving but gauge value is stuck and the Line chart drawer is not open only the hamburger-icon is changing.
There is no Exception in log and the UI is not hanging, Just Ui components are not responsive.
I did profiling but everything seems OK.I have read this post also but in his case the ui is hanging and i have no issue regarding this, all the button are clicky and i am able to change the screens with not issue.
After reloading the Screen All gets back to normal.
sample code i've used to update the component.
Controller
public class testGaugeController implements Initializable {
// Component
private static final int MAX_DATA_POINTS = 1000;
private int xSeriesData = 0;
private final XYChart.Series<Number, Number> series1 = new XYChart.Series<>();
private ExecutorService executor;
private final ConcurrentLinkedQueue<Number> dataQ1 = new ConcurrentLinkedQueue<>();
private NumberAxis xAxis,yAxis;
LineChart<Number, Number> lineChart;
DatabaseHandler dh = new DatabaseHandler();
Connection connect = dh.MakeConnection();
#FXML
private JFXDrawer drawer;
#FXML
private JFXHamburger burger;
#FXML
private Gauge Gauge;
/**
* Initializes the controller class.
*
* #param url
* #param rb
*/
public void initialize(URL url, ResourceBundle rb) throws IOException {
initializeRecorder();
start_recording();
}
private void initializeRecorder() throws IOException {
try {
xAxis = new NumberAxis(0, MAX_DATA_POINTS, MAX_DATA_POINTS / 100);
xAxis.setForceZeroInRange(false);
xAxis.setAutoRanging(true);
xAxis.setTickLabelsVisible(true);
xAxis.setTickMarkVisible(true);
xAxis.setMinorTickVisible(true);
yAxis = new NumberAxis();
// Create a LineChart
lineChart = new LineChart<Number, Number>(xAxis, yAxis) {
// Override to remove symbols on each data point
#Override
protected void dataItemAdded(XYChart.Series<Number, Number> series, int itemIndex, XYChart.Data<Number, Number> item) {
}
};
lineChart.setAnimated(false);
lineChart.setTitle("");
lineChart.setHorizontalGridLinesVisible(true);
series1.setName("Test Value");
lineChart.getData().addAll(series1);
drawer.setSidePane(lineChart);
drawer.setOverLayVisible(false);
} catch (Exception e) {
}
HamburgerBackArrowBasicTransition burgermove = new HamburgerBackArrowBasicTransition(burger);
burgermove.setRate(-1);
burger.addEventHandler(MouseEvent.MOUSE_PRESSED, (evt) -> {
burgermove.setRate(burgermove.getRate() * -1);
burgermove.play();
if (drawer.isShown()) {
drawer.close();
} else {
drawer.open();
}
});
}
int count_executer_status = 0;
boolean initial_start_trend = true;
private void start_recording() {
if (initial_start_trend) {
initial_start_trend = false;
} else {
xSeriesData = 0;
System.out.println("Clearing dataQue");
dataQ1.clear();
series1.getData().clear();
}
xAxis.setLowerBound(0);
count_executer_status++;
System.out.println("Cleared dataQue");
executor = Executors.newCachedThreadPool((Runnable r) -> {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
});
count_executer_status = 0;
AddToQueue addToQueue = new AddToQueue();
executor.execute(addToQueue);
//-- Prepare Timeline
prepareTimeline();
}
private class AddToQueue implements Runnable {
String query = "SELECT test_value FROM test_data_reader ORDER BY test_data_reader_id DESC LIMIT 1";
ResultSet rs;
#Override
public void run() {
try {
// add a item of random data to queue.
rs = dh.getData(query, connect);
if (rs.next()) {
double test_value = Double.parseDouble(rs.getString("test_value"));
dataQ1.add(test_value);
String Record_data = "INSERT INTO `test_data_record` (`test_value`, `date_time`) VALUES( '" + rs.getString("test_value") + "', NOW());";
dh.execute(Record_data, connect);
Platform.runLater(() -> {
Gauge.setValue(test_value);
});
}
xaxis_count++;
Thread.sleep(1000);
executor.execute(this);
} catch (Exception ex) {
}
}
}}
//-- Timeline gets called in the JavaFX Main thread
private void prepareTimeline() {
// Every frame to take any data from queue and add to chart
new AnimationTimer() {
#Override
public void handle(long now) {
addDataToSeries();
}
}.start();
}
int xaxis_count = 0;
private void addDataToSeries() {
try {
for (int i = 0; i < 20; i++) {
//-- add 20 numbers to the plot+
if (dataQ1.isEmpty()) {
break;
}
series1.getData().add(new XYChart.Data<>(xaxis_count, dataQ1.remove()));
}
if (series1.getData().size() > MAX_DATA_POINTS) {
series1.getData().remove(0, series1.getData().size() - MAX_DATA_POINTS);
}
// update
xAxis.setLowerBound(xSeriesData - MAX_DATA_POINTS);
xAxis.setUpperBound(xSeriesData - 1);
} catch (Exception e) {
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXDrawer?>
<?import com.jfoenix.controls.JFXHamburger?>
<?import eu.hansolo.medusa.Gauge?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="e913_300mt.testGaugeController">
<children>
<VBox prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<HBox fx:id="sectionHeader" minHeight="-Infinity" prefHeight="50.0" prefWidth="600.0" style="-fx-background-color: #2F333E;">
<children>
<VBox alignment="CENTER" layoutX="10.0" layoutY="10.0" HBox.hgrow="ALWAYS" />
<VBox alignment="CENTER" HBox.hgrow="ALWAYS" />
<VBox alignment="CENTER" HBox.hgrow="ALWAYS" />
<VBox alignment="CENTER" HBox.hgrow="ALWAYS" />
<VBox alignment="CENTER" HBox.hgrow="ALWAYS">
<children>
<JFXHamburger fx:id="burger" />
</children>
</VBox>
</children>
</HBox>
<HBox prefHeight="100.0" prefWidth="200.0" VBox.vgrow="ALWAYS">
<children>
<Gauge fx:id="gauge" autoScale="false" borderPaint="#0099ff" borderWidth="3.0" decimals="0" foregroundPaint="#0000000b" highlightSections="true" innerShadowEnabled="true" knobType="METAL" lcdDesign="RED" lcdFont="LCD" majorTickMarkType="PILL" majorTickSpace="250.0" markersVisible="true" maxValue="3000.0" mediumTickMarkType="TRAPEZOID" mediumTickMarksVisible="false" minorTickSpace="50.0" needleSize="THIN" needleType="VARIOMETER" shadowsEnabled="true" threshold="300.0" title="Test Gauge" unit="unit" HBox.hgrow="ALWAYS">
<HBox.margin>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</HBox.margin>
</Gauge>
</children>
</HBox>
</children>
</VBox>
<JFXDrawer fx:id="drawer" defaultDrawerSize="600.0" direction="RIGHT" layoutY="56.0" prefHeight="344.0" prefWidth="600.0" />
</children>
</AnchorPane>
Libraries
jfoenix-8.0.1-for-java8.jar Github
fontawesomefx-8.9.jar bitbucket
Medusa-8.0.jar jar-download
For testing purpose i am only updating one gauge.And system Configuration is :
OS : Ubuntu 18.04 lts
Processor : Intel core i5-8400
Ram : 8Gb
Any Idea on this.
I'm a tad confused with JavaFX at the minute. Basically, when I run my code, I can only click on a button on the side bar of the application once, then it will swap the center pane for the one that I want displayed. After that though, it appears that the ActionEvent does not trigger... I've tried reattaching them after handling but it doesn't work, and I have no idea whats wrong.
I've spent 2 days trying to crack this, and I'm sure it's something so annoyingly simple.
Controller:
#FXML private Button fooButton, barButton;
#FXML private Pane fooPane, barPane;
#FXML private BorderPane mainWindow;
#FXML private TabPane tabPane;
#FXML private VBox buttonBar;
#FXML private AnchorPane centerAP;
private HashMap<Button, Pane> buttonsPaneHMap = new HashMap<>(); //storing the data in a HashMap to create a link between buttons and their panes.
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
putNodesInHashmap();
assertControlsExist();
mainWindow.setCenter(welcomePane);
setOnActions(buttonsPaneHMap);
}
public final void handleButton(ActionEvent event) throws IOException {
Node newCenter = new AnchorPane();
if (event.getSource() == fooButton){
newCenter = FXMLLoader.load(getClass().getResource("/FXML/fooPane.fxml"));
}
if (event.getSource() == barButton){
newCenter = FXMLLoader.load(getClass().getResource("/FXML/barPane.fxml"));
}
try{
this.mainWindow.setCenter(newCenter);
}
catch (NullPointerException e){
e.printStackTrace();
}
}
public final void setOnActions(HashMap<Button, Pane> hMap){
for (Button button : hMap.keySet()){
((ButtonBase) button).setOnAction(arg0 -> {
try {
handleButton(arg0);
}
catch (Exception e) {
e.printStackTrace();
}
});
}
}
public final void putNodesInHashMap(){
buttonsPaneHMap.put(fooButton, fooPane);
buttonsPaneHMap.put(barButton, barPane);
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.URL?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<BorderPane fx:id="mainWindow" prefHeight="461.0" prefWidth="760.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="guiControllers.MainController">
<top>
<Pane id="body" prefHeight="96.0" prefWidth="658.0" style="-fx-background-color: #243242; -fx-border-color: #0E141B; -fx-border-radius: 3;" stylesheets="#application.css" BorderPane.alignment="CENTER">
<children>
<Label layoutX="103.0" layoutY="25.0" prefHeight="48.0" prefWidth="394.0" text="Title Here" textFill="WHITE">
<font>
<Font name="Calibri Bold" size="41.0" />
</font>
</Label>
<ImageView fitHeight="55.0" fitWidth="61.0" layoutX="25.0" layoutY="20.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../Res/mhlogo.png" />
</image>
</ImageView>
</children>
</Pane>
</top>
<left>
<VBox id="buttonBar" fx:id="buttonBar" alignment="TOP_CENTER" prefHeight="365.0" prefWidth="168.0" style="-fx-background-color: #2E4055; -fx-border-radius: 3; -fx-border-color: #0E141B;" BorderPane.alignment="CENTER">
<children>
<Pane prefHeight="31.0" prefWidth="98.0">
<children>
<Pane layoutX="-1.0" layoutY="-2.0" prefHeight="33.0" prefWidth="169.0" style="-fx-background-color: #565656; -fx-border-color: #000000; -fx-border-radius: 20; -fx-background-radius: 20;">
<children>
<ImageView fitHeight="19.0" fitWidth="18.0" layoutX="7.0" layoutY="7.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../Res/magnifying-glass.png" />
</image>
</ImageView>
<TextField layoutX="29.0" layoutY="2.0" prefHeight="0.0" prefWidth="134.0" style="-fx-border-radius: 1; -fx-border-color: #111111; -fx-border-width: 2; -fx-background-color: #FFFFFF; -fx-background-radius: 20; -fx-border-radius: 20;" styleClass="stop-color-leaking" stylesheets="#../cSS/application.css" />
</children>
</Pane>
</children>
</Pane>
<Button id="fooButton" fx:id="fooButton" mnemonicParsing="false" onAction="#handleButton" prefHeight="31.0" prefWidth="171.0" style="-fx-background-color: #CDCDCD; -fx-border-color: #0E141B; -fx-border-radius: 3;" text="foo" />
<Button id="barButton" fx:id="barButton" mnemonicParsing="false" onAction="#handleButton" prefHeight="31.0" prefWidth="202.0" style="-fx-background-color: #CDCDCD; -fx-border-color: #0E141B; -fx-border-radius: 3;" text="bar" />
<children>
<ImageView id="settingsButton" fitHeight="38.0" fitWidth="48.0" layoutX="64.0" layoutY="130.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../Res/settings.png" />
</image>
</ImageView>
</children>
</AnchorPane>
</children>
</VBox>
</left>
<right>
<TabPane id="tabPane" fx:id="tabPane" focusTraversable="false" prefHeight="365.0" prefWidth="166.0" rotateGraphic="true" style="-fx-background-color: # #414760;" styleClass="tab-header-background" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER">
<tabs>
<Tab fx:id="notesTab" text="Notes">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="336.0" prefWidth="216.0" style="-fx-border-color: #414760; -fx-background-radius: 3;" styleClass="tab-header-background" stylesheets="#../application/CSS/application.css" />
</content>
</Tab>
<Tab fx:id="diagramTab" closable="false" text="Diagram" />
</tabs>
<cursor>
<Cursor fx:constant="DEFAULT" />
</cursor>
<stylesheets>
<URL value="#application.css" />
<URL value="#../application/CSS/application.css" />
</stylesheets>
</TabPane>
</right>
<center>
<AnchorPane fx:id="centerAP" style="-fx-background-color: #414760;" BorderPane.alignment="CENTER">
<children>
<VBox fx:id="welcomePane" prefHeight="304.0" prefWidth="391.0" style="-fx-background-color: #414760;">
<children>
<Pane fx:id="welcomePane" prefHeight="313.0" prefWidth="428.0" style="-fx-background-color: #414760;">
<children>
<ImageView fitHeight="183.0" fitWidth="296.0" layoutX="14.0" layoutY="65.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../Res/welcomepane.png" />
</image>
</ImageView>
<Label layoutX="141.0" layoutY="14.0" text="Welcome" textFill="WHITE">
<font>
<Font name="Calibri Bold" size="33.0" />
</font>
</Label>
<Label layoutX="82.0" layoutY="53.0" prefHeight="68.0" prefWidth="346.0" text="To start, please select an" textFill="WHITE" textOverrun="CLIP">
<font>
<Font name="Calibri" size="24.0" />
</font>
</Label>
<Label layoutX="82.0" layoutY="80.0" prefHeight="68.0" prefWidth="346.0" text="option from the left." textFill="WHITE" textOverrun="CLIP">
<font>
<Font name="Calibri" size="24.0" />
</font>
</Label>
</children>
</Pane>
</children>
</VBox>
</children>
</AnchorPane>
</center>
</BorderPane>
As far as I can tell all objects are injected correctly from the FXML, but once the center panel has switched, the side buttons no longer function (Though I can click any initially and it will load.
Footnote: The code above is slightly cut down and changed for readability.
I took an idea from Android's playbook.
If you know how to get to the node's parent and you know the node's fx:id, you can use this approach.
The full code loads different panes into the center of a Scene depending on which button is press. The code below is a sample that show how one pane is loaded. You can get any node using this idea if you know the node's parent, the node's fx:id and the node's type for casting.
Controller code
private void showSetupAccountScreen()
{
try
{
spCenterDisplay.getChildren().remove(0);//remove old display
BorderPane root = FXMLLoader.load(getClass().getResource("SubSetupAccount.fxml"));
spCenterDisplay.getChildren().add(root);//add new display
GridPane tempDisplay = (GridPane)root.getChildren().get(1);//get Parent of the nodes I will be using in this controller
loadQWERTYKeyboard();
TextField tfFirstName = (TextField)findNodeByID("tfFirstName", tempDisplay.getChildren());
TextField tfLastName = (TextField)findNodeByID("tfLastName", tempDisplay.getChildren());
TextField tfStreetAddress = (TextField)findNodeByID("tfStreetAddress", tempDisplay.getChildren());
TextField tfCity = (TextField)findNodeByID("tfCity", tempDisplay.getChildren());
TextField tfState = (TextField)findNodeByID("tfState", tempDisplay.getChildren());
TextField tfZip = (TextField)findNodeByID("tfZip", tempDisplay.getChildren());
TextField tfInitialDepositChecking = (TextField)findNodeByID("tfInitialDepositChecking", tempDisplay.getChildren());
TextField tfInitialDepositSavings = (TextField)findNodeByID("tfInitialDepositSavings", tempDisplay.getChildren());
ChoiceBox cbChecking = (ChoiceBox)findNodeByID("cbChecking", tempDisplay.getChildren());
cbChecking.getItems().addAll("No", "Yes");
cbChecking.setValue("No");
ChoiceBox cbSavings = (ChoiceBox)findNodeByID("cbSavings", tempDisplay.getChildren());
cbSavings.getItems().addAll("No", "Yes");
cbSavings.setValue("No");
if(true)//come back and check to make sure all info is in textfields
{
btnLeftOne.setOnAction((event) -> {
boolean createChecking = cbChecking.getValue().equals("Yes");
boolean createSavings = cbSavings.getValue().equals("Yes");
dbh.createNewAccount(tfFirstName.getText(), tfLastName.getText(), tfStreetAddress.getText(), tfCity.getText(),
tfState.getText(), tfZip.getText(), createChecking, Double.parseDouble(tfInitialDepositChecking.getText()),
createSavings, Double.parseDouble(tfInitialDepositSavings.getText()));
});
}
else
{
//create Alert
}
btnRightOne.setOnAction((event) -> {
cancelAccountCreation();
});
btnLeftTwo.setOnAction(null);
btnLeftThree.setOnAction(null);
btnLeftFour.setOnAction(null);
btnRightTwo.setOnAction(null);
btnRightThree.setOnAction(null);
btnRightFour.setOnAction(null);
}
catch (IOException ex)
{
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void loadQWERTYKeyboard()
{
try
{
AnchorPane keyboardRoot = FXMLLoader.load(getClass().getResource("KeyboardQWERTY.fxml"));
System.out.println(keyboardRoot.getId());
spBottomDisplay.getChildren().add(keyboardRoot);
GridPane tempKeyboard = (GridPane)keyboardRoot.getChildren().get(0);
tempKeyboard.getChildren().stream().filter((tempNode)
-> (tempNode instanceof Button)).map((
tempNode) -> (Button) tempNode).forEachOrdered((tempButton) -> {
buttons.put(tempButton.getText().toLowerCase(), tempButton);
});
apMain.setOnKeyPressed((event) -> {
Button tempButton = buttons.get(event.getText());
if (tempButton != null) {
tempButton.arm();
tempButton.setStyle("-fx-background-color: blue");
}
else if (event.getCode().equals(KeyCode.ENTER)) {
tempButton = buttons.get("enter");
tempButton.arm();
tempButton.setStyle("-fx-background-color: blue");
}
else if (event.getCode().equals(KeyCode.BACK_SPACE)) {
tempButton = buttons.get("backspace");
tempButton.arm();
tempButton.setStyle("-fx-background-color: blue");
}
else if (event.getCode().equals(KeyCode.SPACE)) {
tempButton = buttons.get("space");
tempButton.arm();
tempButton.setStyle("-fx-background-color: blue");
}
});
apMain.setOnKeyReleased((event) -> {
System.out.println();
Button tempButton = buttons.get(event.getText());
System.out.println("Released key text: " + event.getText());
System.out.println("Released key code: " + event.getCode());
if (tempButton != null) {
tempButton.disarm();
tempButton.setStyle("");
}
else if (event.getCode().equals(KeyCode.ENTER)) {
tempButton = buttons.get("enter");
tempButton.disarm();
tempButton.setStyle("");
}
else if (event.getCode().equals(KeyCode.BACK_SPACE)) {
tempButton = buttons.get("backspace");
tempButton.disarm();
tempButton.setStyle("");
}
else if (event.getCode().equals(KeyCode.SPACE)) {
tempButton = buttons.get("space");
tempButton.disarm();
tempButton.setStyle("");
}
});
}
catch (IOException ex)
{
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
private Node findNodeByID(String id, ObservableList<Node> observableList)
{
for(Node node : observableList)
{
if(node.getId().equals(id))
{
System.out.println("node found!");
return node;
}
else
{
System.out.println("node not found yet!");
}
}
return null;
}
In this snippet of code I use two different approaches. In the loadQWERTYKeyboard methods is one approach. In the findNodeByID is the second approach. The full code is found here. Working but project not complete.
This answer is similar to the code you posted. This answer uses the same two ideas talked about in the original answer.
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication75 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();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="449.0" prefWidth="564.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication75.FXMLDocumentController">
<children>
<Button fx:id="btnMainBar" layoutX="76.0" layoutY="391.0" onAction="#handleButtonAction" text="Load Bar" />
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<Button fx:id="btnMainFoo" layoutX="419.0" layoutY="391.0" mnemonicParsing="false" onAction="#handleButtonAction" text="Load Foo" />
<AnchorPane fx:id="apMain" layoutX="161.0" layoutY="88.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="100.0" AnchorPane.leftAnchor="50.0" AnchorPane.rightAnchor="50.0" AnchorPane.topAnchor="25.0" />
</children>
</AnchorPane>
Controller
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
/**
*
* #author blj0011
*/
public class FXMLDocumentController implements Initializable
{
#FXML AnchorPane apMain;//This pane will be used to display the other two panes depending on which button is pressed.
//Foo Pane children nodes
Button btnFooOne, btnFooTwo;
TextField tfFooOne, tfFooTwo;
Label lblFoo;
//Bar Pane children nodes
Button btnBar;
TextField tfBar;
Label lblBar;
#FXML
private void handleButtonAction(ActionEvent event)
{
if(((Button)event.getSource()).getId().equals("btnMainBar"))
{
loadBarPane();
}
else if(((Button)event.getSource()).getId().equals("btnMainFoo"))
{
loadFooPane();
}
}
#Override
public void initialize(URL url, ResourceBundle rb)
{
// TODO
}
//This approach uses the findNodeByID method.
private void loadFooPane()
{
try
{
if(apMain.getChildren().size() > 0)
{
apMain.getChildren().remove(0);//if a node is loaded into apMain, remove the node.
}
Pane root = FXMLLoader.load(getClass().getResource("Foo.fxml"));
apMain.getChildren().add(root);//Add Foo Pane to apMain
//Get Foo Pane's children nodes
tfFooOne = (TextField)findNodeByID("tfFooOne", root.getChildren());
tfFooTwo = (TextField)findNodeByID("tfFooTwo", root.getChildren());
btnFooOne = (Button)findNodeByID("btnFooOne", root.getChildren());
btnFooTwo = (Button)findNodeByID("btnFooTwo", root.getChildren());
lblFoo = (Label)findNodeByID("lblFoo", root.getChildren());
//Set Listeners
tfFooOne.textProperty().addListener((obserValue, oldValue, newValue) -> {
lblFoo.setText("new value: " + newValue);
});
tfFooTwo.textProperty().addListener((obserValue, oldValue, newValue) -> {
lblFoo.setText("new value: " + newValue);
});
btnFooOne.setOnAction((event) -> {lblFoo.setText("You pressed btnFooOne");});
btnFooTwo.setOnAction((event) -> {lblFoo.setText("You pressed btnFooTwo");});
}
catch (IOException ex)
{
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void loadBarPane()
{
try
{
//This way is more complicate if you have more than one of the same type of node
if(apMain.getChildren().size() > 0)
{
apMain.getChildren().remove(0);//if a node is loaded into apMain, remove the node.
}
Pane root = FXMLLoader.load(getClass().getResource("Bar.fxml"));
apMain.getChildren().add(root);//Add Foo Pane to apMain
//Get Bar Pane's children nodes
for(Node node : root.getChildren())
{
if(node instanceof Button)
{
btnBar = (Button)node;
}
else if(node instanceof TextField)
{
tfBar = (TextField)node;
}
else if(node instanceof Label)
{
lblBar = (Label)node;
}
}
//Set listeners
tfBar.textProperty().addListener((obserValue, oldValue, newValue) -> {
lblBar.setText("new value: " + newValue);
});
btnBar.setOnAction((event) -> {lblBar.setText("You pressed btnFooOne");});
}
catch (IOException ex)
{
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
private Node findNodeByID(String id, ObservableList<Node> observableList)
{
for(Node node : observableList)
{
if(node.getId().equals(id))
{
System.out.println("node found!");
return node;
}
else
{
System.out.println("node not found yet!");
}
}
return null;
}
}
Foo FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.Pane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="324.0" prefWidth="464.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button fx:id="btnFooOne" layoutX="84.0" layoutY="209.0" mnemonicParsing="false" text="Button" />
<Button fx:id="btnFooTwo" layoutX="329.0" layoutY="209.0" mnemonicParsing="false" text="Button" />
<TextField fx:id="tfFooOne" layoutX="36.0" layoutY="162.0" />
<TextField fx:id="tfFooTwo" layoutX="281.0" layoutY="162.0" />
<Label fx:id="lblFoo" layoutX="165.0" layoutY="39.0" text="You just loaded Foo Pane" />
</children>
</Pane>
Bar FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.Pane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="324.0" prefWidth="464.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button fx:id="btnBar" layoutX="206.0" layoutY="186.0" mnemonicParsing="false" text="Button" />
<TextField fx:id="tfBar" layoutX="158.0" layoutY="130.0" />
<Label fx:id="lblBar" layoutX="160.0" layoutY="65.0" text="You just loaded Bar Pane" />
</children>
</Pane>
I am trying to change the data of the StackedAreaChart dynamically. So I have created an fxml file and a controller for it.
fig.fxml
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="495.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.gollahalli.test.controller">
<children>
<StackedAreaChart fx:id="graph" layoutX="24.0" layoutY="95.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<xAxis>
<NumberAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</StackedAreaChart>
<TextField fx:id="number" layoutX="57.0" layoutY="39.0" />
<Button fx:id="button" layoutX="330.0" layoutY="39.0" mnemonicParsing="false" text="Button" />
</children>
</AnchorPane>
Controller.java
public class controller {
#FXML
private Button button;
#FXML
private TextField number;
#FXML
private StackedAreaChart<Number, Number> graph;
public void initialize(){
XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
button.setOnAction(event -> {
int number1 = Integer.parseInt(number.getText());
System.out.println(number1);
for (int i = 0; i < number1; i++) {
series.getData().addAll(new XYChart.Data(i, i));
}
graph.getData().add(series);
});
}
}
When I enter a number say 100, I am able to get the graph correctly, when I change the data say 101 and click on the button I get an error as Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Duplicate series added.
I do know that to overcome this I would have to use ObservableList, but I am not sure how to use it.
Now the question is, how should I change/refresh the data every time I click on the button?
The exception message is clear. To avoid it add series only once:
public void initialize(){
XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
// add series only once at init
graph.getData().add(series);
button.setOnAction(event -> {
int number1 = Integer.parseInt(number.getText());
System.out.println(number1);
// clear current data
series.getData().clear();
// add new data
for (int i = 0; i < number1; i++) {
series.getData().add(new XYChart.Data(i, i));
}
});
}
It has been so difficult for me to try and get an answer for this. Oracle doesn't document on their website for some reason?! It has been asked on stackoverflow already (JavaFX: TableView(fxml) filling with data, and JavaFX FXML table; why won't my data display), but when i try to recreate with the answers given, I am still unable to get it to work. I would be extremely grateful if someone would be able to help! I'll give out all the code of have put together.
public class Heroes extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
AnchorPane page = FXMLLoader.load(Heroes.class.getResource("FXMLDocument.fxml"));
Scene scene = new Scene(page);
primaryStage.setScene(scene);
primaryStage.setTitle("Sample Window");
primaryStage.setResizable(false);
primaryStage.show();
} catch (Exception e) {
}
}
}
public class FXMLDocumentController implements Initializable {
/**
* Initializes the controller class.
*/
#FXML
TableView<Table> tableID;
#FXML
TableColumn<Table, Integer> tID;
#FXML
TableColumn<Table, String> tName;
#FXML
TableColumn<Table, String> tDate;
#FXML
TableColumn<Table, String> tPrice;
int iNumber = 1;
ObservableList<Table> data =
FXCollections.observableArrayList(
new Table(iNumber++, "Superman", "12/02/2013", "20"),
new Table(iNumber++, "Batman", "2/02/2013", "40"),
new Table(iNumber++, "Aquaman", "1/02/2013", "100"),
new Table(iNumber++, "The Flash", "12/02/2013", "16"));
#Override
public void initialize(URL url, ResourceBundle rb) {
// System.out.println("called");
tID.setCellValueFactory(new PropertyValueFactory<Table, Integer>("rID"));
tName.setCellValueFactory(new PropertyValueFactory<Table, String>("rName"));
tDate.setCellValueFactory(new PropertyValueFactory<Table, String>("rDate"));
tPrice.setCellValueFactory(new PropertyValueFactory<Table, String>("rPrice"));
tableID.setItems(data);
}
}
public class Table {
SimpleIntegerProperty rID;
SimpleStringProperty rName;
SimpleStringProperty rDate;
SimpleStringProperty rPrice;
public Table(int rID, String rName, String rDate, String rPrice) {
this.rID = new SimpleIntegerProperty(rID);
this.rName = new SimpleStringProperty(rName);
this.rDate = new SimpleStringProperty(rDate);
this.rPrice = new SimpleStringProperty(rPrice);
System.out.println(rID);
System.out.println(rName);
System.out.println(rDate);
System.out.println(rPrice);
}
public Integer getrID() {
return rID.get();
}
public void setrID(Integer v) {
this.rID.set(v);
}
public String getrDate() {
return rDate.get();
}
public void setrDate(String d) {
this.rDate.set(d);
}
public String getrName() {
return rName.get();
}
public void setrName(String n) {
this.rDate.set(n);
}
public String getrPrice() {
return rPrice.get();
}
public void setrPrice(String p) {
this.rPrice.set(p);
}
}
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml" fx:controller="heroes.FXMLDocumentController">
<children>
<SplitPane dividerPositions="0.535175879396985" focusTraversable="true" orientation="VERTICAL" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<TableView fx:id="tableID" prefHeight="210.0" prefWidth="598.0" tableMenuButtonVisible="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn minWidth="20.0" prefWidth="40.0" text="ID" fx:id="tID" >
<cellValueFactory>
<PropertyValueFactory property="tID" />
</cellValueFactory>
</TableColumn>
<TableColumn prefWidth="100.0" text="Date" fx:id="tDate" >
<cellValueFactory>
<PropertyValueFactory property="tDate" />
</cellValueFactory>
</TableColumn>
<TableColumn prefWidth="200.0" text="Name" fx:id="tName" >
<cellValueFactory>
<PropertyValueFactory property="tName" />
</cellValueFactory>
</TableColumn>
<TableColumn prefWidth="75.0" text="Price" fx:id="tPrice" >
<cellValueFactory>
<PropertyValueFactory property="tPrice" />
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0" />
</items>
</SplitPane>
</children>
</AnchorPane>
The PropertyValueFactory tries to find your data values in two ways:
1) Looking for a method e.g. nameProperty where name is what you specify in the constructor, in your example e.g. "rID".
Thus you need to a methods named like this (name of the field + "Property"):
public IntegerProperty rIDProperty() {
return rID;
}
And similar for your other properties.
2) If these aren't present, it looks for methods named e.g. getName where Name is what you specifiy in the constructor with the first letter capitalized (following the Java Beans convention).
In your example you don't have 1) but you seem to have 2) - but you haven't capitalized the first letter of the property name in the getters and setters!
So change these to e.g.
public Integer getRID() {
return rID.get();
}
And similar.
You need either 1) or 2) but it would be good practice to have both.
Also note that the problem is not related to FXML in any way.