I'm developing an application in which I dynamically create forms by reading data from a database. What I want is the user to be able to update or delete the database by using the corresponding button in the database(I am allowing user to connect to almost any database so I have no idea about the type of columns, or whether an update will be supported). I've successfully created code to insert data in any database but I am struggling to figure out a way to update and delete records. This is the code snippet for the class for updating/deleting :
/* tflist contains the list of text fields(I used setName() to set their names to
the column names in the table) which I created dynamically
for allowing the user to enter new values and they already hold the
current values,panel contains all the labels and generated gui which is basically
column name in a label and text field,
e.g. Roll no(label) : 9(in a text field),
tablename has the name of the table,
jtable is the table on which event occurred
(you click on a row of table, and a form appears that gives you the option to
update or delete something),and rowno contains the row number of jtable on which
the user clicked */
private void update_buttonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String querypart2=" WHERE ";
for(int i=0;i<tflist.size();i++)
{
JTextField tf=tflist.get(i);
if(tf.getText()!=null&&!tf.getText().equals(""))
{
if(jtable.getValueAt(rowno, i)==null||jtable.getValueAt(rowno, i).equals(""))
{
querypart2=querypart2+"\""+tf.getName()+"\" IS NULL";
}
else
{
querypart2=querypart2+"\""+tf.getName()+"\"='"+jtable.getValueAt(rowno,i)+"'";
}
querypart2=querypart2+" AND ";
}
}
if(querypart2.equals(" WHERE "))
{
querypart2="";
}
else
{
querypart2=querypart2.substring(0, querypart2.length()-5);
}
try {
Statement statement = Aw_supersensible.conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs=statement.executeQuery("SELECT * FROM \""+tablename+"\""+querypart2);
rs.absolute(1);
for(int i=0;i<tflist.size();i++)
{
JTextField tf=tflist.get(i);
rs.updateObject(tf.getName(), tf.getText());
}
Aw_supersensible.conn.commit();
for(int i=0;i<tflist.size();i++)
{
JTextField tf=tflist.get(i);
jtable.setValueAt( tf.getText(),rowno,i);
rs.updateRow();
}
central_window.cw.setEnabled(true);
dispose();
}
catch(final Exception e)
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new errorWindow(new javax.swing.JFrame(),e.toString()).setVisible(true);
}
});
}
}
private void delete_buttonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String querypart2=" WHERE ";
for(int i=0;i<tflist.size();i++)
{
JTextField tf=tflist.get(i);
if(tf.getText()!=null&&!tf.getText().equals(""))
{
if(jtable.getValueAt(rowno, i)==null||jtable.getValueAt(rowno, i).equals(""))
{
querypart2=querypart2+"\""+tf.getName()+"\" IS NULL";
}
else
{
querypart2=querypart2+"\""+tf.getName()+"\"='"+jtable.getValueAt(rowno,i)+"'";
}
querypart2=querypart2+" AND ";
}
}
if(querypart2.equals(" WHERE "))
{
querypart2="";
}
else
{
querypart2=querypart2.substring(0, querypart2.length()-5);
}
try {
Statement statement = Aw_supersensible.conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs=statement.executeQuery("SELECT * FROM \""+tablename+"\""+querypart2);
rs.absolute(1);
rs.deleteRow();
((DefaultTableModel)jtable.getModel()).removeRow(rowno);
Aw_supersensible.conn.commit();
central_window.cw.setEnabled(true);
dispose();
}
catch(final Exception e)
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new errorWindow(new javax.swing.JFrame(),e.toString()).setVisible(true);
}
});
}
}
This is some pseudo code for your delete operation, to show you what I think a 'modular' approach would look like.
I am not an experienced developer (in fact I am not a developer), so there may be better ways.
private void delete_buttonActionPerformed(java.awt.event.ActionEvent evt) {
String tableName;
List<String> whereProperties;
List<String> whereValues;
// get your table name
// get your properties and values from the GUI in such a way that the property in whereProperties.get(n) corresponds to the value in whereValues(n)
// have a function in some class (I've called it SQL) that can take the following parameters and performs the delete operation.
SQL.delete(tableName, whereProperties, whereValues);
}
Related
I have been struggling with this problem for a while where I have two classes namely OrderSearch.java(main class) and CreateOrder.java. I have a JTable on my main class and when a row is doubleclicked it opens a new frame i.e CreateOrder.java with values from jTablein different textfields. I have a SaveButton in CreateOrder.java that saves the changes made in the class and shows it JTable again.
However the problem is I cannot perform refresh table operation i.e some sql queries when the SaveButton is clicked. I want the table in frame OrderSearch is refreshed when the savebutton on CreateOrder is clicked
Problems: Creating an object for class OrderSearch.java in CreateOrder.java gives me a stackoverflow error. Creating an object in the Savebutton opens a whole new frame again.
OrderSearch.java
public class OrderSearch extends CreateOrder{
//declarations for label,text, and buttons
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
OrderSearch window = new OrderSearch();
window.frmXraymanager.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public OrderSearch () { *Stack overflow error here*
initialize();
}
private void initialize() {
table = new JTable();
scrollPane.setViewportView(table);
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e2) {
if (e2.getClickCount() == 2 && !e2.isConsumed()) {
e2.consume();
try{
int index = table.getSelectedRow();
String table_Click = table.getModel().getValueAt(table.convertRowIndexToModel(index), 0).toString();
String sql = "SELECT ID, Date, Place, UserName FROM TEST.dbo.Intern WHERE ID = '"+table_Click+"'";
PreparedStatement pst = connection.prepareStatement(sql);
ResultSet rs = pst.executeQuery();
if(rs.next()){
String id = rs.getString("ID");
String date = rs.getString("Date").toString();
String place = rs.getString("Place");
String uname = rs.getString("UserName");
frameCreate.setVisible(true); //Frame from CreateOrder.java
Number.setText(id); // textfields from CreateOrder.java
String date1 = startDate;
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
Date date2 = df.parse(date1);
dateChooser.setDate(date2);
jobSite.setText(place);
uName.setText(uname);
Component.setText(component);
Remarks.setText(remarks);
rs.close();
pst.close();
}
catch(Exception e){
JOptionPane.showMessageDialog(null, e);
}
}
}
});
}
public void refresh()
{
query1 = "SELECT * FROM Test.dbo.Intern;
try(PreparedStatement pst = connection.prepareStatement(query1);
ResultSet rs = pst.executeQuery();){
table.setModel(DbUtils.resultSetToTableModel(rs));
table.setRowHeight(40);
}
catch(Exception e){
e.printStackTrace();
}
}
}
CreateOrder.java
public class CreateOrder {
public CreateOrder () {
initialize();
}
OrderSearch one = new OrderSearch(); *Stack overflow error here*
private void initialize() {
button_Save = new JButton("Save");
button_Save.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
*would like to add refresh() here*
}
});
}
}
How should I create an object of OrderSearch in CreateOrder to acces the method refresh() without opening the frame again?
Thanks in advance!
-Ajay
EDIT:
Actually the error is in
OrderSearch one = new OrderSearch();
and public OrderSearch () I totally understand it makes sense because it goes into infinite loop when I call an Object in CreateOrder.java. But is there any way to access the contents of OrderSearch.java in CreateOrder.java without getting the stackoverflow error or opening the whole new frame OrderSearch.java again?
No, there is no way to do it assuming your current setup. This leads us to the conclusion that you need to refactor the code. The main problem is that your code has no way to execute the required db command without creating a frame. You will need to separate the engine from the ui. You will need to be able to execute business logic without being tied to a UI event. The UI should be a user of the business logic, not its wrapper. You will need to move all your business logic into separate class(es) and call the relevant methods from the ui at the appropriate places and events.
I'm making a program where you login and it takes you into a into a different frame after you log in.. That part of the program works, but I'm having trouble getting it to return the user's name and other data from the database. It connects to the database, but it won't return the information inside JTextField. If I can find out how to do firstName, I can figure out the rest. I'm using Eclipse as my IDE and SQLite Manager as the database.
There are 2 tables
Login (username,password)
Student(SID,firstName,GradeLevel, and more)
Also username is there ID start with an S (like S01 and so forth).
Here's the code.
public class student extends JFrame {
private JTextField textField;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
student frame = new student();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void ShowInfo() {
try{
String query="SELECT firstName From Student,Login Where firstname=?";
PreparedStatement ps=conn.prepareStatement(query);
ps.setString(1, "firstName");
ResultSet rs= ps.executeQuery();
while (rs.next()) {
textField.setText(rs.getString("firstName"));
System.out.print(""+textField);
}ps.close();
conn.close();
} catch ( Exception ex)
{
JOptionPane.showMessageDialog(null,ex);
}
}
}
private void ShowInfo() {
try{
String query="SELECT firstName From Student,Login Where firstname=?";
PreparedStatement ps=conn.prepareStatement(query);
ps.setString(1, "firstName");
ResultSet rs= ps.executeQuery();
if(rs.next()) {
textField.setText(rs.getString(1));
System.out.print(""+textField); //you are getting data
}ps.close();
conn.close();
} catch ( Exception ex)
{
JOptionPane.showMessageDialog(null,ex); //you have a error
}
}
there were sevral thing which were wrong in the code. first one is there should be something wrong with sql statment Student,Login Where firstname.
you should change this line textField.setText(rs.getString(1));
and you have a while loop to extract the data but and you are planning on having a textfield to store data. that is pointless if you are expecting more than one output from your resultset you need something more than a jtextfield maybe a jtable. bt i have changed your while loop to a if loop to get one single output from the resultset.and the other thing i notice in your application is you are not calling the showInfo method.
I've the following code which i'm trying to make work . I have to read the content of a text file , which contains questions and save it to the database testsystem .
The main problem that i'm facing is that it's not inserted in the database. and i'm not sure whether it is reading the textfile or not.
I have received help from GameDroids , from what he explained above , i managed to get this , but now it's not only inserting and my upload button has become unresponsive , it doesn't trigger any event now. please i really need help.
any help will be glady appreciated .
For example for the bellow question, i shall have in my Category_questions : Collections, and for my questions : Which of these is not an example of a "real-life" collection? and for my quest_opt_a : a. The cards you hold in a card game. etc and for correct_option_answer i shall have d inserted in the database table.
this is the question :
Collections Which of these is not an example of a "real-life" collection?
a. The cards you hold in a card game.
b. Your favorite songs stored in your computer.
c. The players on a soccer team.
d. The number of pages in a book.
d.
public void actionPerformed(ActionEvent ev)
{
String file = fileField.getText();
SetGetQuestionFileName setGet = new SetGetQuestionFileName(file);
try
{
ConnectToDatabase database = new ConnectToDatabase();
// prepare the query
String query = "INSERT INTO questionnaire (category_questions, questions, quest_opt_a,quest_opt_b, quest_opt_c, quest_opt_d, correct_option_answer ) VALUES (?, ?, ?, ?, ?, ?, ?)";
PreparedStatement preparedStmt = null;
database.getConnection();
preparedStmt = database.getConnection().prepareStatement(query);
if(ev.getActionCommand().equals("UPLOAD"))
{
// JOptionPane.showMessageDialog(null,"File field can't be empty. Try again","ERROR",JOptionPane.INFORMATION_MESSAGE);
File filePathString = new File(file);
// load the file
Scanner scanner = new Scanner(file);
//fis = new FileInputStream(filePathString);
if(file.length() == 0)
{
JOptionPane.showMessageDialog(null,"File field can't be empty. Try again","ERROR",JOptionPane.INFORMATION_MESSAGE);
}
else
{
if(filePathString.exists() && filePathString.isFile())
{
// read the file line by line
while (scanner.hasNextLine())
{
String line = scanner.nextLine();
String[] questionAnswer = line.split("?");//[ // line.split["?"] will split the line into two strings, right at the ? and put those two strings into an array.
String question = questionAnswer[0]; // so [0] will access the first element in that array - the question
String[] answers = questionAnswer[1].split(","); // now we split the string after the ? into many strings divided by comma
// create the mysql insert preparedstatement
preparedStmt.setString(1, "JDBC");
preparedStmt.setString(2, question);
preparedStmt.setString(3, answers[0]);
preparedStmt.setString(4, answers[1]);
preparedStmt.setString(5, answers[2]);
preparedStmt.setString(6, answers[3]);
preparedStmt.setString(7, answers[4]);
preparedStmt.executeUpdate();
}
// database.disconnect();
JOptionPane.showMessageDialog(null,"File successfuly uploaded","INFORMATION",JOptionPane.INFORMATION_MESSAGE);
fileField.setText("");
}
}
if(!filePathString.exists() && !filePathString.isFile())
JOptionPane.showMessageDialog(null,"File coudn't be found. Do check file name.","ERROR",JOptionPane.INFORMATION_MESSAGE);
}
}
catch(Exception ex)
{
}
if(ev.getActionCommand().equals("LOGOUT"))
{
System.exit(0);
}
}
You can extend your JPanel or JFrame or any other view class with ActionListener if you want, but it is generally a good idea to create a separate class for the ActionListener.
public class MyActionListener extends ActionListener{
String myVariable;
public MyActionListner(String variableINeedForTheAction){ // pass the parameters you need in the constructor or getter method
this.myVariable = variableINeedForTheAction;
}
#Override
public void actionPerformed(ActionEvent e) {
this.myVariable = "actionPerformed"; // then, when the action gets performed you can access that variable
}
}
public class MyFrame extends JFrame{
//some code
JButton myButton = new JButton();
String text = "";
MyActionListner buttonListener = new MyActionListener(text); // instantiate your own action listener class and pass the variables you need for performing the action
myButton.addActionListener(buttonListener); // add the listener to some button
}
All this is done to separate your view from the controllers in your program. Imagine you have another button somewhere in another frame or panel and you want it to do the same thing as this button, then you can simply register another instance of your action listener, without having to copy the whole code.
Anyway, my guess is that you are doing too much work in your performed action and that the complete GUI becomes unresponsive because you are reading a file from disc and putting its content into a database in your actionPerformed method.
What you could try is using a Thread to handle all your upload / read / write stuff:
public void actionPerformed(ActionEvent e){
Thread myThread = new Thread(new Runnable(){
public void run(){
System.out.println(Thread.currentThread().getName() + " is running");
File filePathString = new File(file);
// load the file
Scanner scanner = new Scanner(file);
//... do the reading and writing here
System.out.println(Thread.currentThread().getName() + " is finished");
}
}, "Upload Thread");
myThread.start();
}
In fact as many people have suggested, the thread and swing workers where things which i really needed.
so i ended up with something like this :
try
{
Runnable r = new Runnable()
{
#Override
public void run()
{
doWork();
}
};
new Thread(r).start();
}
/* catch(SQLException ex)
{
ex.printStackTrace();
}*/
catch(Exception e)
{
e.printStackTrace();
e.getCause();
}
I am working on a NetBeans project (Java Swings) using MySQL # the back ground. Got struck in this particular scenario.
I am working with a JTable in one frame, say frame1 from where a row has to be selected on 'onclick' action event.
The corresponding data from the table in background in mysql will be retrieved and the data to be passed on to another frame, say frame2 where the data will be set to a JTextField.
The table in frame1 contains only a few selected tuples of the whole table maintained in the database.
The following are the code snippets i used
::
database table name DB_table
1- Select the data from the table in frame1
public static String Table;
public static int row;
private void jTable1MouseClicked(java.awt.event.MouseEvent evt)
{
// TODO add your handling code here:
jButton3.setEnabled(true);
row = jTable1.getSelectedRow();
Table = (jTable1.getModel().getValueAt(row,0).toString());
}
2- The action event on the button to redirect it to frame2
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt)
{
// TODO add your handling code here:
frame2 ac =new frame2();
jDesktopPane1.add(ac);
try {
ac.setSelectedRow(Table);
} catch (Exception e) {
// Logger.getLogger(showp1.class.getName()).log(Level.SEVERE, null, ex);
}
ac.setVisible(true);
}
3- this is the method in frame2
void setSelectedRow(String Table) {
try {
//ResultSet resultSet = null;
System.out.print(Table);
rs = pst.executeQuery("SELECT * FROM DB_Table where attr="+ Table +"");
//System.out.print(Table);
while (rs.next()) {
System.out.print(Table);
//jTextField1.setText(resultSet.getString(1));
//System.out.print(Table);
jTextField1.setText(rs.getString("attr"));
}
} catch (SQLException ex) {
Logger.getLogger(AddClient.class.getName()).log(Level.SEVERE, null, ex);
}
}
The data is being printed in the output console but not being stored in the text field in frame2...
Hope I am clear with the problem
Any suggestions will be very much appreciated..
I have a main frame that has a list and "add" button. When I click on the 'add' button, one frame will be shown that I can enter name, family and id.
And by clicking on the "addAPerson", the name will be stored in the SQL. But when I close the frame, the new person will not be added to my list which is in my main frame but if I close the main frame and run it again, the new person will be added to the list.
How can I update the JList without running the main frame?
My main frame (a part of that):
public class ListFrame extends javax.swing.JFrame {
private InformationClass client;
private DefaultListModel model = new DefaultListModel();
/** Creates new form ListFrame. */
public ListFrame(InformationClass client) {
initComponents();
this.client = client;
fillTable();
}
public void fillTable() {
try {
List<InformationClass> list = null;
list = Manager.getClientListFromMySQL();
if (list == null) {
JOptionPane.showMessageDialog(
this,
"You should add a person to your list",
"Information",
JOptionPane.OK_OPTION);
return;
}
else {
for (int i = 0; i < list.size(); i++) {
InformationClass list1 = list.get(i);
model.add(i, list1.getId());
}
jList1.setModel(model);
}
}
catch (SQLException ex) {
Logger.getLogger(
ListFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
My frame which will be shown when you click on the add button (a part of that):
public class Add extends javax.swing.JFrame {
private InformationClass client;
public Add(InformationClass client) {
initComponents();
this.client = client;
}
private void addAPersonActionPerformed(java.awt.event.ActionEvent evt) {
submit();
clear();
}
private void submit() {
String s1 = nameF.getText();
String s2 = familyF.getText();
String s3 = iDf.getText();
if (s1.equals("") || s2.equals("") || s3.equals("")) {
JOptionPane.showMessageDialog(
this,
"fill the empty name/family/id text fields",
"Error",
JOptionPane.ERROR_MESSAGE);
return;
}
else {
try {
boolean b = Manager.isAddPerson(s1, s2, s3);
if (b == false) {
Manager.addPerson(s1, s2, s3);
JOptionPane.showMessageDialog(
this,
"The person has been added successfully",
"Information",
JOptionPane.INFORMATION_MESSAGE);
}
else {
JOptionPane.showMessageDialog(
this,
"These datas has been added before!!",
"Information",
JOptionPane.INFORMATION_MESSAGE);
}
}
catch (NullPointerException e) {
e.printStackTrace();
}
}
}
}
My Manager class (a part of that):
public static void addPerson(String name, String family, String yahooId) {
PreparedStatement pstmt;
String query;
try {
query = ("INSERT INTO newpersontable(name,family,yahooId) VALUES(?,?,?)");
pstmt = (PreparedStatement) conn.prepareStatement(query);
pstmt.setString(1, name);
pstmt.setString(2, family);
pstmt.setString(3, yahooId);
pstmt.executeUpdate();
}
catch (SQLException e) {
Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, e);
}
}
An implementation of the Observer pattern will do the trick.
Your InformationClass calls the Manager to add a person, if it is not already known. But you want that new person appear in the ListFrame. With the Observer pattern, the ListFrame will observe the Manager if it has some added, changed or deleted records. If it is the case, the ListFrame can update itself with the actual values, that it just requests again from the Manager.
We need one additional interface, a Listener and some methods on the Manager, that's all.
Here's a basic implementation:
public interface PersonsModelChangeListener {
public void modelHasChanged();
}
In Manager, add the following fields and methods:
List<PersonsModelChangeListener> listeners = new ArrayList<PersonsModelChangeListener>();
public void addListener(PersonsModelChangeListener listener) {
listeners.add(listener);
}
private void fireModelChangeEvent() {
for (PersonsModelChangeListener listener:listeners) {
listener.modelHasChanged();
}
}
Add the following line to the add method of Manager:
public void add(String s1, String s2, String s3) {
// existing code
fireModelChanged();
}
Next step: make ListFrame implement the PersonsModelChangeListener interface and implement the modelHasChanged method so that ListFrame can 'get' the actual values whenever the Managers data set has changed.
Edit
public class Manager {
// existing code
private static List<PersonsModelChangeListener> listeners = new ArrayList<PersonsModelChangeListener>();
public static void addListener(PersonsModelChangeListener listener) {
listeners.add(listener);
}
private static void fireModelChangeEvent() {
for (PersonsModelChangeListener listener:listeners) {
listener.modelHasChanged();
}
}
public static void addPerson(String name, String family, String yahooId) {
PreparedStatement pstmt;
String query;
try {
query = ("INSERT INTO newpersontable(name,family,yahooId) VALUES(?,?,?)");
pstmt = (PreparedStatement) conn.prepareStatement(query);
pstmt.setString(1, name);
pstmt.setString(2, family);
pstmt.setString(3, yahooId);
pstmt.executeUpdate();
fireModelChangedEvent();
} catch (SQLException e) {
Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, e);
}
}
public class ListFrame extends javax.swing.JFrame implements PersonsModelChangeListener {
// your fields
/** Creates new form ListFrame */
public ListFrame(InformationClass client) {
initComponents();
this.client = client;
fillTable();
Manager.addListener(this);
}
#Override
public void modelHasChanged() {
// this method will be called when you add something with the
// Manager.
// Add your code here to get the actual data from the Manager
// and update this component
}
}
Hope it helps :)
In the submit method save the created person and create a field for it which you can 'get' from the actionPerformed method for the 'add' button in the ListFrame class. Then just add it to the list model.
you just call the update method at the end of your coding.the update method should display the table.So when you add some thing to the list it will get updated in the database. so at the end of your coding it will call the update method which will display the updated table.Hopu u got my point