-3

I am New in java, I have a JTable that can read records from a txt file and show they perfectly. I want to add a new book to my JFrame that when user select a row on table and clicked the "delete" button, that row should delete and that deleted row records must delete from txt file,too. my code is this, but it has errors and not seen JTable! :

public class CopyOfAllUserTable extends AbstractTableModel {
Vector data;
Vector column;
public static void main(String[] args){
    new CopyOfAllUserTable();
}
public CopyOfAllUserTable() {

        String line;
        data = new Vector();
        column = new Vector();
        try {
        FileInputStream fis = new FileInputStream("D:\\AllUserRecords.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
      StringTokenizer st1 = new StringTokenizer(br.readLine(), " ");
              while (st1.hasMoreTokens())
               column.addElement(st1.nextToken());
                while ((line = br.readLine()) != null) {
                       StringTokenizer st2 = new StringTokenizer(line, " ");
                        while (st2.hasMoreTokens())
                                data.addElement(st2.nextToken());
                }
                br.close();
        } catch (Exception e) {
                e.printStackTrace();
        }

    final JFrame frame1=new JFrame();
     JTable table=new JTable(data,column);
    JButton button1=new JButton("Delete");


    button1.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
           DefaultTableModel model=new DefaultTableModel(data, column);
           JTable table=new JTable(model);

        }
    });


    JPanel panel=new JPanel();
    panel.add(table);
    panel.add(button1);
    frame1.add(panel);
    frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame1.setBounds(200, 80, 600, 500);
    frame1.setVisible(true);
    frame1.setEnabled(true);


}

public int getRowCount() {
        return data.size() / getColumnCount();
}

public int getColumnCount() {
        return column.size();
}

public Object getValueAt(int rowIndex, int columnIndex) {
        return (String) data.elementAt((rowIndex * getColumnCount())
                        + columnIndex);
}

}

My problem is in delete row, and read records from file to jtable are perfectly successful.

StanislavL
  • 56,971
  • 9
  • 68
  • 98
Sajad
  • 2,273
  • 11
  • 49
  • 92

3 Answers3

3

Firstly you're not adding your JTable to the content of the frame.

For containers like: frame.getContentPane() and JPanel you should add the child components by using their #add(...) method.

For example:

 final JPanel panel=new JPanel(new BorderLayout());
 button1.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
       DefaultTableModel model=new DefaultTableModel(data, column);
       JTable table=new JTable(model);
       panel.add(new JScrollPane(table));
       panel.revalidate();
    }
});

Note that JPanel default layout is FlowLayout. Second thing - if you want to have headers and scrolling in your JTable you need to wrap it with JScrollPane. Next - you should revalidate the panel after adding/removing/etc.

The second issue is removing rows from JTable. I usually write a method to handle it:

protected void removeRows(final int[] rows) {
    int modelRows[] = new int[rows.length];
    for(int i = 0; i < rows.length; ++i) {
        modelRows[i] = table.convertRowIndexToModel(rows[i]);
    }
    Arrays.sort(modelRows);
    for(int i = modelRows.length - 1; i >= 0; --i) {
        int row = modelRows[i];
        model.removeRow(row);
    }
    model.fireTableDataChanged();
}

The convertRowIndexToModel method converts index returned by JTable#getSelectedRows() or JTable#getSelectedRow() (which are the visible indices) to the model indices. If you set RowSorter for your JTable or you leave it to standard implementation:

table.setAutoCreateRowSorter(true);
Xeon
  • 5,949
  • 5
  • 31
  • 52
  • Are you use the default table model in your removeRows method? Or write this method manually? – Sajad Dec 28 '12 at 08:26
  • Thank you so much, One question , is it necessary to use jscroolpane, if our table is small? – Sajad Dec 28 '12 at 08:38
2

You are adding table directly to the panel with out using the JScrollPane. Your table header will not be visible if you do like this, So instead of this,

JPanel panel=new JPanel();
    panel.add(table);

Do this,

JPanel panel=new JPanel();
panel.add(new JScrollPane(table));

Why to use JScrollPane? Read this.

When user selects a row and clicks on delete, then get the selected row and remove it from the table list. As you are using AbstractTableModel then you have to write your custom removeRow(..) method to perform this.

Example:

private boolean removeSelectedRow(int row) {
    // Remove the row from the list that the table is using.
    dataList.remove(row);
    // You need to call fireXXX method to refresh the table model.
    fireTableDataChanged();
    return true;
   // If fail return false;
}

If delete is the action then first get the selected row and then call removeSelectedRow(int) like the following,

private void deleteRow() {
  int selectedRow = table.getSelectedRow();
  boolean deleteStatus = removeSelectedRow(selectedRow);

  // Only if the deletion is success then delete from the file.
  if(deleteStatus) {
    // Delete it from the file too.
  }
}
Community
  • 1
  • 1
Amarnath
  • 8,736
  • 10
  • 54
  • 81
0

first you have to make sure that something has been selected: when there is something selected than enable the delete button. please look up the JTable java source code @

http://developer.classpath.org/doc/javax/swing/JTable-source.html

and the following code:

1331: /**
1332: * Receives notification when the row selection changes and fires
1333: * appropriate property change events.
1334: *
1335: * @param event the list selection event
1336: */
1337: public void valueChanged(ListSelectionEvent event)
1338: {
1339: firePropertyChange(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY,
1340: Boolean.FALSE, Boolean.TRUE);
1341: int r = getSelectedRow();
1342: int c = getSelectedColumn();
1343: if (r != lastSelectedRow || c != lastSelectedColumn)
1344: {
1345: Accessible o = getAccessibleAt(lastSelectedRow,lastSelectedColumn);
1347: Accessible n = getAccessibleAt(r, c);
1348: firePropertyChange(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY, o, n);
1350: lastSelectedRow = r;
1351: lastSelectedColumn = c;
1352: }
1353: }

You need to register for the last event to be notified when the selected rows have been changed. Add your own listener to enable the deletebutton based on whether or not a row has been selected which is as you can see in the event itself.

Please use to start with the DefaultTableModel because it will work in 90% of the cases.

And any change is applied to the tabledatamodel which will automatically propogate to the JTable View: normally you never change the view because all selection and scroll information is lost which is something you don't want.

When the delete button is fired the approach is straight forward: there is a row selected, otherwise it is impossible to click it: remove that selected row number from the defaultTableModel, and last but not least I would write simply the entire contents of the datamodel model to the designated file because the table's model hold the actual rows that are indeed displayed in the View.

So please think in terms of models models and models: Views are instantiated only once, packed scrolled etc and than you leave them as is. Models are normally also never changed: you change the contents of the models by adding and or deleting rows. One other tip: use always renderers: those that don't don't, in my humble opinion, don't understand how to work with JTables.

And yes you can leave out the first part to listen for selection changes: sure and pop up a warning to indicate the problem. And in a later stage add the functionality that listens for selection changes to enable and or disable the JButton delete row.

Hope this helps.