I'm writing an application with JavaFX, Scene Builder and SQlite
I have combobox with values(id) that goes from SQLite database.I have 2 textArias. I have a button "Add" that has a method void addCard(ActionEvent event). The method add text from textArias and apply it to particular columns in SQLite.
The problem is: when I try to add values to SQLite and click a button and then I open combobox, I don't see added ID, but when I close the window and open it again combobox display my added id.
It is very annoying to close and open window every time when I want to see the added result in combobox
Model class holds all logic
Controller Class operate between Model and view
Persistent Queries class holds all queries to/from SQLite
How to display new added ID after clicking on the button "Add"?
This video shows how my application work:
Video
Model class:
package src.card;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Cards {
PersistentQueries pq = new PersistentQueries();
final ObservableList OPTIONS = FXCollections.observableArrayList();
Connection connection;
PreparedStatement pst = null;
ResultSet rs = null;
public Cards() {
try {
this.connection = DbConnection.getConnection();
} catch (SQLException ex) {
ex.printStackTrace();
}
if (this.connection == null) {
System.out.println("connection is not successful!");
System.exit(1);
}
}
public ObservableList getOPTIONS() {return OPTIONS;}
//add ID of cards to combobox
void fillCombobox() {
try {
pst = connection.prepareStatement(pq.getSqlSelectID());
rs = pst.executeQuery();
while (rs.next()) {
OPTIONS.add(rs.getString("ID"));
}
pst.close();
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//check if database is connected
public boolean isDbConnected() {
return this.connection != null;
}
}
Controller Class:
package src.card;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import src.card.Cards;
import src.card.Context;
import src.card.DbConnection;
import src.card.PersistentQueries;
import java.net.URL;
import java.sql.*;
import java.util.ResourceBundle;
public class QuestController implements Initializable {
#FXML private TextArea ta_questText, ta_answerText;
#FXML private Label questId, error;
#FXML private ComboBox<String> combobox_question;
Cards cards = new Cards();
PersistentQueries pq = new PersistentQueries();
#Override
public void initialize(URL location, ResourceBundle resources) {
//register QuestController in Context Class
Context.getInstance().setQuestController(this);
cards.fillCombobox();
combobox_question.setItems(cards.getOPTIONS());
}
//adding cards to database
#FXML
void addCard(ActionEvent event) {
if (ta_questText.getText().equals("") ||
ta_answerText.getText().equals("")) {
error.setText("All fields are required!");
} else {
try {
error.setText("");
Connection conn = DbConnection.getConnection();
PreparedStatement stmt = conn.prepareStatement(pq.getSqlInsert());
stmt.setString(1, this.ta_questText.getText());
stmt.setString(2, this.ta_answerText.getText());
ta_questText.setText("");
ta_answerText.setText("");
stmt.execute();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
#FXML
void idList(ActionEvent event) {
questId.setText(combobox_question.getValue() + ".");
}
}
PersistentQueries Class
package src.card;
public class PersistentQueries {
private String sqlInsert = "INSERT INTO Cards(question, answer) VALUES
(?,?)";
private String sqlSelectID = "SELECT ID FROM Cards";
private String sqlSelect = "SELECT question and answer FROM Cards";
public String getSqlInsert() {
return sqlInsert;
}
public void setSqlInsert(String sqlInsert) {
this.sqlInsert = sqlInsert;
}
public String getSqlSelectID() {
return sqlSelectID;
}
public void setSqlSelectID(String sqlSelectID) {
this.sqlSelectID = sqlSelectID;
}
public String getSqlSelect() {
return sqlSelect;
}
public void setSqlSelect(String sqlSelect) {
this.sqlSelect = sqlSelect;
}
}
PROBLEM SOLVED!
in QuestController in the method #FXML void addCard(ActionEvent event) I added
cards.getOBS().clear();
It removes all objects from Observable list
then, I called method from Cards Class that reads all new data from SQLite and add it to Observable list
cards.fillCombobox();
and then I just close all connections:
pst.close();
rs.close();
conn.close();
My rewritten method looks like this:
/adding cards to database, update combobox and clear label text
#FXML void addCard(ActionEvent event) {
if (ta_questText.getText().equals("") || ta_answerText.getText().equals("")) {
error.setText("All fields are required!");
} else {
try {
error.setText("");
Connection conn = DbConnection.getConnection();
pst = conn.prepareStatement(pq.getSqlInsert());
pst.setString(1, this.ta_questText.getText());
pst.setString(2, this.ta_answerText.getText());
pst.execute();
pst = conn.prepareStatement(pq.getSqlSelectID());
rs = pst.executeQuery();
ta_questText.clear();
ta_answerText.clear();
cards.getOBS().clear();
questId.setText("");
cards.fillCombobox();
pst.close();
rs.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Related
I am pretty new to Java. I have this particular issue that have kept me from moving to the next phase of my project. I want to close a JFrame from my main class from another class and open another jFrame on button click. I have been able to open the second JFrame on button click, but can't close the first JFrame. I am working with Netbeans.
NOTE: I'm trying to have separate codes for views and controller using an MVC design pattern.
Here are my codes.
LoginPage (Main class)
package auth;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LoginPage extends javax.swing.JFrame {
public static LoginPage lp = new LoginPage();
public LoginPage() {
initComponents();
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here: Cancel button
System.exit(0);
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here: Login button
String uname = jTextField1.getText();
String pword = jPasswordField1.getText();
try {
LoginController.collectUserData(uname, pword);
} catch (SQLException ex) {
Logger.getLogger(LoginController.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new LoginPage().setVisible(true);
}
});
}
and the other class
LoginController
package auth;
import dbconnect.dbconnect;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.swing.*;
public class LoginController extends javax.swing.JFrame {
public static void collectUserData(String uname, String pword) throws SQLException {
Login user = new Login();
user.setUsername(uname);
user.setPass(pword);
checkDatabaseAndLogin(user);
}
public static void checkDatabaseAndLogin(Login test) throws SQLException {
JFrame rootPane;
if (test.getUsername().equals("")||test.getPass().equals("")) {
rootPane = new JFrame();
JOptionPane.showMessageDialog(rootPane, "Some fields are empty", "Error", 1);
} else {
try {
//LoginPage lp = new LoginPage();
Connection con = dbconnect.connect();
PreparedStatement pst = con.prepareStatement("select * from test where username=? and pass=?");
pst.setString(1, test.getUsername());
pst.setString(2, test.getPass());
ResultSet rs = pst.executeQuery();
if (rs.next()) {
String un = rs.getString("username");
//System.out.println(un);
PatronPage pt = new PatronPage(un);
pt.setVisible(true); //Code to open the new window
LoginPage.lp.dispose(); //Code to close the old window
} else {
rootPane = new JFrame();
JOptionPane.showMessageDialog(rootPane, "Username or Password do not match record", "Login error", 1);
}
} catch (Exception ex) {
System.out.println(""+ex);
}
}
}
}
Of course there are other system generated codes in Netbeans I removed, I just provided the chunk of code that I feel are relevant to the solution. Please help out, I'm stuck.
The LoginPage instance that you are "closing" in your LoginController class with the line
LoginPage.lp.dispose();
is not the instance which you initially displayed with
new LoginPage().setVisible(true);
I am afraid your whole approach to creating a Swing UI is wrong. Maybe work through the Swing tutorial first.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 1 year ago.
this is my code an di get this error, I don't understand why, I tried multiple times to figure it out what is happening, are you able please to help me. I tried to check the several topic that are around here regarding this but nothing similar found and if I need to do a null check, I am new to this and I don't understand exactly what I need to do
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.*;
public class JavaCrud {
private JPanel Main;
private JTextField txtName;
private JButton saveButton;
private JButton deleteButton;
private JButton updateButton;
private JTextField textField2;
private JTextField txtPrice;
private JTextField txtQty;
public static void main(String[] args) {
JFrame frame = new JFrame("JavaCrud");
frame.setContentPane(new JavaCrud().Main);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public JavaCrud() {
Connect();
saveButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String name, price, qty;
name = txtName.getText();
price = txtPrice.getText();
qty = txtQty.getText();
try {
pst = con.prepareStatement("insert into products(pname,price,qty)values(?,?,?)");
pst.setString(1, name);
pst.setString(2, price);
pst.setString(3, qty);
pst.executeUpdate();
JOptionPane.showMessageDialog(null,"Record Addedddddd!!!!");
txtName.setText("");
txtPrice.setText("");
txtQty.setText("");
txtName.requestFocus();
}
catch (SQLException e1)
{
e1.printStackTrace();
}
}
});
deleteButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String bid;
bid = textField2.getText();
try {
pst = con.prepareStatement("delete from products where pid = ?");
pst.setString(1, bid);
pst.executeUpdate();
JOptionPane.showMessageDialog(null, "Record Deleteeeeee!!!!!");
txtName.setText("");
txtPrice.setText("");
txtQty.setText("");
txtName.requestFocus();
textField2.setText("");
}
catch (SQLException e1)
{
e1.printStackTrace();
}
}
});
updateButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String pid,name,price,qty;
name = txtName.getText();
price = txtPrice.getText();
qty = txtQty.getText();
pid = textField2.getText();
try {
pst = con.prepareStatement("update products set pname = ?,price = ?,qty = ? where pid = ?");
pst.setString(1, name);
pst.setString(2, price);
pst.setString(3, qty);
pst.setString(4, pid);
pst.executeUpdate();
JOptionPane.showMessageDialog(null, "Record Updateee!!!!!");
txtName.setText("");
txtPrice.setText("");
txtQty.setText("");
txtName.requestFocus();
textField2.setText("");
}
catch (SQLException e1)
{
e1.printStackTrace();
}
}
});
}
Connection con;
PreparedStatement pst;
public void Connect(){
try{
Connection con;
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/gbproducts","root","root");
System.out.println("Success");
}catch(SQLException ex){
ex.printStackTrace();
}
}
}
A NullPointerException is thrown because you adding an addActionListener to your button that has not been instantiated.
In your JavaCrud() method you need to instantiate your buttons.
saveButton = new JButton("SAVE");
deleteButton = new JButton("DELETE");
updateButton = new JButton("UPDATE");
You would also need to instantiate your JTextfield because after a user clicks on a button you are trying to getText() from a JTextField that is null.
Also, it is better to implements ActionListener to your class than to addActionListener to every button. It allows for cleaner code and easier debugging.
Here you can read up on ActionListener Interface
So I'm making a login system. Based on the role your account has when you log in, it displays role specific buttons. For instance if you login as an employee, you get to see two buttons called RequestStatus and RegisterMissing. If you login as a manager, you get to see the buttons RequestStatus, RegisterMissing, Reports and UserRoles.
After a bit of trail and error (As I am a beginner in java) I managed to make it work!
CODE:
#FXML
private TextField textUsername;
#FXML
private PasswordField textPassword;
Stage dialogStage = new Stage();
Scene scene;
ResultSet resultSet = null;
//Login for employee
#FXML
private void handleButtonAction(ActionEvent event) {
Database db = new Database();
String username = textUsername.getText();
String password = textPassword.getText();
int usrID = 0;
int roleID = 0;
//String RoleID = EmpSelect.getValue();
String sql = String.format("SELECT * FROM Employee "
+ "WHERE username = '%s' "
+ "and password = '%s' ",
//+ "and RoleID = '%s' ",
username, password);
infoBox("sql [" + sql + "]", "Success", null);
try {
resultSet = db.executeResultSetQuery(sql);
if (!resultSet.next()) {
infoBox("Enter Correct Username and Password", "Failed", null);
} else {
//infoBox("Login Successfull", "Success", null);
resultSet.first();
usrID = resultSet.getInt("idEmployee");
roleID = resultSet.getInt("RoleID");
utilities.setEmployee(usrID, roleID);
FXMLDocumentController controller = new FXMLDocumentController();
utilities.newAnchorpane("EmployeeHomescreen", paneLogin);
infoBox("Login Successfull", "Success", null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void infoBox(String infoMessage, String titleBar, String headerMessage) {
Alert alert = new Alert(AlertType.INFORMATION);
alert.setTitle(titleBar);
alert.setHeaderText(headerMessage);
alert.setContentText(infoMessage);
alert.showAndWait();
}
So basically what I'm doing here is that an employee of the company can login and it displays the result of the query just so that I know that it works.
import static com.mycompany.mavenproject2.LoginController.infoBox;
import java.net.URL;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
/**
*
* #author John
*/
public class WorkerHomescreenController implements Initializable {
#FXML
private AnchorPane actualmain;
#FXML
private Pane mainpage;
#FXML
private Label label1;
#FXML
private Button but1, but2, but3, but4;
#FXML
private VBox VBPane;
#Override
public void initialize(URL url, ResourceBundle rb) {
//infoBox("User ID = " + utilities.userID, "Success", null);
Database db = new Database();
ResultSet resultSet = null;
String sqlMenu = String.format("SELECT * FROM Menu "
+ "WHERE idMenu IN (SELECT MenuID FROM MenuRoles WHERE RoleID = " + utilities.roleID + ") ");
//+ "AND Active = True");
try {
resultSet = db.executeResultSetQuery(sqlMenu);
int i=0;
GridPane gpnael = new GridPane();
while (resultSet.next()) {
Button button = new Button(resultSet.getString("Link"));
gpnael.add (button, i++, 1 );
button.setStyle("-fx-font: 22 arial; -fx-base: #d81e05; "
+ "-fx-background-radius: 0; -fx-border-width: 1 0 0 0; "
+ "-fx-border-color: white; -fx-font-weight: bold; "
+ "-fx-font-size: 18;");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
try {
resultSet.getURL("Link");
} catch (SQLException ex) {
Logger.getLogger(WorkerHomescreenController.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
} catch (SQLException e) {
e.printStackTrace();
}
}
Utilities utilities = new Utilities();
//Methods to open other pages
#FXML
private void openRequestStatus(ActionEvent event) {
utilities.newPane("RequestStatus", but1, mainpage, label1);
}
#FXML
private void openRegisterMissing(ActionEvent event) {
utilities.newPane("RegisterMissing", but2, mainpage, label1);
}
#FXML
private void openRequestTest(ActionEvent event) {
utilities.newPane("RequestStatus", but3, mainpage, label1);
}
#FXML
private void openRegistertesting(ActionEvent event) {
utilities.newPane("RegisterMissing", but4, mainpage, label1);
}
}
This is the controller of the page where you are redirected to after you login. This page is currently set up in a manner in which based on which RoleId the account you used to login with, it will generate the buttons with the info I have stored in my database.
Utilities controller:
public static int userID;
public static int roleID;
#FXML
public void setEmployee(int idEmployee, int RoleID) {
this.userID = idEmployee;
this.roleID = RoleID;
}
The Utilities controller is used to set the current employee.
My question is this:
My program currently works so that it generates buttons based on your account (Which is good!). What I want to do now is that the buttons have a link saved in the database as well. So that when the buttons are generated, it has a label and a link attached to it so that when you press the button it will go to the link that is attached to the button.
I hope this makes sense.
I know that in a .FXML file if you make a button inside of there you can give it an onAction event which makes it so that if you press the button it takes you to the correct page.
This is what my database looks like:
EMPLOYEE Table
idEmployee firstname lastname username password RoleID
1 John Doe John123 Test123 1
2 Tim Gardener Tim123 Welcome123 2
ROLES Table
idRole roleName
1 Employee
2 Manager
MENU Table
idMenu Name Link
1 but1 RequestStatus
2 but2 RegisterMissing
3 but3 Reports
4 but4 UserRoles
MenuRoles Table
MenuID RoleID
1 1
1 2
2 1
2 2
3 2
4 2
I hope you guys can help me with this problem and thank you for your time I appreciate it!
EDIT 1:
After reading the comment I edit a bit of my code.
The problem I'm having now is that the resultSet in resultSet.getURL("Link"); gives me an error saying: "Local variabel is accessed from within inner class; needs to be declared final.
After making the resultSet final it gives me another error saying
final ResultSet resultSet = null;
This part now gives me an error saying:
resultSet = db.executeResultSetQuery(sqlMenu);
Cannot assign value to final variabel resultSet.
I made a JavaFX Scenebuilder "Application" and I need to fill my listView with things from my database. The problem is that I don't know how and I don't know where to look.
Is there someone who can help me out?
Here is the code with my connection to the database. That's the only thing I have. And the scene builder "Sample.fxml" file of course.
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Connection Conn = null;
try {
Conn = DriverManager.getConnection("jdbc:mysql://localhost/hitdossier", "root", "");
System.out.println("Verbonden met de database");
} catch (SQLException e) {
System.out.println(e.getMessage());
System.out.println("Verbinding met de database is mislukt.");
}
Statement stmt = null;
ResultSet rs = null;
try {
stmt = Conn.createStatement();
rs = stmt.executeQuery("SELECT naam FROM artiest");
while (rs.next()) {
System.out.println(rs.getString(1));
}
} catch (SQLException e) {
}
primaryStage.setTitle("Eindopdracht Java Periode 4");
primaryStage.setScene(new Scene(root, 700, 650));
primaryStage.show();
}
This is my Controller.java
package sample;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
public class Controller {
#FXML
private ComboBox<String> cboWeek;
}
I would go for the following code:
First define your listView and an observable list (assuming that you have a ListView in your fxml with the id "list"):
#FXML
ListView<String> list;
ObservableList<String> items = FXCollections.observableArrayList();
Then set the list view to the items list:
list.setItems(items);
in your while loop simply add the results to the items list:
items.add(rs.getString(1));
You could do the following (code not tested):
Main.java:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Eindopdracht Java Periode 4");
primaryStage.setScene(new Scene(root, 700, 650));
primaryStage.show();
}
}
Controller.java (associated with a fxml that contains a ListView with id=list):
public class Controller implements Initializable{
#FXML
private ListView<String> list;
private ObservableList<String> items = FXCollections.observableArrayList();
#Override
public void initialize(URL location, ResourceBundle resources) {
list.setItems(items);
Connection Conn = null;
try {
Conn = DriverManager.getConnection("jdbc:mysql://localhost/hitdossier", "root", "");
System.out.println("Verbonden met de database");
} catch (SQLException e) {
System.out.println(e.getMessage());
System.out.println("Verbinding met de database is mislukt.");
}
Statement stmt = null;
ResultSet rs = null;
try {
stmt = Conn.createStatement();
rs = stmt.executeQuery("SELECT naam FROM artiest");
while (rs.next()) {
items.add(rs.getString(1));
System.out.println(rs.getString(1));
}
} catch (SQLException e) {
}
}
}
By implementing the initialize method you could load the contents whenever the scene is shown.
I use the following code to create new Database. If the given Database name is same as existing Database name means the existing Database need to be deleted else the new data base need to be created with the given name. I have error in creating new database.
package db1;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.sql.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Main implements ActionListener
{
JTextField txt;
JButton create;
JFrame frame;
JPanel panel;
JOptionPane jop;
//Font font = UIManager.getFont("txt.font");
public Main()
{
frame=new JFrame();
panel=new JPanel();
txt=new JTextField(10);
create=new JButton("create");
create.setBounds(20, 200, 50, 40);
panel.add(txt);
panel.add(create);
create.addActionListener(this);
frame.add(panel);
// n.getContentPane().add(new textf());
frame.setSize(440,310);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
Connection con = null;
try{
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/vijay1","root","root");
try{
Statement st = con.createStatement();
String database=txt.getText();
st.executeUpdate("DROP DATABASE IF EXISTS "+database);
JOptionPane.showMessageDialog(frame,"EXISTING DATABASE DELETED");
st.executeUpdate("CREATE DATABASE "+database);
JOptionPane.showMessageDialog(frame,"DATABASE CREATED");
}
catch (SQLException s){
System.out.println("SQL statement is not executed!");
}
}
catch (Exception ea){
ea.printStackTrace();
}
}
public static void main(String[] args)
{
new Main();
}
}
Try this as your inner try block, hope this will help.
try
{
String database=txt.getText();
String query = "if exists(select * from sys.databases where (name = ?))"
+ "drop database " + database
+ "create database " + database;
PreparedStatement statement = con.prepareStatement(query);
statement.setString(1, database);
statement.executeUpdate();
JOptionPane.showMessageDialog(frame,"EXISTING DATABASE DELETED");
JOptionPane.showMessageDialog(frame,"DATABASE CREATED");
}
Regards