Default Table Model's removeRow method problem

I'm using the following code for the listener and although when I check the value of the selected Row it shows the correct index, when I call the tblmodel.removeRow() method it throws an exception -1 ....

publicvoid valueChanged(ListSelectionEvent e){

if(e.getSource() == tbl.getSelectionModel() && tbl.getRowSelectionAllowed()){

// Get the data model for this table

//TableModel model = (TableModel)tbl.getModel();

// Determine the selected model

int selectedRowIndex = tbl.getSelectedRow();

String id = (String)tblmodel.getValueAt(tbl.getSelectedRow(),0);

String value = (String)tblmodel.getValueAt(tbl.getSelectedRow(),tbl.getSelectedColumn());

// Display the selected item

if (! e.getValueIsAdjusting()){

if(value.equals("Delete")){

if(JOptionPane.showConfirmDialog(null,"Are you sure you want to delete account no "+id +"\n Row Index: " + selectedRowIndex +"\nModel Row Count : "+tblmodel.getRowCount(),"Confirmation",JOptionPane.OK_CANCEL_OPTION)==0){

try{

deleteAccount(id);

tblmodel.removeRow(selectedRowIndex);

}

catch (ArrayIndexOutOfBoundsException ex){

JOptionPane.showMessageDialog(null, ex.getMessage() +"Returned Row Index is : " + selectedRowIndex,"Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

}

}

}

//JOptionPane.showMessageDialog(null,"The Value recieved is : "+id + "-"+value, "Value Recieved", JOptionPane.PLAIN_MESSAGE);

}

}

}

[2526 byte] By [topiwala] at [2007-11-26 12:58:06]
# 1

If you need further help then you need to create a [url http://homepage1.nifty.com/algafield/sscce.html]Short, Self Contained, Compilable and Executable, Example Program[/url] (SSCCE) that demonstrates the incorrect behaviour, because I can't guess exactly what you are doing based on the information provided.

And don't forget to use the [url http://forum.java.sun.com/help.jspa?sec=formatting]Code Formatting Tags[/url] so the code retains its original formatting.

camickra at 2007-7-7 16:55:10 > top of Java-index,Desktop,Core GUI APIs...
# 2

perhaps you should try replacing

tblmodel.removeRow(selectedRowIndex);

with

tblmodel.removeRow(tbl.getSelectedRow());

You may have a race condition. Perhaps the component is sometimes unstable when you determine the row being edited. Determining the row being edited in the same statement that removes it may help. Just a shot in the dark.

-Mark

Message was edited by:

MidnightJava

MidnightJavaa at 2007-7-7 16:55:10 > top of Java-index,Desktop,Core GUI APIs...
# 3

I will pretend that these two threads are not the same,

and suggest that perhaps something like

if ( listSelectionEvent.getValueIsAdjusting() )

return;

as the first lines in the selection listener may be the key.

JayDSa at 2007-7-7 16:55:10 > top of Java-index,Desktop,Core GUI APIs...
# 4

Here is full class code. When the ListSelectionEvent is triggered, the deleteAccount method deletes the record from DB and then ALL I WANT is to (somehow) refresh the table model to reflect the changes. For this I use tblmodel.removeRow(tbl.getSelectedRow()); which is not working i-e throwing an exception of ArrayInderOutOfBounds ( -1 ). Don't understand WHY?..Please help :

/*

* Account.java

* This class displays customer accounts data

*/

package ebankgui;

import java.awt.*;

import java.sql.DriverManager;

import javax.swing.*;

import java.awt.event.*;

import java.sql.*;

import java.sql.Connection.*;

import java.lang.*;

import javax.swing.table.*;

import javax.swing.JTable.*;

import java.util.Vector ;

import javax.swing.table.TableModel;

import javax.swing.event.TableModelEvent;

import javax.swing.event.TableModelListener;

import java.util.EventListener;

import javax.swing.ListSelectionModel;

import javax.swing.event.ListSelectionEvent;

import javax.swing.event.ListSelectionListener;

public class Account extends JFrame implements TableModelListener, ListSelectionListener {

private JPanel panel1 = new JPanel(new FlowLayout(70));

private JLabel CustomerAccounts = new JLabel();

Font headingfnt = new Font("Arial", Font.BOLD, 16);

Font tblHeader = new Font("Arial", Font.BOLD, 11);

private JPanel panel2 = new JPanel(new FlowLayout(FlowLayout.LEFT,70,10));

private JPanel panel3 = new JPanel(new FlowLayout(FlowLayout.LEFT,70,10));

private JLabel accountID = new JLabel("AccountID");

private JLabel acountTitle = new JLabel("Account Title");

private JLabel balance = new JLabel("Balance");

private JLabel creditLimit = new JLabel("Credit Limit");

private JLabel cards = new JLabel("Cards");

private DefaultTableModel tblmodel = new DefaultTableModel();

private Vector<String> vecColumnNames = new Vector<String>();

private JTable tbl;

private int numberOfRows;

private String cardnumbers = "";

private String customerName = "";

private Connection connection;

private Statement statement;

static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";

static final String DATABASE_URL = "jdbc:mysql://localhost/td?user=root";

/** Temp Button **/

JButton addNewAccountBtn = new JButton("Add New Account");

/** Creates a new instance of Account */

public Account(int id) {

super("eBank Customer Accounts");

setSize(800,600);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

CustomerAccounts.setText("Customer Account(s) - " + getCustomerName(id) + " ");

panel1.setBackground(Color.ORANGE);

accountID.setForeground(Color.BLUE);

acountTitle.setForeground(Color.BLUE);

balance.setForeground(Color.BLUE);

creditLimit.setForeground(Color.BLUE);

cards.setForeground(Color.BLUE);

CustomerAccounts.setFont(headingfnt);

BorderLayout bl1 = new BorderLayout();

setLayout(bl1);

tblmodel.addColumn("Account ID");

tblmodel.addColumn("Account Type");

tblmodel.addColumn("Balance");

tblmodel.addColumn("Credit Limit");

tblmodel.addColumn("Card");

tblmodel.addColumn("Modify");

tblmodel.addColumn("Delete");

panel1.add(CustomerAccounts);

panel3.setBackground(Color.LIGHT_GRAY);

panel1.add(addNewAccountBtn);

try {

Class.forName(JDBC_DRIVER);

connection = DriverManager.getConnection(DATABASE_URL);

statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

String qry = "SELECT * FROM account where customer_id="+id;

ResultSet rs = statement.executeQuery(qry);

if(getRowCount(rs)==0){

JOptionPane.showMessageDialog(null, "There are currently no accounts associated with this customer", "Message", JOptionPane.INFORMATION_MESSAGE);

}else{

rs.beforeFirst();

while (rs.next())

{

String [] accountsList = {rs.getString("account_id"),rs.getString("account_type"),rs.getString("balance"),rs.getString("credit_limit"), getCards(rs.getInt("account_id")), "Modify", "Delete"};

tblmodel.addRow(accountsList);

} //end while

} //end if

} //end try

//detect problems interacting with database

catch (SQLException e) {

JOptionPane.showMessageDialog(null, e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

}

//detect problems loading database driver

catch (ClassNotFoundException e){

JOptionPane.showMessageDialog(null, e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

}

//ensure Statement and COnnection are closed properly

/**

finally {

try {

statement.close();

connection.close();

}

//any execptions while closing connection and statement

catch(SQLException e){

JOptionPane.showMessageDialog(null, e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

}

}

*/

tbl = new JTable(tblmodel) {

public boolean isArrayTable(){

return false;

}

};

tbl.setFont(tblHeader);

tbl.setAutoResizeMode(tbl.AUTO_RESIZE_ALL_COLUMNS);

tbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

tbl.setSurrendersFocusOnKeystroke(true);

tbl.setDragEnabled(false);

tbl.setRowSelectionAllowed(true);

JScrollPane scrollpane = new JScrollPane(tbl);

//panel3.add(scrollpane);

//tempBtn.addActionListener(this);

ListSelectionModel selectionModel = tbl.getSelectionModel();

selectionModel.addListSelectionListener( this );

add(panel1,bl1.NORTH);

//add(panel2,bl1.SOUTH);

add(scrollpane,bl1.CENTER);

setVisible(true);

}

public String getCards(int a) {

try {

Connection connection = null;

Class.forName(JDBC_DRIVER);

connection = DriverManager.getConnection(DATABASE_URL);

statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

String qry = "SELECT * FROM cards where account_id="+a;

ResultSet rs = statement.executeQuery(qry);

if(getRowCount(rs)==0){

cardnumbers = "Card Not Issued";

}else{

rs.beforeFirst();

while (rs.next())

{

cardnumbers += rs.getString("card_no") + " (" + rs.getString("card_title") + ")";

} //end while

} //end if

} //end try

//detect problems interacting with database

catch (SQLException e) {

JOptionPane.showMessageDialog(null, e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

}

//detect problems loading database driver

catch (ClassNotFoundException e){

JOptionPane.showMessageDialog(null, e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

}

return cardnumbers;

}

public int getRowCount(ResultSet a){

try {

a.last();

numberOfRows = a.getRow();

return numberOfRows;

}

//any execptions

catch(SQLException e){

JOptionPane.showMessageDialog(null, e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

}

return numberOfRows;

}

public String getCustomerName (int cid){

try {

Class.forName(JDBC_DRIVER);

connection = DriverManager.getConnection(DATABASE_URL);

statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

String qry = "SELECT customer_name FROM customer where customer_id="+cid;

ResultSet rs = statement.executeQuery(qry);

rs.next();

customerName = rs.getString("customer_name");

} //end try

//detect problems interacting with database

catch (SQLException e) {

JOptionPane.showMessageDialog(null, e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

}

//detect problems loading database driver

catch (ClassNotFoundException e){

JOptionPane.showMessageDialog(null, e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

}

return customerName;

}

// public void slectionChanged(TableModelEvent e){}

public void valueChanged(ListSelectionEvent e){

if (!e.getValueIsAdjusting()){

if(e.getSource() == tbl.getSelectionModel() && tbl.getRowSelectionAllowed()){

int selectedRowIndex = tbl.getSelectedRow();

String id = (String)tblmodel.getValueAt(tbl.getSelectedRow(),0);

String value = (String)tblmodel.getValueAt(tbl.getSelectedRow(),tbl.getSelectedColumn());

// Check if Delete operation is required and run the operation

if(value.equals("Delete")){

if(JOptionPane.showConfirmDialog(null,"Are you sure you want to delete account no "+id + "\n Row Index: " + selectedRowIndex + "\nModel Row Count : "+tblmodel.getRowCount(), "Confirmation",JOptionPane.OK_CANCEL_OPTION)==0){

try {

// Call to deleteAccount method (DB delete row operation)

deleteAccount(id);

tblmodel.removeRow(tbl.getSelectedRow());

} //end try

catch (ArrayIndexOutOfBoundsException ex) {

JOptionPane.showMessageDialog(null, ex.getMessage() + "Returned Row Index is : " + selectedRowIndex, "Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

} //end catch

}

}

//JOptionPane.showMessageDialog(null,"The Value recieved is : "+id + "-"+value, "Value Recieved", JOptionPane.PLAIN_MESSAGE);

} //end inner if

} // end outer if

}

public void tableChanged(TableModelEvent e){}

public void deleteAccount(String account_id){

try{

Class.forName(JDBC_DRIVER);

connection = DriverManager.getConnection(DATABASE_URL);

statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

String qry = "delete from account where account_id=" + account_id;

//System.out.println(qry);

statement.executeUpdate(qry);

JOptionPane.showMessageDialog(null, "Account successfully deleted", "!!!", JOptionPane.PLAIN_MESSAGE);

}

//detect problems interacting with database

catch (SQLException e) {

JOptionPane.showMessageDialog(null, e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

}

//detect problems loading database driver

catch (ClassNotFoundException e){

JOptionPane.showMessageDialog(null, e.getMessage(), "Database Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

}

}

}

topiwala at 2007-7-7 16:55:10 > top of Java-index,Desktop,Core GUI APIs...
# 5
Code that access a database doesn't help us. We don't have access to the database.We want a simple SSCCE that we can compile and execute to see the described behaviour. This means you have to duplicate the problem without the database.
camickra at 2007-7-7 16:55:10 > top of Java-index,Desktop,Core GUI APIs...
# 6

Here is the SSCCE code :

/*

* Account.java

* This class displays customer accounts data

*/

package ebankgui;

import java.awt.*;

import java.sql.DriverManager;

import javax.swing.*;

import java.awt.event.*;

import java.sql.*;

import java.sql.Connection.*;

import java.lang.*;

import javax.swing.table.*;

import javax.swing.JTable.*;

import java.util.Vector ;

import javax.swing.table.TableModel;

import javax.swing.event.TableModelEvent;

import javax.swing.event.TableModelListener;

import java.util.EventListener;

import javax.swing.ListSelectionModel;

import javax.swing.event.ListSelectionEvent;

import javax.swing.event.ListSelectionListener;

public class Name extends JFrame implements TableModelListener, ListSelectionListener {

private JPanel panel1 = new JPanel(new FlowLayout(70));

private JLabel CustomerAccounts = new JLabel();

Font headingfnt = new Font("Arial", Font.BOLD, 16);

Font tblHeader = new Font("Arial", Font.BOLD, 11);

private JPanel panel2 = new JPanel(new FlowLayout(FlowLayout.LEFT,70,10));

private JPanel panel3 = new JPanel(new FlowLayout(FlowLayout.LEFT,70,10));

private JLabel accountID = new JLabel("AccountID");

private JLabel acountTitle = new JLabel("Account Title");

private JLabel balance = new JLabel("Balance");

private JLabel creditLimit = new JLabel("Credit Limit");

private JLabel cards = new JLabel("Cards");

private DefaultTableModel tblmodel = new DefaultTableModel();

private Vector<String> vecColumnNames = new Vector<String>();

private JTable tbl;

private int numberOfRows;

private String cardnumbers = "";

private String customerName = "";

/** Temp Button **/

JButton addNewAccountBtn = new JButton("Add New Account");

/** Creates a new instance of Account */

public Name() {

super("eBank Customer Accounts");

setSize(800,600);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

CustomerAccounts.setText("Customer Account(s) - ");

panel1.setBackground(Color.ORANGE);

accountID.setForeground(Color.BLUE);

acountTitle.setForeground(Color.BLUE);

balance.setForeground(Color.BLUE);

creditLimit.setForeground(Color.BLUE);

cards.setForeground(Color.BLUE);

CustomerAccounts.setFont(headingfnt);

BorderLayout bl1 = new BorderLayout();

setLayout(bl1);

tblmodel.addColumn("Account ID");

tblmodel.addColumn("Account Type");

tblmodel.addColumn("Balance");

tblmodel.addColumn("Credit Limit");

tblmodel.addColumn("Card");

tblmodel.addColumn("Modify");

tblmodel.addColumn("Delete");

panel1.add(CustomerAccounts);

panel3.setBackground(Color.LIGHT_GRAY);

panel1.add(addNewAccountBtn);

String [] accountsList1 = {"1","Saving Account","2000","1000","232128565653373", "Modify", "Delete"};

String [] accountsList2 = {"2","Current Account","2000","1000","232128565653373", "Modify", "Delete"};

tblmodel.addRow(accountsList1);

tblmodel.addRow(accountsList2);

tbl = new JTable(tblmodel) {

public boolean isArrayTable(){

return false;

}

};

tbl.setFont(tblHeader);

tbl.setAutoResizeMode(tbl.AUTO_RESIZE_ALL_COLUMNS);

tbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

tbl.setSurrendersFocusOnKeystroke(true);

tbl.setDragEnabled(false);

tbl.setRowSelectionAllowed(true);

JScrollPane scrollpane = new JScrollPane(tbl);

//panel3.add(scrollpane);

//tempBtn.addActionListener(this);

ListSelectionModel selectionModel = tbl.getSelectionModel();

selectionModel.addListSelectionListener( this );

add(panel1,bl1.NORTH);

//add(panel2,bl1.SOUTH);

add(scrollpane,bl1.CENTER);

setVisible(true);

}

// public void slectionChanged(TableModelEvent e){}

public void valueChanged(ListSelectionEvent e){

if (!e.getValueIsAdjusting()){

if(e.getSource() == tbl.getSelectionModel() && tbl.getRowSelectionAllowed()){

int selectedRowIndex = tbl.getSelectedRow();

String id = (String)tblmodel.getValueAt(tbl.getSelectedRow(),0);

String value = (String)tblmodel.getValueAt(tbl.getSelectedRow(),tbl.getSelectedColumn());

// Check if Delete operation is required and run the operation

if(value.equals("Delete")){

if(JOptionPane.showConfirmDialog(null,"Are you sure you want to delete account no "+id + "\n Row Index: " + selectedRowIndex + "\nModel Row Count : "+tblmodel.getRowCount(), "Confirmation",JOptionPane.OK_CANCEL_OPTION)==0){

try {

// delete selected row

tblmodel.removeRow(tbl.getSelectedRow());

} //end try

catch (ArrayIndexOutOfBoundsException ex) {

JOptionPane.showMessageDialog(null, "ArrayOutOfBoundsException : " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);

System.exit(1);

} //end catch

}

}

} //end inner if

} // end outer if

}

public void tableChanged(TableModelEvent e){}

public static void main(String[] args) {

Name ebankgui = new Name();

}

}

topiwala at 2007-7-7 16:55:10 > top of Java-index,Desktop,Core GUI APIs...
# 7

Hi, I ran your program using the Eclipse debugger and found your problem.

After you removed the row no row was selected and another ListSelectionEvent was fired to notify you of that.... If you don't want to catch this event you could do as follows:

tbl.getSelectionModel().removeListSelectionListener(this);

tblmodel.removeRow(selectedRowIndex);

tbl.getSelectionModel().addListSelectionListener(this);

More importantly: If you are using a selected index always check if it is not -1!

tbl.getSelectedRow() returned -1 and this is a valid value which means that no row is selected. This explains the index out of bounds -1.

copy/paste this at line 107 and it works ;-)

public void valueChanged(ListSelectionEvent e){

if (!e.getValueIsAdjusting()){

if(e.getSource() == tbl.getSelectionModel() && tbl.getRowSelectionAllowed()){

int selectedRowIndex = tbl.getSelectedRow();

if (selectedRowIndex >= 0) {

String id = (String)tblmodel.getValueAt(selectedRowIndex,0);

String value = (String)tblmodel.getValueAt(selectedRowIndex,tbl.getSelectedColumn());

// Check if Delete operation is required and run the operation

if(value.equals("Delete")){

if(JOptionPane.showConfirmDialog(null,"Are you sure you want to delete account no "+id + "\n Row Index: " + selectedRowIndex + "\nModel Row Count : "+tblmodel.getRowCount(), "Confirmation",JOptionPane.OK_CANCEL_OPTION)==0){

tbl.getSelectionModel().removeListSelectionListener(this);

tblmodel.removeRow(selectedRowIndex);

tbl.getSelectionModel().addListSelectionListener(this);

}

}

}

} //end inner if

} // end outer if

}

Strider80a at 2007-7-7 16:55:10 > top of Java-index,Desktop,Core GUI APIs...
# 8
Another option could be to use a real button to delete the row: http://forum.java.sun.com/thread.jspa?forumID=57&threadID=680674
camickra at 2007-7-7 16:55:10 > top of Java-index,Desktop,Core GUI APIs...
# 9
Thank you very much ... Its perfect now ...
topiwala at 2007-7-7 16:55:10 > top of Java-index,Desktop,Core GUI APIs...