Reputation: 2363
I have am creating a library system program in java without database.(Directly with file).
I have a strange problem with delete a line in my jtable (that delete from file too).
Sometimes when i select a row in my table and click to delete button, more that one line has been deleted!
also most time it work correctly!!
My code:
public final class UserPage extends JFrame implements ActionListener {
private AllUser userModel;
private JTable uTable;
JButton deleteUser;
int selectedRow;
public UserPage() {
titleUserCount();
userModel = new AllUser();
uTable = new JTable(userModel);
add(new JScrollPane(uTable), BorderLayout.CENTER);
add(buttonPanels(), BorderLayout.PAGE_START);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(800, 600);
this.setLocation(300, 60);
this.setResizable(false);
}
public final JPanel buttonPanels() {
JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
deleteUser = new JButton("Delete User");
deleteUser.addActionListener(this);
buttonsPanel.add(deleteUser);
return buttonsPanel;
}
public void titleUserCount() {
AllUser userCount = new AllUser();
UserPage.this.setTitle("All User Information , Number Of user is : " + userCount.getRowCount());
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == deleteUser) {
int selectedrow = uTable.getSelectedRow();
if (selectedrow >= 0) {
userModel.RemoveRow(selectedrow);
titleUserCount();
} else {
JOptionPane.showMessageDialog(null, "No Row Selected");
}
}
}
}
My model class:
public class AllUser extends AbstractTableModel {
UserInformation uiS = new UserInformation();
String[] col = {"ID", "Fname", "Lname", "Gender", "Date"};
ArrayList<UserInformation> Udata = new ArrayList<UserInformation>();
public AllUser() {
BufferedReader br = null;
try {
FileReader fr = new FileReader("AllUserRecords.txt");
br = new BufferedReader(fr);
String line;
while ((line = br.readLine()) != null) {
if (line.trim().length() == 0) {
continue;
}
Udata.add(initializeUserInfos(line));
}
} catch (IOException e) {
} finally {
if (br != null) {
try {
br.close();
} catch (IOException ioe) {
}
}
}
}
private UserInformation initializeUserInfos(String str) {
UserInformation Uinit = new UserInformation();
String[] CellArray = str.split(" ");
Uinit.setID(CellArray[0]);
Uinit.setFname(CellArray[1]);
Uinit.setLname(CellArray[2]);
Uinit.setGender(CellArray[3]);
Uinit.setDate(CellArray[4]);
return Uinit;
}
public void RemoveRow(int rowIndex) {
if (RemoveUserFromFile(rowIndex)) {
Udata.remove(rowIndex);
fireTableRowsDeleted(rowIndex, rowIndex);
} else {
JOptionPane.showMessageDialog(null, "Unable to delete");
}
}
public boolean RemoveUserFromFile(int index) {
File Mf = new File("AllUserRecords.txt");
File Tf = new File("Uoutput.txt");
try {
BufferedReader Ubr = new BufferedReader(new FileReader(Mf));
PrintWriter Upw = new PrintWriter(new FileWriter(Tf));
String line;
while ((line = Ubr.readLine()) != null) {
if (line.trim().length() == 0) {
continue;
}
if (!line.startsWith(String.valueOf(getValueAt(index, 0)))) {
Upw.println(line);
}
}
Upw.close();
Ubr.close();
Mf.delete();
Tf.renameTo(Mf);
return true;
} catch (FileNotFoundException e1) {
return false;
} catch (IOException ioe) {
return false;
}
}
@Override
public String getColumnName(int colu) {
return col[colu];
}
@Override
public int getRowCount() {
return Udata.size();
}
@Override
public int getColumnCount() {
return col.length;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
UserInformation uinfoS = Udata.get(rowIndex);
Object value = null;
switch (columnIndex) {
case 0:
value = uinfoS.getID();
break;
case 1:
value = uinfoS.getFname();
break;
case 2:
value = uinfoS.getLname();
break;
case 3:
value = uinfoS.getGender();
break;
case 4:
value = uinfoS.getDate();
break;
default:
value = "...";
}
return value;
}
@Override
public void setValueAt(Object value, int rowIndex, int columnIndex) {
UserInformation userInfo = Udata.get(rowIndex);
switch (columnIndex) {
case 0:
userInfo.setID((String) value);
break;
case 1:
userInfo.setFname((String) value);
break;
case 2:
userInfo.setLname((String) value);
break;
case 3:
userInfo.setGender((String) value);
break;
case 4:
userInfo.setDate((String) value);
break;
}
}
}
User information Class:
public class UserInformation {
private String Fname;
private String Lname;
private String ID;
private String Gender;
private String Date;
public String getFname() {
return Fname;
}
public void setFname(String fname) {
this.Fname = fname;
}
public String getLname() {
return Lname;
}
public void setLname(String lname) {
this.Lname = lname;
}
public String getID() {
return ID;
}
public void setID(String i_d) {
this.ID = i_d;
}
public String getGender() {
return Gender;
}
public void setGender(String gndr) {
this.Gender = gndr;
}
public String getDate() {
return Date;
}
public void setDate(String date) {
this.Date = date;
}
@Override
public String toString() {
return ID + " " + Fname + " "
+ Lname + " " + Gender + " " + Date + "\n";
}
}
My text File:
85 lo ii Female 2013/03/08
86 jkj nmn Female 2013/03/08
52 tyr fgfg Female 2013/03/08
7 dfdf wew Female 2013/03/08
47 zczc asa Female 2013/03/08
16 erw www Male 2013/03/08
83 gfg dsd Male 2013/03/08
Upvotes: 3
Views: 8036
Reputation: 13066
Well, since I Don't have your all code so I am proceeding with a dummy Program for removing a record from JTable
as well as the corresponding file. Watch the removeRow
method defined in MyTabeModel
class. It also covers the risk in case data couldn't be written on file
(records.temp) after the record
is deleted from ArrayList
.
import javax.swing.table.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.io.*;
public class TableFocus extends JFrame
{
MyTableModel model1;
JTable table1;
public void createAndShowGUI()
{
setTitle("JTables");
Container c = getContentPane();
model1 = new MyTableModel();
table1 = new JTable(model1);
table1.setColumnSelectionAllowed(false);
table1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane jsTable1 = new JScrollPane(table1);
c.add(jsTable1);
JButton button = new JButton("Delete");
button.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
if (model1.getRowCount() > 0 && table1.getSelectedRow() != -1 )
{
model1.deleteRow(table1.getSelectedRow());
}
}
});
add(button,BorderLayout.SOUTH);
setSize(500,300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
private class MyTableModel extends AbstractTableModel
{
String columns[] ;
ArrayList<ArrayList<String>> data;
public MyTableModel()
{
columns = new String[] {"Roll No.","Name"};
prepareData();
}
private void prepareData()
{
data = new ArrayList<ArrayList<String>>();
data.add(new ArrayList<String>(){{add("1");add("Michael");}});
data.add(new ArrayList<String>(){{add("2");add("Derake");}});
data.add(new ArrayList<String>(){{add("3");add("Archie");}});
}
@Override
public String getColumnName(int columnIndex)
{
return columns[columnIndex];
}
@Override
public int getRowCount()
{
return data.size();
}
@Override
public int getColumnCount()
{
return columns.length;
}
@Override
public Object getValueAt(int row, int col)
{
return data.get(row).get(col);
}
@Override
public void setValueAt(Object aValue, int rowIndex, int colIndex)
{
data.get(rowIndex).set(colIndex,(String)aValue);
fireTableCellUpdated(rowIndex,colIndex);
}
@Override
public boolean isCellEditable(int row, int col)
{
return false;
}
public void deleteRow(int row)
{
ArrayList<String> temp = data.get(row);//backup of value in case of IOException while writing to file
BufferedWriter bfr = null;
try
{
data.remove(row);
//Write here the logic for repopulating file with new records.
bfr = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("records.temp")));
StringBuffer sBuffer = new StringBuffer();
for (ArrayList<String> list : data)
{
StringBuffer buf = new StringBuffer();
for (String val : list )
{
buf.append(val+"\t");
}
buf.replace(buf.length() - 1, buf.length(),"\n");
sBuffer.append(buf.toString());
}
bfr.write(sBuffer.toString());
bfr.flush();
bfr.close();
fireTableRowsDeleted(row,row);
}
catch (Exception ex)
{
data.add(row,temp);//Rollback the delete from ArrayList
ex.printStackTrace();
}
finally
{
if (bfr != null)
{
try
{
bfr.close();
}
catch (Exception ex){}
}
}
}
}
public static void main(String[] args)
{
SwingUtilities.invokeLater( new Runnable()
{
@Override
public void run()
{
TableFocus ths = new TableFocus();
ths.createAndShowGUI();
}
});
}
}
UPDATE
Sometimes when i select a row in my table and click to delete button, more that one line has been deleted!
Well after going through your code I got to know the case when you have more than one row deleted. The case is: When you have more than one row in your file starting with the same user ID
whom record you want to delete.
For Example suppose you have entry like this in your file:
85 lo ii Female 2013/03/08
86 jkj nmn Female 2013/03/08
52 tyr fgfg Female 2013/03/08
86 jkj pqr Male 2013/03/08
7 dfdf wew Female 2013/03/08
47 zczc asa Female 2013/03/08
16 erw www Male 2013/03/08
83 gfg dsd Male 2013/03/08
Here userID 86
is contained in two rows (row 2
and row 4
).When you select 4th
row in your JTable
to delete that particular record, It deletes 2nd
as well as 4th
row from your File. But in JTable
the 2nd
row will keep showing because it is not refreshed with the new File
till now. As soon as you refresh your JTable
with new file , it shows both the rows deleted from there.
To know why is it happening , have a look at your RemoveUserFromFile(int index)
method while loop
which is as follows:
while ((line = Ubr.readLine()) != null) //Reads the file till the end.
{
if (line.trim().length() == 0) {
continue;
}
if (!line.startsWith(String.valueOf(getValueAt(index, 0)))) //If line starts with 86 don't write it to new `Uoutput.txt`. so all lines starting with 86 will be ignored.
{
Upw.println(line);//Lines starting with 86 is not written.
}
}
I hope that now you got the solid reason for why sometimes deleting a record from JTable
deletes two or more than two lines from your file
.
A workaround to this problem is to change your methods(RemoveRow
and RemoveUserFromFile
) in following way:(USE THIS MODIFIED CODE)
public void RemoveRow(int rowIndex) {
UserInformation temp = Udata.get(rowIndex);//Keep it as back up so that you could reconsolidate it to ArrayList in case RemoveUserFromFile return false
Udata.remove(rowIndex);//remove the element from Udata on temporary basis.
if (RemoveUserFromFile(rowIndex))
{
fireTableRowsDeleted(rowIndex, rowIndex);
}
else
{
Udata.add(rowIndex,temp);//re-insert temp in ArrayList as the file updation is failed.
JOptionPane.showMessageDialog(null, "Unable to delete");
}
}
public boolean RemoveUserFromFile(int index)
{
File Mf = new File("AllUserRecords.txt");
File Tf = new File("Uoutput.txt");
PrintWriter Upw = null;
try
{
Upw = new PrintWriter(new FileWriter(Tf));
for (UserInformation uino : Udata )
{
Upw.print(uino.toString());//Don't use Upw.println because the toString() method of UserInformation class is already using \n in last.
}
Upw.close();
Mf.delete();
Tf.renameTo(Mf);
return true;
} catch (FileNotFoundException e1) {
return false;
} catch (IOException ioe) {
return false;
}
finally
{
if (Upw != null)
{
try
{
Upw.close();
}
catch (Exception ex){}
}
}
}
I hope this fixed up your problem now...
NOTE: As a side note. I want to suggest you to stick with java naming convention while writing your codes. For Example: A class name always starts with a capital letter. A variable name always starts with small letter. And the constants (i.e Final variables) are having its all letters in capital. There are many others. Have a look at the official site of oracle.
Upvotes: 3
Reputation: 1835
This test:
if (!line.startsWith(String.valueOf(getValueAt(index, 0)))) {
in your removeUserFromFile()
method is VERY DANGEROUS because it's a String test such that an ID like 3 will match 30, 31, 35, 301, etc. (pretty much anything starting with 3).
To fix this particular test, you probably want to compare the IDs as integer numbers. First, pull the number from the line, something like:
Integer.parseInt(line.split("\\s")[0]);
Then compare that number to your getValueAt
from the table.
It's worth noting that the other answers have better overall designs; this is just meant to target a specific problem.
Upvotes: 2
Reputation: 47608
A few things I would change here:
RemoveRow
, only have Udata.remove(rowIndex); fireTableRowsDeleted(rowIndex, rowIndex);
RemoveUserFromFile
method with a saveToFile(File file)
method which would simply iterate over your Udata
and write it to the given file
Side notes:
titleUserCount()
you are recreating a new TableModel every time, only to count the entries in your table. You could simply use userModel.getRowCount()
JFrame
Upvotes: 5