Sajad
Sajad

Reputation: 2363

Jtable Row delete

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

Answers (3)

Vishal K
Vishal K

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

SeKa
SeKa

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

Guillaume Polet
Guillaume Polet

Reputation: 47608

A few things I would change here:

  • in your RemoveRow, only have Udata.remove(rowIndex); fireTableRowsDeleted(rowIndex, rowIndex);
  • replace your RemoveUserFromFile method with a saveToFile(File file) method which would simply iterate over your Udata and write it to the given file

Side notes:

  • follow Java naming conventions (variables and methods start with a lower-case letter!). Your code is much harder to read because of that.
  • In your titleUserCount() you are recreating a new TableModel every time, only to count the entries in your table. You could simply use userModel.getRowCount()
  • There is no need to exend JFrame

Upvotes: 5

Related Questions