I use this code and get errors java.lang.ArrayIndexOutOfBoundsException . I know that the problem is multi-threading and EDT. I read about using the method publish(), but I do not know how to use it and I do not know how to change your code to correct errors. Please tell me how to change the code to avoid any mistakes. Thank U! Error message:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 1 >= 1
at java.util.Vector.elementAt(Unknown Source)
at javax.swing.table.DefaultTableColumnModel.getColumn(Unknown Source)
at javax.swing.plaf.basic.BasicTableHeaderUI.getHeaderHeight(Unknown Source)
at javax.swing.plaf.basic.BasicTableHeaderUI.createHeaderSize(Unknown Source)
at javax.swing.plaf.basic.BasicTableHeaderUI.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at javax.swing.ViewportLayout.preferredLayoutSize(Unknown Source)
at java.awt.Container.preferredSize(Unknown Source)
at java.awt.Container.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at javax.swing.ScrollPaneLayout.layoutContainer(Unknown Source)
at java.awt.Container.layout(Unknown Source)
at java.awt.Container.doLayout(Unknown Source)
at java.awt.Container.validateTree(Unknown Source)
at java.awt.Container.validate(Unknown Source)
at javax.swing.RepaintManager$2.run(Unknown Source)
at javax.swing.RepaintManager$2.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at javax.swing.RepaintManager.validateInvalidComponents(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Main Class:
import java.sql.*;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class DatabaseTable extends JFrame {
private String
dsn = "jdbc:mysql://localhost:3306/TestDB",
uid = "root",
pwd = "root";
private static int start = 0, count = 10;
private JProgressBar progressBar = null;
private JButton btnNewButton = null;
private DatabaseTableModel dbm = null;
private Statement st = null;
Connection connections() throws ClassNotFoundException, SQLException{
Connection conn = null;
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(dsn, uid, pwd);
return conn;
}
public DatabaseTable(){
dbm = new DatabaseTableModel(false);
JTable table = new JTable(dbm);
try {
JFrame frame = new JFrame("Next record");
frame.setSize(400, 300);
frame.getContentPane().add(new JScrollPane(table));
btnNewButton = new JButton("Next!");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Task task = new Task();
task.execute();
}
});
frame.getContentPane().add(btnNewButton, BorderLayout.NORTH);
progressBar = new JProgressBar();
frame.getContentPane().add(progressBar, BorderLayout.SOUTH);
frame.show();
} catch (Exception ex) {
System.out.println("DatabaseTable().Exception");
}
}
class Task extends SwingWorker<Void, Void> {
@Override
public Void doInBackground() throws Exception {
btnNewButton.setEnabled(false);
progressBar.setIndeterminate(true);
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try {
st = connections().createStatement();
ResultSet rs = st.executeQuery("select * from testTable LIMIT "+start+","+count);
start += 10;
dbm.setDataSource(rs);
rs.close();
connections().close();
}catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("Task.ClassNotFoundException");
}catch ( SQLException e) {
System.out.println("Task.SQLException");
}catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("Task.Exception");
}
return null;
}
@Override
public void done(){
progressBar.setIndeterminate(false);
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
progressBar.setValue(100);
btnNewButton.setEnabled(true);
}
}
public static void main(String[] args) {
new DatabaseTable();
}
}
Class TableModel:
import javax.swing.*;
import javax.swing.table.*;
import java.sql.*;
import java.util.*;
public class DatabaseTableModel extends AbstractTableModel {
private ArrayList columnNames = new ArrayList();
private ArrayList columnTypes = new ArrayList();
private ArrayList data = new ArrayList();
public DatabaseTableModel(boolean editable) {
this.editable = editable;
}
private boolean editable;
public int getRowCount() {
synchronized (data) {
return data.size();
}
}
public int getColumnCount() {
return columnNames.size();
}
public Class getColumnClass(int column) {
return (Class)columnTypes.get(column);
}
public String getColumnName(int column) {
return (String)columnNames.get(column);
}
public Object getValueAt(int row, int column) {
synchronized (data) {
return ((ArrayList)data.get(row)).get(column);
}
}
public boolean isEditable(int row, int column) {
return editable;
}
public void setValueAt(Object value, int row, int column){
synchronized (data) {
((ArrayList)data.get(row)).set(column, value);
}
}
public void setDataSource(ResultSet rs) throws Exception {
data.clear();
columnNames.clear();
columnTypes.clear();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
for ( int i=0; i<columnCount; i++) {
columnNames.add(rsmd.getColumnName(i+1));
Class type = Class.forName(rsmd.getColumnClassName(i+1));
columnTypes.add(type);
}
fireTableStructureChanged();
while ( rs.next() ) {
ArrayList row = new ArrayList();
for ( int i=0; i<columnCount; i++) {
if (columnTypes.get(i) == String.class)
row.add(rs.getString(i+1));
else
row.add(rs.getObject(i+1));
}
synchronized (data) {
data.add(row);
fireTableRowsInserted(data.size()-1, data.size()-1);
}
}
}
}
There is no need for the "synchronized" logic in the TableModel. A TableModel should be updated on the Event Dispatch Thread when it has been added to the JTable.
So I would suggest that instead of using:
dbm = new DatabaseTableModel(false);
JTable table = new JTable(dbm);
You create the TableModel in the SwingWorker. Then in the "done()" method of the SwingWorker you can use:
table.setModel( )
Code in the "done()" method executes on the Event Dispatch Thread so you can safely reset the model of the table.
Edit:
You create a new TableModel with code like:
DatabaseTableModel dbm = new DatabaseTableModel(false);
dbm.setDataSource(rs);
Then you pass the TableModel to the "done()" method so that you can reset the table using the new TableModel.
Read the section from the Swing tutorial on Simple Background Tasks for an example that passes data from the "doInBackground()" method to the "done()" method by using the "return" statement and the "get()" method.