I'm trying to adapt a Chart model (lineChart) with JavaFX, at first based on this link model:
https://docs.oracle.com/javafx/2/charts/line-chart.htm
My problem is showing the X-Axis values (Months in my case)
I've tried to make it more dynamic, based on these other links, but it still didn't work ...
//JavaFX Adding multiple XYChart.Series to LineChart without explicating declaring each series
//How to plot multiple series with javafx line chart which is in array list
Finally, based on this link, I was able to build a dynamic graph, which creates series to represent Month / Year of a collection movement:
//Is it possible to create an array of XYChart.Series on JavaFX?
I have a "small" detail that I couldn't solve yet, the models are created "scene" directly, without XML, this way it works normal.
But I would like to create with XML (I am using the Scene Builder to assemble the XML), to put more details on the screen, such as a TableView, etc.
As I mentioned above, the problem is that when I use the graph with XML, it does not show the values of the X Axis (Months in my case) it is "all in one column" ...
I hope you managed to explain ... I will leave the example that trying to adapt here, any help, thank you in advance.
I'll leave the sample program (simpler, not the one that assembles dynamically, to try to illustrate better).
"Scene" call class
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class LineChartExemplo extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
FXML file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.chart.CategoryAxis?>
<?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="579.0" prefWidth="918.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.171" fx:controller="linechartexemplo.FXMLDocumentController">
<children>
<Button fx:id="button" layoutX="14.0" layoutY="14.0" onAction="#handleButtonAction" text="Visualizar Gráfico" />
<Label fx:id="label" layoutX="135.0" layoutY="14.0" minHeight="16" minWidth="69" prefHeight="25.0" prefWidth="710.0" />
<LineChart fx:id="lineChart" layoutX="14.0" layoutY="52.0" prefHeight="512.0" prefWidth="887.0" title="Exemplo Gŕafico">
<xAxis>
<CategoryAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</LineChart>
</children>
</AnchorPane>
Controller class
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Label;
public class FXMLDocumentController implements Initializable {
#FXML private Label label;
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
//final LineChart<String,Number> lineChart = new LineChart<String,Number>(xAxis,yAxis);
//#FXML private LineChart<String, Number> lineChart;
#FXML private LineChart<String, Number> lineChart = new LineChart<String,Number>(xAxis,yAxis);
#FXML
private void handleButtonAction(ActionEvent event) {
label.setText("Teste Gráfico...");
visualizaGrafico();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
private void visualizaGrafico(){
lineChart.setTitle("Exemplo Gráfico");
yAxis.setLabel("Valores");
xAxis.setLabel("Meses");
XYChart.Series series = new XYChart.Series();
series.setName("Ano: 2018");
series.getData().add(new XYChart.Data("Jan", 23));
series.getData().add(new XYChart.Data("Feb", 14));
series.getData().add(new XYChart.Data("Mar", 15));
series.getData().add(new XYChart.Data("Apr", 24));
series.getData().add(new XYChart.Data("May", 34));
series.getData().add(new XYChart.Data("Jun", 36));
series.getData().add(new XYChart.Data("Jul", 22));
series.getData().add(new XYChart.Data("Aug", 45));
series.getData().add(new XYChart.Data("Sep", 43));
series.getData().add(new XYChart.Data("Oct", 17));
series.getData().add(new XYChart.Data("Nov", 29));
series.getData().add(new XYChart.Data("Dec", 25));
XYChart.Series series2 = new XYChart.Series();
series2.setName("Ano: 2019");
series2.getData().add(new XYChart.Data("Jan", 28));
series2.getData().add(new XYChart.Data("Feb", 17));
series2.getData().add(new XYChart.Data("Mar", 19));
series2.getData().add(new XYChart.Data("Apr", 14));
series2.getData().add(new XYChart.Data("May", 20));
series2.getData().add(new XYChart.Data("Jun", 42));
series2.getData().add(new XYChart.Data("Jul", 27));
series2.getData().add(new XYChart.Data("Aug", 48));
series2.getData().add(new XYChart.Data("Sep", 47));
series2.getData().add(new XYChart.Data("Oct", 19));
series2.getData().add(new XYChart.Data("Nov", 39));
series2.getData().add(new XYChart.Data("Dec", 29));
lineChart.getData().addAll(series, series2);
}
}
Print the chart to better illustrate.
Graph without using XML (OK with Database)
It looks like there is a bug somewhere that prevents this working properly when the chart is animated. Turn off animation in the chart with
#Override
public void initialize(URL url, ResourceBundle rb) {
lineChart.setAnimated(false);
}
There are additional issues with your code:
Never initialize fields annotated #FXML in your controller. The objects these fields are supposed to refer to are created according to the FXML code by the FXMLLoader, and are initialized in the controller by injection.
It's also unclear why you are creating a second set of axes in the controller, when you have already defined the axes in the FXML file.
Replace this code:
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
#FXML private LineChart<String, Number> lineChart = new LineChart<String,Number>(xAxis,yAxis);
with
#FXML private CategoryAxis xAxis ;
#FXML private NumberAxis yAxis ;
#FXML private LineChart<String, Number> lineChart ;
and add fx:ids to the axes in the FXML file so that they are properly injected into the controller:
<LineChart fx:id="lineChart" layoutX="14.0" layoutY="52.0" prefHeight="512.0" prefWidth="887.0" title="Exemplo Gŕafico">
<xAxis>
<CategoryAxis fx:id="xAxis" side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis fx:id="yAxis" side="LEFT" />
</yAxis>
</LineChart>
I'll put the solution code here, it can be useful for other people later.
I'm using SQL Server for Database (2012) and NetBeanas to develop ...
Class to start the scene
package graficos;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Graficos extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLGraficos.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
FXMLGraficos File
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.chart.BarChart?>
<?import javafx.scene.chart.CategoryAxis?>
<?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.chart.PieChart?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.DatePicker?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.effect.DropShadow?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="701.0" prefWidth="1407.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="graficos.FXMLGraficosController">
<children>
<AnchorPane layoutX="7.0" layoutY="152.0" prefHeight="254.0" prefWidth="361.0" style="-fx-background-color: #F5F5F5;">
<children>
<PieChart fx:id="pieChart" layoutX="7.0" prefHeight="254.0" prefWidth="355.0" title="Gráfico Movimento" />
</children>
<effect>
<DropShadow />
</effect>
</AnchorPane>
<AnchorPane layoutX="6.0" layoutY="14.0" prefHeight="131.0" prefWidth="363.0" style="-fx-background-color: #F5F5F5;">
<effect>
<DropShadow />
</effect>
<children>
<DatePicker fx:id="dtpInicial" layoutX="5.0" layoutY="43.0" prefHeight="25.0" prefWidth="106.0" />
<Label layoutX="5.0" layoutY="24.0" text="Data Inicial:" />
<DatePicker fx:id="dtpFinal" layoutX="124.0" layoutY="43.0" prefHeight="25.0" prefWidth="106.0" />
<Label layoutX="124.0" layoutY="24.0" text="Data Final:" />
<Button fx:id="btnOK" layoutX="247.0" layoutY="43.0" mnemonicParsing="false" onAction="#verificaData" prefHeight="34.0" prefWidth="61.0" text="OK" />
<Label fx:id="lblData" layoutX="12.0" layoutY="86.0" prefHeight="26.0" prefWidth="296.0" text="-" />
</children>
</AnchorPane>
<AnchorPane layoutX="7.0" layoutY="417.0" prefHeight="271.0" prefWidth="363.0" style="-fx-background-color: #F5F5F5;">
<effect>
<DropShadow />
</effect>
<children>
<BarChart fx:id="barChart" prefHeight="271.0" prefWidth="363.0" title="Gráfico Movimento">
<xAxis>
<CategoryAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</BarChart>
</children>
</AnchorPane>
<AnchorPane layoutX="379.0" layoutY="153.0" prefHeight="535.0" prefWidth="975.0" style="-fx-background-color: #F5F5F5;">
<effect>
<DropShadow />
</effect>
<children>
<LineChart fx:id="lineChart" layoutX="-2.0" prefHeight="535.0" prefWidth="968.0">
<xAxis>
<CategoryAxis side="BOTTOM" fx:id="xAxis" />
</xAxis>
<yAxis>
<NumberAxis fx:id="yAxis" side="LEFT" />
</yAxis>
</LineChart>
</children>
</AnchorPane>
<AnchorPane layoutX="379.0" layoutY="14.0" prefHeight="131.0" prefWidth="975.0" style="-fx-background-color: #F5F5F5;">
<effect>
<DropShadow />
</effect>
<children>
<TableView prefHeight="131.0" prefWidth="975.0">
<columns>
<TableColumn prefWidth="62.0" text="Janeiro" />
<TableColumn prefWidth="72.0" text="Fevereiro" />
<TableColumn prefWidth="79.0" text="Março" />
<TableColumn prefWidth="79.0" text="Abril" />
<TableColumn prefWidth="76.0" text="Maio" />
<TableColumn prefWidth="87.0" text="Junho" />
<TableColumn prefWidth="89.0" text="Julho" />
<TableColumn prefWidth="87.0" text="Agosto" />
<TableColumn prefWidth="83.0" text="Setembro" />
<TableColumn minWidth="0.0" prefWidth="81.0" text="Outubro" />
<TableColumn minWidth="0.0" prefWidth="79.0" text="Novembro" />
<TableColumn prefWidth="115.0" text="Dezembro" />
</columns>
</TableView>
</children>
</AnchorPane>
</children>
</AnchorPane>
FXMLGraficosController class
package graficos;
import Utilitarios.ConexaoBD;
import java.net.URL;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.ResourceBundle;
import java.util.stream.Stream;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javax.swing.JOptionPane;
public class FXMLGraficosController implements Initializable {
#FXML private DatePicker dtpInicial;
#FXML private DatePicker dtpFinal;
#FXML private Button btnOK;
#FXML private PieChart pieChart;
#FXML private BarChart<String, Double> barChart;
#FXML private LineChart<String, Number> lineChart;
#FXML private Label lblData;
ObservableList<PieChart.Data> pieChartData;
ObservableList<PieChart.Data> lineChartData;
//ArrayList<Integer> cell = new ArrayList<Integer>();
//ArrayList<String> name = new ArrayList<String>();
ConexaoBD connBD;
#Override
public void initialize(URL url, ResourceBundle rb) {
connBD = new ConexaoBD();
dtpInicial.setValue(LocalDate.now());
dtpFinal.setValue(LocalDate.now());
}
public void verificaData(javafx.event.ActionEvent event){
//String sData = dtpInicial.getValue().format(DateTimeFormatter.ofPattern("yyyy-mm-dd"));
java.sql.Date dDataIni = java.sql.Date.valueOf(dtpInicial.getValue());
java.sql.Date dDataFim = java.sql.Date.valueOf(dtpFinal.getValue());
String sDataIni = formataDataStr(dDataIni,1);
String sDataFim = formataDataStr(dDataFim,1);
lblData.setText("Período : " + sDataIni + " à " + sDataFim);
graficoPizza(sDataIni, sDataFim);
graficoLinhas(sDataIni, sDataFim);
}
public void graficoPizza(String sDataIni, String sDataFim){
String strSQL = null;
strSQL = " SELECT 'Boleto' AS Doacao, 'Valor' = COUNT(*)" +
" FROM BOLETO B " +
" WHERE B.BOLDATAVEN BETWEEN '"+sDataIni+"' AND '"+sDataFim+"' ";
strSQL = strSQL + " UNION ALL";
strSQL = strSQL + " SELECT 'Recibo' AS Doacao, 'Valor' = COUNT(*)" +
" FROM RECIBO R " +
" WHERE R.RECDATAVEN BETWEEN '"+sDataIni+"' AND '"+sDataFim+"' ";
strSQL = strSQL + " UNION ALL";
strSQL = strSQL + " SELECT 'Debito' AS Doacao, 'Valor' = COUNT(*)" +
" FROM DEBITO D " +
" WHERE D.DEBDATAVEN BETWEEN '"+sDataIni+"' AND '"+sDataFim+"' ";
pieChartData = FXCollections.observableArrayList();
try {
connBD.conectaBD();
} catch (ClassNotFoundException ex) {
JOptionPane.showMessageDialog(null, "Erro ao Conectar Banco de Dados - ERRO :" + ex.getMessage());
}
try {
connBD.executaSQL(strSQL); //Conecta no Banco conforme Parametro passado
if (connBD.rs.isBeforeFirst()){
while (connBD.rs.next()){
pieChartData.add(new PieChart.Data(connBD.rs.getString("Doacao"), connBD.rs.getInt("Valor")));
//name.add(connBD.rs.getString("Doacao"));
//cell.add(connBD.rs.getInt("Valor"));
System.out.println(connBD.rs.getString("Doacao") + " - " +connBD.rs.getString("Valor"));
}
}
pieChart.setData(pieChartData);
connBD.desconectaBD();
} catch (SQLException ex) {
JOptionPane.showMessageDialog(null, "Erro ao Carregar Dados para Alteração!\n" + ex.getMessage());
}
}
public void graficoLinhas(String sDataIni, String sDataFim){
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Meses");
yAxis.setLabel("Valores");
lineChart.getData().clear();
ArrayList arrayAno = new ArrayList();
String sSQL = null;
sSQL = montaStrSQL(sDataIni, sDataFim);
try {
connBD.conectaBD();
} catch (ClassNotFoundException ex) {
JOptionPane.showMessageDialog(null, "Erro ao Conectar Banco de Dados - ERRO :" + ex.getMessage());
}
try {
connBD.executaSQL(sSQL); //Conecta no Banco conforme Parametro passado
if (connBD.rs.isBeforeFirst()){
try {
connBD.rs.beforeFirst();
while (connBD.rs.next()){
if(!arrayAno.contains(connBD.rs.getString("Ano"))){
arrayAno.add(connBD.rs.getString("Ano"));
System.out.println(connBD.rs.getString("Ano"));
}
}
connBD.rs.beforeFirst();
} catch (SQLException ex) {
JOptionPane.showMessageDialog(null, "Erro ao Carregar Dados para Alteração!\n" + ex.getMessage());
}
XYChart.Series<String, Number>[] seriesArray = Stream.<XYChart.Series<String, Number>>generate(XYChart.Series::new).limit(arrayAno.size()).toArray(XYChart.Series[]::new);
for (int i = 0; i < arrayAno.size(); i++) {
try {
while (connBD.rs.next() && connBD.rs.getString("Ano").equals(arrayAno.get(i).toString())){
seriesArray[i].getData().add(new XYChart.Data(retornaMes(connBD.rs.getInt("Mes")), connBD.rs.getInt("Qtde")));
System.out.println(connBD.rs.getString("Ano") + " - " + connBD.rs.getString("Mes") + " - " + connBD.rs.getString("Qtde"));
}
seriesArray[i].setName("Ano: " + arrayAno.get(i).toString());
lineChart.getData().add(seriesArray[i]);
if (!connBD.rs.isLast())
connBD.rs.previous();
} catch (SQLException ex) {
JOptionPane.showMessageDialog(null, "Erro ao Carregar Dados para Alteração!\n" + ex.getMessage());
}
}
}
connBD.desconectaBD();
} catch (SQLException ex) {
JOptionPane.showMessageDialog(null, "Erro ao Carregar Dados para Alteração!\n" + ex.getMessage());
}
}
private String montaStrSQL(String sDataI, String sDataF){
String strSQL = null;
strSQL = "SELECT ANO, MES, SUM(QTDE) AS QTDE FROM (";
strSQL = strSQL + " SELECT 'Ano' = YEAR(B.BOLDATAVEN), 'Mes' = MONTH(B.BOLDATAVEN), 'Qtde' = COUNT(*)" +
" FROM BOLETO B " +
" WHERE B.BOLDATAVEN BETWEEN '"+sDataI+"' AND '"+sDataF+"' ";
strSQL = strSQL + " GROUP BY YEAR(B.BOLDATAVEN), MONTH(B.BOLDATAVEN)";
strSQL = strSQL + " UNION ALL";
strSQL = strSQL + " SELECT 'Ano' = YEAR(R.RECDATAVEN), 'Mes' = MONTH(R.RECDATAVEN), 'Qtde' = COUNT(*)" +
" FROM RECIBO R " +
" WHERE R.RECDATAVEN BETWEEN '"+sDataI+"' AND '"+sDataF+"' ";
strSQL = strSQL + " GROUP BY YEAR(R.RECDATAVEN), MONTH(R.RECDATAVEN)";
strSQL = strSQL + " UNION ALL";
strSQL = strSQL + " SELECT 'Ano' = YEAR(D.DEBDATAVEN), 'Mes' = MONTH(D.DEBDATAVEN), 'Qtde' = COUNT(*)" +
" FROM DEBITO D " +
" WHERE D.DEBDATAVEN BETWEEN '"+sDataI+"' AND '"+sDataF+"' ";
strSQL = strSQL + " GROUP BY YEAR(D.DEBDATAVEN), MONTH(D.DEBDATAVEN)";
strSQL = strSQL + ")Resultado";
strSQL = strSQL + " GROUP BY Resultado.ANO, Resultado.MES" ;
strSQL = strSQL + " ORDER BY Resultado.ANO, Resultado.MES" ;
return strSQL;
}
private String retornaMes(int iMes){
String sMes = null;
if (iMes == 1) sMes = "Jan";
else if (iMes == 2) sMes = "Fev";
else if (iMes == 3) sMes = "Mar";
else if (iMes == 4) sMes = "Abr";
else if (iMes == 5) sMes = "Mai";
else if (iMes == 6) sMes = "Jun";
else if (iMes == 7) sMes = "Jul";
else if (iMes == 8) sMes = "Ago";
else if (iMes == 9) sMes = "Set";
else if (iMes == 10) sMes = "Out";
else if (iMes == 11) sMes = "Nov";
else if (iMes == 12) sMes = "Dez";
return sMes;
}
public String formataDataStr(Date dData, int iOpc){
if (dData != null){
//JOptionPane.showMessageDialog(null, "Validando Data...");
SimpleDateFormat sdf;
switch (iOpc) {
case 1:
sdf = new SimpleDateFormat("yyyy-MM-dd");
break;
case 2:
sdf = new SimpleDateFormat("dd-MM-yyyy");
break;
default:
sdf = new SimpleDateFormat("dd/MM/yyyy");
break;
}
String sDataFormat = sdf.format(dData);
return sDataFormat;
} else {
//JOptionPane.showMessageDialog(null, "Retorno data vazio...");
return "";
}
}
}
BD class
package Utilitarios;
import java.sql.*;
import javax.swing.JOptionPane;
public class ConexaoBD {
public Connection conn = null;
public Statement stm = null;
public ResultSet rs = null;
private final String driverDB = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; //Nome do Driver conforme o BD a ser utilizado
private final String strDB = "jdbc:sqlserver://"; //String para montar Url Banco
private final String strIP = "XXX.X.XX.XX"; //IP do Servidor
private final String portaDB = ":1433;"; //Porta para montar Url Banco
private String nomeDB = "yourBD"; /Nome do Banco de Dados
private String usuarioDB = "youUSer"; //**
private String senhaDB = "yourPassword"; //**
private String connectionUrl = null;
public void conectaBD() throws ClassNotFoundException{ //Inicia Construtor
try {
try {
Class.forName(driverDB);
connectionUrl = strDB + strIP + portaDB + "databaseName=" + nomeDB + ";user=" + usuarioDB + ";password=" + senhaDB;
conn = DriverManager.getConnection(connectionUrl);
stm = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "Erro ao Carregar Arquivo Configurações BD (ConexaoBD: conectaBD()):\n"+ex.getMessage());
}
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "Erro Conexão BD - IP:\n"+ex.getMessage());
}
}
public void desconectaBD(){
try {
conn.close();
} catch (SQLException ex) {
JOptionPane.showMessageDialog(null, "Erro ao Desconectar Banco de Dados (ConexaoBD: desconectaBD())\n"+ex.getMessage());
}
}
public void executaSQL(String strSQL){
try {
rs = stm.executeQuery(strSQL);
} catch (SQLException ex) {
JOptionPane.showMessageDialog(null, "Erro na Execução SQL (ConexaoBD: executaSQL())\n Erro: "+ex.getMessage() );
}
}
}
And the print of the execution ... now I can continue with the part of filling in the tablewiews, etc ...
Thank you all!
Related
This is my first time using Derby database and I am having trouble adding information into my tableview.
public class AddController implements Initializable {
final String DB_URL = "jdbc:derby:StudentDB;";
#FXML TableView<Student> studentListView;
#FXML TableColumn stuName;
#FXML TableColumn stuAge;
#FXML TableColumn stuMajor;
#FXML TableColumn stuGPA;
#FXML ComboBox ageCB;
#FXML ComboBox majorCB;
#FXML ComboBox gpaCB;
ObservableList<Student> studentList;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
studentList = FXCollections.observableArrayList();
createDB();
createStudentsDB();
studentListView.setItems(studentList);
}
public void createDB(){
try
{
Connection conn = DriverManager.getConnection("jdbc:derby:StudentDB;create=true");
conn.close();
System.out.println("Connection successful");
}
catch(Exception ex)
{
System.out.println("ERROR: " + ex.getMessage());
}
}
public void createStudentsDB(){
try{
Connection conn = DriverManager.getConnection(DB_URL);
Statement stmt = conn.createStatement();
stmt.execute("DROP TABLE Student");
stmt.execute("CREATE TABLE Student (" +
"Name CHAR(25), " +
"Age INT, " +
"Major CHAR(45), " +
"GPA DECIMAL, ");
String sql = "INSERT INTO Student VALUES" +
"('Robert', 21, 'Computer Information Systems', 3.8)";
stmt.executeUpdate(sql);
String sqlStatement = "SELECT Name, Age, Major, GPA FROM Student";
ResultSet result = stmt.executeQuery(sqlStatement);
ObservableList<Student> studentList = FXCollections.observableArrayList();
while (result.next())
{
Student newStudent = new Student();
newStudent.name = result.getString("Name");
newStudent.age = result.getInt("Age");
newStudent.major = result.getString("Major");
newStudent.gpa = result.getDouble("GPA");
studentList.add(newStudent);
}
stmt.close();
conn.close();
}
catch (Exception ex)
{
var msg = ex.getMessage();
System.out.println(msg);
}
}
<TableView fx:id="studentListView" prefWidth="400">
<columns>
<TableColumn fx:id="stuName" text="Student" prefWidth="125"/>
<TableColumn fx:id="stuAge" text="Age" prefWidth="75"/>
<TableColumn fx:id="stuMajor" text="Major" prefWidth="125"/>
<TableColumn fx:id="stuGPA" text="GPA" prefWidth="75"/>
</columns>
</TableView>
I already created a TableView in FXML with the 4 columns I want. I just do not know how to get the information from the database to the TableView.
This code reads from a Derby Database the table is named Parent
We are using a MVC Model View Controller Pattern
And we strongly suggest you use the MVC concept when working with any database
private void ReadFromParent() throws SQLException{
ObservableList<ParentModel> TableData = FXCollections.observableArrayList();
stmnt = conn.createStatement();
ResultSet rs = stmnt.executeQuery("SELECT * FROM Parent");
while (rs.next()){// Add data to observableArrayList TableData to select a table ROW
TableData.add(new ParentModel(rs.getString("PID"),rs.getString("pMonth"),rs.getString("pYear")));
}
PropertyValueFactory<ParentModel, String> IDCellValueFactory = new PropertyValueFactory<>("PID");
colID.setCellValueFactory(IDCellValueFactory);
PropertyValueFactory<ParentModel, String> DateCellValueFactory = new PropertyValueFactory<>("pMonth");
colMonth.setCellValueFactory(DateCellValueFactory);
PropertyValueFactory<ParentModel, String> TypeCellValueFactory = new PropertyValueFactory<>("pYear");
colYear.setCellValueFactory(TypeCellValueFactory);
// ================================================================
// colTxDate are the ID's for the tableview columns
// sortDate are the Column Names for the Database TABLE CDBalance
// ================================================================
colMonth.setStyle("-fx-alignment: CENTER;");
colYear.setStyle("-fx-alignment:CENTER;");
Collections.sort(TableData, (p2, p1)-> p1.getPID().compareToIgnoreCase(p2.getPID()));
// Line of Code above Sorts Database Columns based on VARIABLE in ParentModel
// Change p2,p1 to sort Ascending or Descending
if(TableData.size() < 15) {// Format TableView to display Vertical ScrollBar
ptable.setPrefWidth(336);// 19 is the off set
}else {
ptable.setPrefWidth(355);
} ptable.setItems(TableData);
stmnt.close();
}
grid stays null when user clicks the button that calls 'pressLookUp' User is suppose to go from an old stage to the new one in the fxml file. And before the new window is shown, I want to add in values to the grids children from the database using grid.add(node, colIndex, rowIndex)
Controller:
package login;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import userGroups.User;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class studentOptionsController{
#FXML
private GridPane grid;//gridpane from ClassesToAdd
public void pressLookUp(ActionEvent event) throws IOException{
Parent userOption = FXMLLoader.load(getClass().getResource("ClassesToAdd.fxml"));
Scene classesToAddScene = new Scene(userOption);
Stage app_stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
app_stage.setScene(classesToAddScene);
app_stage.show();
Connection c = null;
Statement stmt = null;
try{
c = DriverManager.getConnection("jdbc:sqlite:users.db");
c.setAutoCommit(false);
System.out.println("Opened database successfully");
stmt = c.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM Classes WHERE IDCLASSES= " + "5;");
int currentIndex = 0;
int currentRow = 0;
//assusming all columns are NOT NULL
while(rs.next()){
Label currentLabel = new Label();
currentLabel.setText(rs.getString("CLASSNAME"));
System.out.println(currentLabel.getText());
grid.add(currentLabel, 5, 0 );
/*if (rs.getString("SUSERNAME") != null && rs.getString("STUDENTPASS") != null){
String username = rs.getString("SUSERNAME");
System.out.println( "SUSERNAME = " + username );
String password = rs.getString("STUDENTPASS");
System.out.println("STUDENTPASS = " + password);
}*/
}
rs.close();
stmt.close();
c.close();
} catch ( Exception e ){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
//System.exit(0);
}
System.out.println("Operation done successfully");
}
}
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane fx:id="grid" prefHeight="400.0" prefWidth="850"
xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="login.studentOptionsController">
<columnConstraints>
<ColumnConstraints percentWidth="11" />
<ColumnConstraints percentWidth="11" />
<ColumnConstraints percentWidth="11" />
<ColumnConstraints percentWidth="11" />
<ColumnConstraints percentWidth="11" />
<ColumnConstraints percentWidth="11" />
<ColumnConstraints percentWidth="11" />
<ColumnConstraints percentWidth="11" />
<ColumnConstraints percentWidth="12" /> <!-- This column for 'Add
Class' buttons ?-->
</columnConstraints>
<rowConstraints>
<RowConstraints />
</rowConstraints>
<children>
<Label maxHeight="Infinity" maxWidth="Infinity" style=" -fx-border-color:gray; " text="Class Name" GridPane.columnIndex="0" GridPane.rowIndex="0" />
<Label maxHeight="Infinity" maxWidth="Infinity" style=" -fx-border-color:gray; " text="Size of Class" GridPane.columnIndex="1" GridPane.rowIndex="0" />
<Label maxHeight="Infinity" maxWidth="Infinity" style=" -fx-border-color:gray; " text="Spots Taken" GridPane.columnIndex="2" GridPane.rowIndex="0" />
<Label maxHeight="Infinity" maxWidth="Infinity" style=" -fx-border-color:gray; " text="Instructor" GridPane.columnIndex="3" GridPane.rowIndex="0" />
<Label maxHeight="Infinity" maxWidth="Infinity" style=" -fx-border-color:gray; " text="CRN" GridPane.columnIndex="4" GridPane.rowIndex="0" />
<Label maxHeight="Infinity" maxWidth="Infinity" style=" -fx-border-color:gray; " text="Days" GridPane.columnIndex="5" GridPane.rowIndex="0" />
<Label maxHeight="Infinity" maxWidth="Infinity" style=" -fx-border-color:gray; " text="Time" GridPane.columnIndex="6" GridPane.rowIndex="0" />
<Label maxHeight="Infinity" maxWidth="Infinity" style=" -fx-border-color:gray; " text="Subject" GridPane.columnIndex="7" GridPane.rowIndex="0" />
<Button maxHeight="Infinity" maxWidth="Infinity" mnemonicParsing="false" onAction="#pressBack" style=" -fx-background-color:red; -fx-border-color:black" text="Back..." GridPane.columnIndex="8" GridPane.rowIndex="0" />
</children>
</GridPane>
Output on system:
Opened database successfully
java.lang.NullPointerException: null
Operation done successfully
No clue why this works but it does.
public void pressLookUp(ActionEvent event) throws IOException{
FXMLLoader loader = new FXMLLoader(getClass().getResource("ClassesToAdd.fxml"));
Parent userOption = loader.load();
grid = loader.getRoot();
Scene classesToAddScene = new Scene(userOption);
Stage app_stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
app_stage.setScene(classesToAddScene);
app_stage.show();
Connection c = null;
Statement stmt = null;
try{
c = DriverManager.getConnection("jdbc:sqlite:users.db");
c.setAutoCommit(false);
System.out.println("Opened database successfully");
stmt = c.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM Classes WHERE IDCLASSES= " + "5;");
int currentIndex = 0;
int currentRow = 0;
//assusming all columns are NOT NULL
while(rs.next()){
Label currentLabel = new Label();
currentLabel.setText(rs.getString("CLASSNAME"));
System.out.println(currentLabel.getText());
grid.add(currentLabel, 0, 1 );
}
loader.setRoot(grid);
rs.close();
stmt.close();
c.close();
} catch ( Exception e ){
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
System.exit(0);
}
System.out.println("Operation done successfully");
}
After looking at Trouble inserting data in a SQLite databae, I tried to add 'c.commit();' before I leave the stage and closing the connection c. However it keeps giving me busy for some reason. Don't know if the dynamically added buttons 'addClass' are causing problems with the on action event handlers or not.
the controller file:
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
import userGroups.Student;
import java.io.IOException;
import java.sql.*;
public class ClassesController{
private Student user;
#FXML
private GridPane grid;
private int currentId;
private Connection c;
public void initialize(){
Statement stmt;
try{
c = DriverManager.getConnection("jdbc:sqlite:users.db");
//c.setAutoCommit(false);
stmt = c.createStatement();
int currentCol = 0;
int currentRow = 1;
currentId = 1;
ResultSet rs = stmt.executeQuery("SELECT * FROM Classes;");
//assuming all columns are NOT NULL
while(rs.next()){
Label label1 = new Label();
label1.setText(rs.getString("CLASSNAME"));
label1.setAccessibleText(rs.getString("CLASSNAME"));
grid.add(label1, currentCol++, currentRow);
Label label2 = new Label();
label2.setText(rs.getString("SIZE"));
grid.add(label2, currentCol++, currentRow);
Label label3 = new Label();
label3.setText(rs.getString("SPOTSTAKEN"));
grid.add(label3, currentCol++, currentRow);
Label label4 = new Label();
label4.setText(rs.getString("INSTRUCTOR"));
grid.add(label4, currentCol++, currentRow);
Label label5 = new Label();
label5.setText(rs.getString("CRN"));
label5.setTextAlignment(TextAlignment.CENTER);
grid.add(label5, currentCol++, currentRow);
Label label6 = new Label();
label6.setText(rs.getString("DAYS"));
grid.add(label6, currentCol++, currentRow);
Label label7 = new Label();
label7.setText(militaryToRegularTime(rs.getString("STARTTIME")) + "-"
+ militaryToRegularTime(rs.getString("ENDTIME")));
grid.add(label7, currentCol++, currentRow);
Label label8 = new Label();
label8.setText(rs.getString("AREA"));
grid.add(label8, currentCol++, currentRow);
Button addClass = new Button();
addClass.setMaxWidth(Double.MAX_VALUE);
addClass.setText("Add Class");
grid.add(addClass, currentCol, currentRow);
addClass.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e){
Object[] a = addClass.getProperties().values().toArray();//array of row and col values of addClass
int classIndex = Integer.parseInt(a[1].toString());//index of class corresponding to the button
String className = grid.getChildren().get(classIndex * 9).getAccessibleText();
if(studentHasClass(classIndex))//finds if student has the class at specific row of button
User.showAlert("You have already added this class!");
else
addClassToUser(classIndex, className);
addClass.setDisable(true);
}
});
currentCol = 0;
currentRow++;
currentId++;
}
rs.close();
stmt.close();
} catch ( Exception e ){
e.printStackTrace();
User.showAlert("Please contact the admin.");
System.exit(0);
}
}
//adds class at classIndex to student user in database in table CLASSES_HAVE_STUDENTS
private void addClassToUser(int classIndex, String className){
try{
PreparedStatement statement = c.prepareStatement(
"INSERT INTO CLASSES_HAVE_STUDENTS (CLASS_ID, CLASS_NAME, STUDENT_ID, S_USERNAME) VALUES(?,?,?,?)");
statement.setInt(1, classIndex);
statement.setString(2, className);
statement.setInt(3, user.getId());
statement.setString(4, user.getUserName());
statement.executeUpdate();
c.commit();
statement.close();
} catch ( Exception e ){
e.printStackTrace();
User.showAlert("Please contact the admin.");
System.exit(0);
}
}
//Return a boolean where if student user has a class at id
private boolean studentHasClass(int classIndex){
Statement stmt;
try{
stmt = c.createStatement();
ResultSet rs = stmt.executeQuery("SELECT S_USERNAME FROM CLASSES_HAVE_STUDENTS WHERE CLASS_ID= " + classIndex + ";");
while(rs.next()){
if(rs.getString("S_USERNAME").equals(user.getUserName())){
rs.close();
stmt.close();
return true;
}
}
rs.close();
stmt.close();
} catch ( Exception e ){
e.printStackTrace();
User.showAlert("Please contact an admin.");
System.exit(0);
}
return false;
}
//assumes militaryTime is in '00:00:00' format. returns regular time in '00:00' format
private String militaryToRegularTime(String militaryTime)
{
Integer hour = Integer.parseInt(militaryTime.substring(0, 2));
if(hour > 12){
hour = hour - 12;
return "0" + hour.toString() + militaryTime.substring(2, 5) + " pm";
}
return militaryTime.substring(0, 5) + " am";
}
//Changes stage to the previous stage
public void pressBack(ActionEvent event) throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("studentOptions.fxml"));
loader.load();
StudentOptionsController display = loader.getController();
display.setUser(user);
try{
//c.commit();
c.close();
} catch (Exception e){
e.printStackTrace();
User.showAlert("Please contact the admin.");
System.exit(0);
}
Parent userOption = loader.getRoot();
Scene classesToAddScene = new Scene(userOption);
Stage app_stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
app_stage.setScene(classesToAddScene);
app_stage.show();
}
public void setUser(Student user){
this.user = user;
}
}
stacktrace:
org.sqlite.SQLiteException: [SQLITE_BUSY] The database file is locked (database is locked)
at org.sqlite.core.DB.newSQLException(DB.java:909)
at org.sqlite.core.DB.newSQLException(DB.java:921)
at org.sqlite.core.DB.execute(DB.java:822)
at org.sqlite.core.DB.executeUpdate(DB.java:863)
at org.sqlite.jdbc3.JDBC3PreparedStatement.executeUpdate(JDBC3PreparedStatement.java:99)
at login.ClassesController.addClassToUser(ClassesController.java:123)
at login.ClassesController.access$200(ClassesController.java:21)
at login.ClassesController$1.handle(ClassesController.java:94)
at login.ClassesController$1.handle(ClassesController.java:80)
at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics/javafx.scene.Node.fireEvent(Node.java:8863)
at javafx.controls/javafx.scene.control.Button.fire(Button.java:200)
at javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:206)
at javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3876)
at javafx.graphics/javafx.scene.Scene$MouseHandler.access$1300(Scene.java:3604)
at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1874)
at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2613)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:397)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:434)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:433)
at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:175)
at java.base/java.lang.Thread.run(Thread.java:844)
So I have a BorderPane in my FXML, what I want to do is to reload my BorderPane.Center properties so it shows a different pane with different layout,
How can I achieve this? The codes below doesn't work for me.
p.s : sorry for indonesian.
My FXML :
<BorderPane fx:id="bPane" xmlns:fx="http://javafx.com/fxml" fx:controller="fx.HomeMhsController" stylesheets="#css.css">
<left>
<VBox spacing="10" fx:id="vbox" id="vbox" prefWidth="100" >
<Label id="Label" fx:id="biodata" text="Biodata" onMouseClicked="#showIdentity"/>
<Label id="Label" fx:id="histori" text="Histori Nilai" onMouseClicked="#showHistory" />
<Label id="Label" fx:id="jadwal" text="Jadwal Kuliah" onMouseClicked="#showSchedule" />
<Label id="Label" fx:id="pilih" text="Pilih Mata Kuliah" onMouseClicked="#chooseSchedule"/>
</VBox>
</left>
My Controller :
public class HomeMhsController{
#FXML private Label biodata2;
#FXML private BorderPane bPane;
#FXML private void showIdentity() throws SQLException{
init.initializeDB();
String query="select * from mahasiswa where nama_dpn ='" + MainController.username + "'";
ResultSet rset = init.stmt.executeQuery(query);
if(rset.next()){
String nim = rset.getString(1);
String nama_dpn = rset.getString(2);
String nama_blkg = rset.getString(3);
String tgl_lahir = rset.getString(4);
String tempat_lahir = rset.getString(5);
String jns_kelamin = rset.getString(6);
String agama = rset.getString(7);
String alamat = rset.getString(8);
String no_hp = rset.getString(9);
biodata2.setText(nim + nama_dpn + nama_blkg + tgl_lahir + tempat_lahir + jns_kelamin + agama + alamat + no_hp);
}
}
#FXML private void showHistory() throws IOException{
FXMLLoader loader = new FXMLLoader();
Parent rootNode = null;
rootNode = loader.load(getClass().getResource("homeMhs_fxml.fxml"));
Label dua = new Label("2");
Pane pane = new Pane();
pane.getChildren().add(dua);
((BorderPane) rootNode).setCenter(pane);
}
#FXML private void showSchedule() throws SQLException, IOException{
FXMLLoader loader = new FXMLLoader();
Parent rootNode = null;
rootNode = loader.load(getClass().getResource("homeMhs_fxml.fxml"));
Label tiga = new Label("3");
Pane pane = new Pane();
pane.getChildren().add(tiga);
((BorderPane) rootNode).setCenter(pane);
}
#FXML private void chooseSchedule() throws SQLException{
}
In the following code snippet:
#FXML private void showHistory() throws IOException{
FXMLLoader loader = new FXMLLoader();
Parent rootNode = null;
rootNode = loader.load(getClass().getResource("homeMhs_fxml.fxml"));
Label dua = new Label("2");
Pane pane = new Pane();
pane.getChildren().add(dua);
((BorderPane) rootNode).setCenter(pane);
}
you are loading the fxml file again, which is a new instance and different from the one you already have (since this method in its controller class). Moreover you are not doing anything with this newly loaded one (i.e. rootNode is not being added to any scene).
Instead just use the existing injected border pane:
#FXML private void showHistory() {
Label dua = new Label("2");
Pane pane = new Pane();
pane.getChildren().add(dua);
bPane.setCenter(pane);
}
or more shorter:
#FXML private void showHistory() {
bPane.setCenter(new Pane(new Label("2")));
}
I have the main application class that does the following just fine:
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"RecordScreen.fxml"));
Parent root = (Parent) loader.load();
Scene newScene = new Scene(root);
Stage newStage = new Stage();
newStage.setScene(newScene);
newStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
It launches a table view that displays people. I select a person, hit the edit button, and try to launch a window that will let me edit them.
#FXML
public void editPerson() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"PersonEditor.fxml"));
PersonEditorCtrl ctrl = loader.getController();
ctrl.init(table.getSelectionModel().getSelectedItem());
Parent root = (Parent) loader.load();
Scene newScene = new Scene(root);
Stage newStage = new Stage();
newStage.setScene(newScene);
newStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
The problem is, getController is returning null. I have been following this pattern for the past 2 weeks with no problems whatsoever. What am I doing wrong now? These untraceable bugs are aggravating!!!
Here are my two fxmls:
The screen with tableview:
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.RecordsCtrl">
<!-- TODO Add Nodes -->
<children>
<VBox id="VBox" alignment="CENTER" spacing="0.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<TableView fx:id="table" prefHeight="-1.0" prefWidth="-1.0">
<columns>
<TableColumn prefWidth="75.0" text="Name" fx:id="nameCol" />
<TableColumn prefWidth="75.0" text="Age" fx:id="ageCol" />
</columns>
</TableView>
<Button mnemonicParsing="false" onAction="#editPerson" text="Edit" />
</children>
</VBox>
</children>
</AnchorPane>
The person editor:
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.PersonEditorCtrl">
<!-- TODO Add Nodes -->
<children>
<VBox layoutX="0.0" layoutY="0.0" prefHeight="-1.0" prefWidth="-1.0">
<children>
<TextField fx:id="nameField" prefWidth="200.0" />
<TextField fx:id="ageField" prefWidth="200.0" />
<Button mnemonicParsing="false" text="Button" />
</children>
</VBox>
</children>
</AnchorPane>
Change this
#FXML
public void editPerson() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"PersonEditor.fxml"));
PersonEditorCtrl ctrl = loader.getController();
ctrl.init(table.getSelectionModel().getSelectedItem());
Parent root = (Parent) loader.load();
Scene newScene = new Scene(root);
Stage newStage = new Stage();
newStage.setScene(newScene);
newStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
To that:
#FXML
public void editPerson() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"PersonEditor.fxml"));
Parent root = (Parent) loader.load();
PersonEditorCtrl ctrl = loader.getController();
ctrl.init(table.getSelectionModel().getSelectedItem());
Scene newScene = new Scene(root);
Stage newStage = new Stage();
newStage.setScene(newScene);
newStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
You first have to run loader.load() then you can get the Controller.
Patrick