我使用此代码并获取错误 java.lang.ArrayIndexOutOfBoundsException 。我知道问题是多线程和EDT 。我读到了使用方法 publish(),但我不知道如何使用它,我不知道如何更改代码以纠正错误。请告诉我如何更改代码以避免任何错误。感谢你! 错误消息:
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)
主要类别:
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);
}
}
}
}
答案 0 :(得分:1)
不需要&#34;同步&#34; TableModel中的逻辑。当事件调度线程被添加到JTable时,应该更新TableModel。
所以我建议不要使用:
dbm = new DatabaseTableModel(false);
JTable table = new JTable(dbm);
您在SwingWorker中创建TableModel。然后在&#34;完成()&#34;您可以使用的SwingWorker方法:
table.setModel( )
&#34;完成()&#34;中的代码方法在Event Dispatch Thread上执行,因此您可以安全地重置表的模型。
编辑:
使用以下代码创建一个新的TableModel:
DatabaseTableModel dbm = new DatabaseTableModel(false);
dbm.setDataSource(rs);
然后将TableModel传递给&#34; done()&#34;方法,以便您可以使用新的TableModel重置表。
阅读Simple Background Tasks上Swing教程中的部分,了解从&#34; doInBackground()&#34;传递数据的示例。 &#34; done()&#34;的方法方法使用&#34; return&#34;声明和&#34; get()&#34;方法
答案 1 :(得分:1)
看起来两个线程同时访问数据库表模型。每次DatabaseTableModel.setDataSource
调用方法,清除columnNames
和columnTypes
字段。从堆栈跟踪中我得到的印象是
EDT正在布置表头并尝试获取列数据,而数据库表模型被另一个擦除
线程。
在SwingWorker
文档(http://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html)中,一名工作人员
描述了一个线程,其中应用程序可以在不进行GUI相关活动的情况下完成耗时的工作。在你的
例如,doInBackground()
方法可以查询数据库并以正确的格式获取数据。 done()
方法可以
然后更新数据库表模型并通知所有更改的侦听器(JTable
对象)。
您当前的doInBackground()
方法执行与GUI相关的工作。你可以通过存储数据(和列信息)来改变这一点
在单独的字段中(在Task
类中)。之前可以将前三行移动到btnNewButton动作侦听器
致电task.execute()
。
获取doInBackground()
方法中的数据/列可能看起来有点像这个虚拟示例:
// Dummy data to test without a database.
if (columnNames.size() == 0) {
columnNames = new ArrayList<>(Arrays.asList("A", "B", "C"));
columnTypes = new ArrayList<>(Arrays.asList(String.class, String.class, String.class));
}
data = new ArrayList();
data.add(new ArrayList<>(Arrays.asList(data.size(), data.size() + 1, data.size() + 2)));
可以将此代码添加到done()
方法的开头,以将数据/列传输到数据库表模型
并通知听众:
dbm.updateModel(columnNames, columnTypes, data);
System.out.println("Task.done - dbm.getRowCount() = " + dbm.getRowCount());
if (dbm.getRowCount() == 1)
dbm.fireTableStructureChanged();
dbm.fireTableRowsInserted(dbm.getRowCount() - 1, dbm.getRowCount() - 1);
更新数据库表模型的方法如下所示:
public void updateModel(ArrayList columnNames, ArrayList columnTypes, ArrayList data) {
if (columnNames != null && columnTypes != null) {
this.columnNames = columnNames;
this.columnTypes = columnTypes;
}
this.data = data;
//this.data.addAll(data);
}
此Stack Overflow问题&amp;回答处理类似的问题: Java Swing: Jtable ArrayIndexOutOfBoundsException