无法将 TableRowSorter 添加到 SwingWorker 生成的 JTable
Can't Add TableRowSorter to JTable Produced By SwingWorker
谢谢 Hovercraft Full Of Eels 注意到我的问题充满了混乱的代码,不太可能得到解决。从那时起,我创建了一个 "minimal" 测试程序来显示问题:
问题
我想要做的是有一个 GUI,显示包含员工信息的 table,并且还允许用户通过在 jtextfield 中键入来实时搜索所述 table gui的顶部。
所以我目前有一个 java class 创建一个 table 并用员工信息填充 table。此信息通过由 SwingWorker
处理的 SQL 语句放入 table 中。 GUI 工作得很好,直到我尝试将 TableRowSorter
添加到包含信息的 table,这会产生错误:
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Invalid range
at javax.swing.DefaultRowSorter.checkAgainstModel(Unknown Source)
at javax.swing.DefaultRowSorter.rowsInserted(Unknown Source)
at javax.swing.JTable.notifySorter(Unknown Source)
at javax.swing.JTable.sortedTableChanged(Unknown Source)
at javax.swing.JTable.tableChanged(Unknown Source)
at javax.swing.table.AbstractTableModel.fireTableChanged(Unknown Source)
at javax.swing.table.AbstractTableModel.fireTableRowsInserted(Unknown Source)
at tesPackage.WorkerTest$JDBCModel$JDBCWorker.process(WorkerTest.java:276)
基于此,这里是
工作示例
package tesPackage;
import java.awt.BorderLayout;
import java.util.concurrent.ThreadLocalRandom;
import java.awt.EventQueue;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
/**
* @see
* @see
*/
public class WorkerTest {
private static final int N = 25;
private static final String URL = "jdbc:h2:mem:test";
private static final Random r = new Random();
private JPanel contentPane;
private static JTable tblSchedule;
private JScrollPane scrollSchedTable;
private JDBCModel model;
private JPanel panel;
private JTextField textField;
private static TableRowSorter<TableModel> rowSorter;
private void display() {
createTestDatabase(N); //Create the Test Database
//Create the GUI
JFrame f = new JFrame("WorkerTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setBounds(100, 100, 780, 450);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
f.setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
{
scrollSchedTable = new JScrollPane();
scrollSchedTable.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
contentPane.add(scrollSchedTable);
{
tblSchedule = new JTable();
tblSchedule.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
tblSchedule.setShowHorizontalLines(true);
tblSchedule.setShowVerticalLines(true);
tblSchedule.setFillsViewportHeight(true);
model = new JDBCModel(getConnection(), "select * from city");
tblSchedule.setModel(model);
rowSorter = new TableRowSorter<TableModel>(model); //IF UNCOMMENT THESE 2 LINES GUI WILL RUN
tblSchedule.setRowSorter(rowSorter); //BUT IF TYPE IN SEARCH BOX THERE IS AN ERROR
scrollSchedTable.setViewportView(tblSchedule);
}
{
panel = new JPanel();
contentPane.add(panel, BorderLayout.NORTH);
panel.setLayout(new BorderLayout(0, 0));
{
textField = new JTextField();
panel.add(textField, BorderLayout.EAST);
textField.setColumns(10);
}
{
panel.add(model.jpb, BorderLayout.CENTER);
}
{
textField.getDocument().addDocumentListener(new DocumentListener(){
@Override
public void insertUpdate(DocumentEvent e) {
String text = textField.getText().trim();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
@Override
public void removeUpdate(DocumentEvent e) {
String text = textField.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
@Override
public void changedUpdate(DocumentEvent e) {
String text = textField.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
});
}
}
}
f.setVisible(true);
}
private static class Row {
String lname;
String fname;
String monTime;
String tueTime;
String wedTime;
String thuTime;
String friTime;
String satTime;
String sunTime;
String totalTime;
}
private static class JDBCModel extends AbstractTableModel {
private final JProgressBar jpb = new JProgressBar();
private static final long serialVersionUID = 1L;
private final List<Row> data = new ArrayList<>();
private ResultSet rs = null;
private ResultSetMetaData meta;
public JDBCModel(Connection conn, String query) {
try {
Statement s = conn.createStatement();
rs = s.executeQuery(query);
meta = rs.getMetaData();
JDBCWorker worker = new JDBCWorker();
jpb.setIndeterminate(true);
worker.execute();
} catch (SQLException e) {
e.printStackTrace(System.err);
}
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public int getColumnCount() {
return 10;
}
@Override
public Object getValueAt(int rowIndex, int colIndex) {
Row row = data.get(rowIndex);
switch (colIndex) {
case 0:
return row.lname;
case 1:
return row.fname;
case 2:
return row.monTime;
case 3:
return row.tueTime;
case 4:
return row.wedTime;
case 5:
return row.thuTime;
case 6:
return row.friTime;
case 7:
return row.satTime;
case 8:
return row.sunTime;
case 9:
return row.totalTime;
}
return null;
}
@Override
public String getColumnName(int colIndex) {
String name = null;
switch(colIndex){
case 0: name = "Last Name";
return name;
case 1: name = "First Name";
return name;
case 2: name = "Monday";
return name;
case 3: name = "Tuesday";
return name;
case 4: name = "Wednesday";
return name;
case 5: name = "Thursday";
return name;
case 6: name = "Friday";
return name;
case 7: name = "Saturday";
return name;
case 8: name = "Sunday";
return name;
case 9: name = "Total";
return name;
}
return name;
}
private class JDBCWorker extends SwingWorker<List<Row>, Row> {
@Override
protected List<Row> doInBackground() {
try {
while (rs.next()) {
Row r = new Row();
Integer total = 0;
r.lname = rs.getString(2);
r.fname = rs.getString(1);
r.monTime = String.valueOf(rs.getInt(3) + " - " + rs.getInt(4));
total += rs.getInt(4) - rs.getInt(3);
r.tueTime = String.valueOf(rs.getInt(5) + " - " + rs.getInt(6));
total += rs.getInt(6) - rs.getInt(5);
r.wedTime = String.valueOf(rs.getInt(7) + " - " + rs.getInt(8));
total += rs.getInt(8) - rs.getInt(7);
r.thuTime = String.valueOf(rs.getInt(9) + " - " + rs.getInt(10));
total += rs.getInt(10) - rs.getInt(9);
r.friTime = String.valueOf(rs.getInt(11) + " - " + rs.getInt(12));
total += rs.getInt(12) - rs.getInt(11);
r.satTime = String.valueOf(rs.getInt(13) + " - " + rs.getInt(14));
total += rs.getInt(14) - rs.getInt(13);
r.sunTime = String.valueOf(rs.getInt(15) + " - " + rs.getInt(16));
total += rs.getInt(16) - rs.getInt(15);
r.totalTime = String.valueOf(total);
publish(r);
}
} catch (SQLException e) {
e.printStackTrace(System.err);
}
return data;
}
@Override
protected void process(List<Row> chunks) {
int n = getRowCount() + 1;
System.out.println("Row Count = " + n);
System.out.println("Chunks Size = " + chunks.size());
for (Row row : chunks) {
data.add(row);
}
fireTableRowsInserted(n, n + chunks.size());
}
@Override
protected void done(){
jpb.setIndeterminate(false);
jpb.setValue(100);
}
}
}
//Creates the Test DB with test names and working hours
private static void createTestDatabase(int n) {
Connection conn = getConnection();
try {
Statement st = conn.createStatement();
st.execute("create table city(fname varchar(10), lname varchar(10), mons int(2), mone int(2), tues int(2), tuee int(2), weds int(2), wede int(2), thus int(2), thue int(2), fris int(2), frie int(2), sats int(2), sate int(2), suns int(2), sune int(2))");
Random gen = new Random();
PreparedStatement ps = conn.prepareStatement(
"insert into city values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
for (int i = 0; i < n; i++) {
ps.setString(1, "First" + i);
ps.setString(2, "Last" + i);
ps.setInt(3, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(4, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(5, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(6, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(7, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(8, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(9, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(10, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(11, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(12, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(13, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(14, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(15, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(16, ThreadLocalRandom.current().nextInt(13, 22));
ps.execute();
}
} catch (SQLException ex) {
ex.printStackTrace(System.err);
}
}
private static Connection getConnection() {
try {
return DriverManager.getConnection(URL, "", "");
} catch (SQLException e) {
e.printStackTrace(System.err);
}
return null;
}
public static void main(String[] args) {
EventQueue.invokeLater(new WorkerTest()::display);
}
}
编辑(仅 5 分钟后)
所以我开始在 eclipse 中使用调试功能,当我逐步执行该程序时,我发现一些名为 EDT.pumpOneEventForFilters(int)
的事件有一个名为 arg0
的变量(它是唯一的参数) -1
的值。一旦进入此事件,就会抛出异常。我不确定这是否是有用的信息,但我想我会把它扔出去以防万一。
原在process()
的实现中通知监听JTable
新行:
fireTableRowsInserted(n, n + chunks.size());
因为table排序过滤时需要考虑所有行,模型应该通知"listeners that all cell values in the table's rows may have changed."
fireTableDataChanged();
顺便说一句,ThreadLocalRandom
的单个实例在 createTestDatabase()
.
中就足够了
代码,经测试:
import java.awt.BorderLayout;
import java.util.concurrent.ThreadLocalRandom;
import java.awt.EventQueue;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
/**
* @see
* @see
* @see
*/
public class WorkerTest {
private static final int N = 256;
private static final String URL = "jdbc:h2:mem:test";
private static final Random r = new Random();
private JPanel contentPane;
private static JTable tblSchedule;
private JScrollPane scrollSchedTable;
private JDBCModel model;
private JPanel panel;
private JTextField textField;
private static TableRowSorter<TableModel> rowSorter;
private void display() {
createTestDatabase(N); //Create the Test Database
//Create the GUI
JFrame f = new JFrame("WorkerTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setBounds(100, 100, 780, 450);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
f.setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
scrollSchedTable = new JScrollPane();
scrollSchedTable.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
contentPane.add(scrollSchedTable);
tblSchedule = new JTable();
tblSchedule.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
tblSchedule.setShowHorizontalLines(true);
tblSchedule.setShowVerticalLines(true);
tblSchedule.setFillsViewportHeight(true);
model = new JDBCModel(getConnection(), "select * from city");
tblSchedule.setModel(model);
rowSorter = new TableRowSorter<TableModel>(model);
tblSchedule.setRowSorter(rowSorter);
scrollSchedTable.setViewportView(tblSchedule);
panel = new JPanel();
contentPane.add(panel, BorderLayout.NORTH);
panel.setLayout(new BorderLayout(0, 0));
textField = new JTextField();
panel.add(textField, BorderLayout.EAST);
textField.setColumns(10);
panel.add(model.jpb, BorderLayout.CENTER);
textField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
String text = textField.getText().trim();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
@Override
public void removeUpdate(DocumentEvent e) {
String text = textField.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
@Override
public void changedUpdate(DocumentEvent e) {
String text = textField.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
});
f.setVisible(true);
}
private static class Row {
String lname;
String fname;
String monTime;
String tueTime;
String wedTime;
String thuTime;
String friTime;
String satTime;
String sunTime;
String totalTime;
}
private static class JDBCModel extends AbstractTableModel {
private final JProgressBar jpb = new JProgressBar();
private static final long serialVersionUID = 1L;
private final List<Row> data = new ArrayList<>();
private ResultSet rs = null;
private ResultSetMetaData meta;
public JDBCModel(Connection conn, String query) {
try {
Statement s = conn.createStatement();
rs = s.executeQuery(query);
meta = rs.getMetaData();
JDBCWorker worker = new JDBCWorker();
jpb.setIndeterminate(true);
worker.execute();
} catch (SQLException e) {
e.printStackTrace(System.err);
}
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public int getColumnCount() {
return 10;
}
@Override
public Object getValueAt(int rowIndex, int colIndex) {
Row row = data.get(rowIndex);
switch (colIndex) {
case 0:
return row.lname;
case 1:
return row.fname;
case 2:
return row.monTime;
case 3:
return row.tueTime;
case 4:
return row.wedTime;
case 5:
return row.thuTime;
case 6:
return row.friTime;
case 7:
return row.satTime;
case 8:
return row.sunTime;
case 9:
return row.totalTime;
}
return null;
}
@Override
public String getColumnName(int colIndex) {
String name = null;
switch (colIndex) {
case 0:
name = "Last Name";
return name;
case 1:
name = "First Name";
return name;
case 2:
name = "Monday";
return name;
case 3:
name = "Tuesday";
return name;
case 4:
name = "Wednesday";
return name;
case 5:
name = "Thursday";
return name;
case 6:
name = "Friday";
return name;
case 7:
name = "Saturday";
return name;
case 8:
name = "Sunday";
return name;
case 9:
name = "Total";
return name;
}
return name;
}
private class JDBCWorker extends SwingWorker<List<Row>, Row> {
@Override
protected List<Row> doInBackground() {
try {
while (rs.next()) {
Row r = new Row();
Integer total = 0;
r.lname = rs.getString(2);
r.fname = rs.getString(1);
r.monTime = String.valueOf(rs.getInt(3) + " - " + rs.getInt(4));
total += rs.getInt(4) - rs.getInt(3);
r.tueTime = String.valueOf(rs.getInt(5) + " - " + rs.getInt(6));
total += rs.getInt(6) - rs.getInt(5);
r.wedTime = String.valueOf(rs.getInt(7) + " - " + rs.getInt(8));
total += rs.getInt(8) - rs.getInt(7);
r.thuTime = String.valueOf(rs.getInt(9) + " - " + rs.getInt(10));
total += rs.getInt(10) - rs.getInt(9);
r.friTime = String.valueOf(rs.getInt(11) + " - " + rs.getInt(12));
total += rs.getInt(12) - rs.getInt(11);
r.satTime = String.valueOf(rs.getInt(13) + " - " + rs.getInt(14));
total += rs.getInt(14) - rs.getInt(13);
r.sunTime = String.valueOf(rs.getInt(15) + " - " + rs.getInt(16));
total += rs.getInt(16) - rs.getInt(15);
r.totalTime = String.valueOf(total);
publish(r);
}
} catch (SQLException e) {
e.printStackTrace(System.err);
}
return data;
}
@Override
protected void process(List<Row> chunks) {
int n = getRowCount() + 1;
System.out.println("Row Count = " + n);
System.out.println("Chunks Size = " + chunks.size());
for (Row row : chunks) {
data.add(row);
}
fireTableDataChanged();
}
@Override
protected void done() {
jpb.setIndeterminate(false);
jpb.setValue(100);
}
}
}
//Creates the Test DB with test names and working hours
private static void createTestDatabase(int n) {
ThreadLocalRandom r = ThreadLocalRandom.current();
Connection conn = getConnection();
try {
Statement st = conn.createStatement();
st.execute("create table city(fname varchar(10), lname varchar(10), mons int(2), mone int(2), tues int(2), tuee int(2), weds int(2), wede int(2), thus int(2), thue int(2), fris int(2), frie int(2), sats int(2), sate int(2), suns int(2), sune int(2))");
Random gen = new Random();
PreparedStatement ps = conn.prepareStatement(
"insert into city values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
for (int i = 0; i < n; i++) {
ps.setString(1, "First" + i);
ps.setString(2, "Last" + i);
ps.setInt(3, r.nextInt(6, 12));
ps.setInt(4, r.nextInt(13, 22));
ps.setInt(5, r.nextInt(6, 12));
ps.setInt(6, r.nextInt(13, 22));
ps.setInt(7, r.nextInt(6, 12));
ps.setInt(8, r.nextInt(13, 22));
ps.setInt(9, r.nextInt(6, 12));
ps.setInt(10, r.nextInt(13, 22));
ps.setInt(11, r.nextInt(6, 12));
ps.setInt(12, r.nextInt(13, 22));
ps.setInt(13, r.nextInt(6, 12));
ps.setInt(14, r.nextInt(13, 22));
ps.setInt(15, r.nextInt(6, 12));
ps.setInt(16, r.nextInt(13, 22));
ps.execute();
}
} catch (SQLException ex) {
ex.printStackTrace(System.err);
}
}
private static Connection getConnection() {
try {
return DriverManager.getConnection(URL, "", "");
} catch (SQLException e) {
e.printStackTrace(System.err);
}
return null;
}
public static void main(String[] args) {
EventQueue.invokeLater(new WorkerTest()::display);
}
}
谢谢 Hovercraft Full Of Eels 注意到我的问题充满了混乱的代码,不太可能得到解决。从那时起,我创建了一个 "minimal" 测试程序来显示问题:
问题
我想要做的是有一个 GUI,显示包含员工信息的 table,并且还允许用户通过在 jtextfield 中键入来实时搜索所述 table gui的顶部。
所以我目前有一个 java class 创建一个 table 并用员工信息填充 table。此信息通过由 SwingWorker
处理的 SQL 语句放入 table 中。 GUI 工作得很好,直到我尝试将 TableRowSorter
添加到包含信息的 table,这会产生错误:
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Invalid range
at javax.swing.DefaultRowSorter.checkAgainstModel(Unknown Source)
at javax.swing.DefaultRowSorter.rowsInserted(Unknown Source)
at javax.swing.JTable.notifySorter(Unknown Source)
at javax.swing.JTable.sortedTableChanged(Unknown Source)
at javax.swing.JTable.tableChanged(Unknown Source)
at javax.swing.table.AbstractTableModel.fireTableChanged(Unknown Source)
at javax.swing.table.AbstractTableModel.fireTableRowsInserted(Unknown Source)
at tesPackage.WorkerTest$JDBCModel$JDBCWorker.process(WorkerTest.java:276)
基于此
工作示例
package tesPackage;
import java.awt.BorderLayout;
import java.util.concurrent.ThreadLocalRandom;
import java.awt.EventQueue;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
/**
* @see
* @see
*/
public class WorkerTest {
private static final int N = 25;
private static final String URL = "jdbc:h2:mem:test";
private static final Random r = new Random();
private JPanel contentPane;
private static JTable tblSchedule;
private JScrollPane scrollSchedTable;
private JDBCModel model;
private JPanel panel;
private JTextField textField;
private static TableRowSorter<TableModel> rowSorter;
private void display() {
createTestDatabase(N); //Create the Test Database
//Create the GUI
JFrame f = new JFrame("WorkerTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setBounds(100, 100, 780, 450);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
f.setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
{
scrollSchedTable = new JScrollPane();
scrollSchedTable.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
contentPane.add(scrollSchedTable);
{
tblSchedule = new JTable();
tblSchedule.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
tblSchedule.setShowHorizontalLines(true);
tblSchedule.setShowVerticalLines(true);
tblSchedule.setFillsViewportHeight(true);
model = new JDBCModel(getConnection(), "select * from city");
tblSchedule.setModel(model);
rowSorter = new TableRowSorter<TableModel>(model); //IF UNCOMMENT THESE 2 LINES GUI WILL RUN
tblSchedule.setRowSorter(rowSorter); //BUT IF TYPE IN SEARCH BOX THERE IS AN ERROR
scrollSchedTable.setViewportView(tblSchedule);
}
{
panel = new JPanel();
contentPane.add(panel, BorderLayout.NORTH);
panel.setLayout(new BorderLayout(0, 0));
{
textField = new JTextField();
panel.add(textField, BorderLayout.EAST);
textField.setColumns(10);
}
{
panel.add(model.jpb, BorderLayout.CENTER);
}
{
textField.getDocument().addDocumentListener(new DocumentListener(){
@Override
public void insertUpdate(DocumentEvent e) {
String text = textField.getText().trim();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
@Override
public void removeUpdate(DocumentEvent e) {
String text = textField.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
@Override
public void changedUpdate(DocumentEvent e) {
String text = textField.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
});
}
}
}
f.setVisible(true);
}
private static class Row {
String lname;
String fname;
String monTime;
String tueTime;
String wedTime;
String thuTime;
String friTime;
String satTime;
String sunTime;
String totalTime;
}
private static class JDBCModel extends AbstractTableModel {
private final JProgressBar jpb = new JProgressBar();
private static final long serialVersionUID = 1L;
private final List<Row> data = new ArrayList<>();
private ResultSet rs = null;
private ResultSetMetaData meta;
public JDBCModel(Connection conn, String query) {
try {
Statement s = conn.createStatement();
rs = s.executeQuery(query);
meta = rs.getMetaData();
JDBCWorker worker = new JDBCWorker();
jpb.setIndeterminate(true);
worker.execute();
} catch (SQLException e) {
e.printStackTrace(System.err);
}
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public int getColumnCount() {
return 10;
}
@Override
public Object getValueAt(int rowIndex, int colIndex) {
Row row = data.get(rowIndex);
switch (colIndex) {
case 0:
return row.lname;
case 1:
return row.fname;
case 2:
return row.monTime;
case 3:
return row.tueTime;
case 4:
return row.wedTime;
case 5:
return row.thuTime;
case 6:
return row.friTime;
case 7:
return row.satTime;
case 8:
return row.sunTime;
case 9:
return row.totalTime;
}
return null;
}
@Override
public String getColumnName(int colIndex) {
String name = null;
switch(colIndex){
case 0: name = "Last Name";
return name;
case 1: name = "First Name";
return name;
case 2: name = "Monday";
return name;
case 3: name = "Tuesday";
return name;
case 4: name = "Wednesday";
return name;
case 5: name = "Thursday";
return name;
case 6: name = "Friday";
return name;
case 7: name = "Saturday";
return name;
case 8: name = "Sunday";
return name;
case 9: name = "Total";
return name;
}
return name;
}
private class JDBCWorker extends SwingWorker<List<Row>, Row> {
@Override
protected List<Row> doInBackground() {
try {
while (rs.next()) {
Row r = new Row();
Integer total = 0;
r.lname = rs.getString(2);
r.fname = rs.getString(1);
r.monTime = String.valueOf(rs.getInt(3) + " - " + rs.getInt(4));
total += rs.getInt(4) - rs.getInt(3);
r.tueTime = String.valueOf(rs.getInt(5) + " - " + rs.getInt(6));
total += rs.getInt(6) - rs.getInt(5);
r.wedTime = String.valueOf(rs.getInt(7) + " - " + rs.getInt(8));
total += rs.getInt(8) - rs.getInt(7);
r.thuTime = String.valueOf(rs.getInt(9) + " - " + rs.getInt(10));
total += rs.getInt(10) - rs.getInt(9);
r.friTime = String.valueOf(rs.getInt(11) + " - " + rs.getInt(12));
total += rs.getInt(12) - rs.getInt(11);
r.satTime = String.valueOf(rs.getInt(13) + " - " + rs.getInt(14));
total += rs.getInt(14) - rs.getInt(13);
r.sunTime = String.valueOf(rs.getInt(15) + " - " + rs.getInt(16));
total += rs.getInt(16) - rs.getInt(15);
r.totalTime = String.valueOf(total);
publish(r);
}
} catch (SQLException e) {
e.printStackTrace(System.err);
}
return data;
}
@Override
protected void process(List<Row> chunks) {
int n = getRowCount() + 1;
System.out.println("Row Count = " + n);
System.out.println("Chunks Size = " + chunks.size());
for (Row row : chunks) {
data.add(row);
}
fireTableRowsInserted(n, n + chunks.size());
}
@Override
protected void done(){
jpb.setIndeterminate(false);
jpb.setValue(100);
}
}
}
//Creates the Test DB with test names and working hours
private static void createTestDatabase(int n) {
Connection conn = getConnection();
try {
Statement st = conn.createStatement();
st.execute("create table city(fname varchar(10), lname varchar(10), mons int(2), mone int(2), tues int(2), tuee int(2), weds int(2), wede int(2), thus int(2), thue int(2), fris int(2), frie int(2), sats int(2), sate int(2), suns int(2), sune int(2))");
Random gen = new Random();
PreparedStatement ps = conn.prepareStatement(
"insert into city values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
for (int i = 0; i < n; i++) {
ps.setString(1, "First" + i);
ps.setString(2, "Last" + i);
ps.setInt(3, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(4, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(5, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(6, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(7, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(8, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(9, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(10, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(11, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(12, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(13, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(14, ThreadLocalRandom.current().nextInt(13, 22));
ps.setInt(15, ThreadLocalRandom.current().nextInt(6, 12));
ps.setInt(16, ThreadLocalRandom.current().nextInt(13, 22));
ps.execute();
}
} catch (SQLException ex) {
ex.printStackTrace(System.err);
}
}
private static Connection getConnection() {
try {
return DriverManager.getConnection(URL, "", "");
} catch (SQLException e) {
e.printStackTrace(System.err);
}
return null;
}
public static void main(String[] args) {
EventQueue.invokeLater(new WorkerTest()::display);
}
}
编辑(仅 5 分钟后)
所以我开始在 eclipse 中使用调试功能,当我逐步执行该程序时,我发现一些名为 EDT.pumpOneEventForFilters(int)
的事件有一个名为 arg0
的变量(它是唯一的参数) -1
的值。一旦进入此事件,就会抛出异常。我不确定这是否是有用的信息,但我想我会把它扔出去以防万一。
原process()
的实现中通知监听JTable
新行:
fireTableRowsInserted(n, n + chunks.size());
因为table排序过滤时需要考虑所有行,模型应该通知"listeners that all cell values in the table's rows may have changed."
fireTableDataChanged();
顺便说一句,ThreadLocalRandom
的单个实例在 createTestDatabase()
.
代码,经测试:
import java.awt.BorderLayout;
import java.util.concurrent.ThreadLocalRandom;
import java.awt.EventQueue;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
/**
* @see
* @see
* @see
*/
public class WorkerTest {
private static final int N = 256;
private static final String URL = "jdbc:h2:mem:test";
private static final Random r = new Random();
private JPanel contentPane;
private static JTable tblSchedule;
private JScrollPane scrollSchedTable;
private JDBCModel model;
private JPanel panel;
private JTextField textField;
private static TableRowSorter<TableModel> rowSorter;
private void display() {
createTestDatabase(N); //Create the Test Database
//Create the GUI
JFrame f = new JFrame("WorkerTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setBounds(100, 100, 780, 450);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
f.setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
scrollSchedTable = new JScrollPane();
scrollSchedTable.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
contentPane.add(scrollSchedTable);
tblSchedule = new JTable();
tblSchedule.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
tblSchedule.setShowHorizontalLines(true);
tblSchedule.setShowVerticalLines(true);
tblSchedule.setFillsViewportHeight(true);
model = new JDBCModel(getConnection(), "select * from city");
tblSchedule.setModel(model);
rowSorter = new TableRowSorter<TableModel>(model);
tblSchedule.setRowSorter(rowSorter);
scrollSchedTable.setViewportView(tblSchedule);
panel = new JPanel();
contentPane.add(panel, BorderLayout.NORTH);
panel.setLayout(new BorderLayout(0, 0));
textField = new JTextField();
panel.add(textField, BorderLayout.EAST);
textField.setColumns(10);
panel.add(model.jpb, BorderLayout.CENTER);
textField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
String text = textField.getText().trim();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
@Override
public void removeUpdate(DocumentEvent e) {
String text = textField.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
@Override
public void changedUpdate(DocumentEvent e) {
String text = textField.getText();
if (text.trim().length() == 0) {
rowSorter.setRowFilter(null);
} else {
rowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
});
f.setVisible(true);
}
private static class Row {
String lname;
String fname;
String monTime;
String tueTime;
String wedTime;
String thuTime;
String friTime;
String satTime;
String sunTime;
String totalTime;
}
private static class JDBCModel extends AbstractTableModel {
private final JProgressBar jpb = new JProgressBar();
private static final long serialVersionUID = 1L;
private final List<Row> data = new ArrayList<>();
private ResultSet rs = null;
private ResultSetMetaData meta;
public JDBCModel(Connection conn, String query) {
try {
Statement s = conn.createStatement();
rs = s.executeQuery(query);
meta = rs.getMetaData();
JDBCWorker worker = new JDBCWorker();
jpb.setIndeterminate(true);
worker.execute();
} catch (SQLException e) {
e.printStackTrace(System.err);
}
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public int getColumnCount() {
return 10;
}
@Override
public Object getValueAt(int rowIndex, int colIndex) {
Row row = data.get(rowIndex);
switch (colIndex) {
case 0:
return row.lname;
case 1:
return row.fname;
case 2:
return row.monTime;
case 3:
return row.tueTime;
case 4:
return row.wedTime;
case 5:
return row.thuTime;
case 6:
return row.friTime;
case 7:
return row.satTime;
case 8:
return row.sunTime;
case 9:
return row.totalTime;
}
return null;
}
@Override
public String getColumnName(int colIndex) {
String name = null;
switch (colIndex) {
case 0:
name = "Last Name";
return name;
case 1:
name = "First Name";
return name;
case 2:
name = "Monday";
return name;
case 3:
name = "Tuesday";
return name;
case 4:
name = "Wednesday";
return name;
case 5:
name = "Thursday";
return name;
case 6:
name = "Friday";
return name;
case 7:
name = "Saturday";
return name;
case 8:
name = "Sunday";
return name;
case 9:
name = "Total";
return name;
}
return name;
}
private class JDBCWorker extends SwingWorker<List<Row>, Row> {
@Override
protected List<Row> doInBackground() {
try {
while (rs.next()) {
Row r = new Row();
Integer total = 0;
r.lname = rs.getString(2);
r.fname = rs.getString(1);
r.monTime = String.valueOf(rs.getInt(3) + " - " + rs.getInt(4));
total += rs.getInt(4) - rs.getInt(3);
r.tueTime = String.valueOf(rs.getInt(5) + " - " + rs.getInt(6));
total += rs.getInt(6) - rs.getInt(5);
r.wedTime = String.valueOf(rs.getInt(7) + " - " + rs.getInt(8));
total += rs.getInt(8) - rs.getInt(7);
r.thuTime = String.valueOf(rs.getInt(9) + " - " + rs.getInt(10));
total += rs.getInt(10) - rs.getInt(9);
r.friTime = String.valueOf(rs.getInt(11) + " - " + rs.getInt(12));
total += rs.getInt(12) - rs.getInt(11);
r.satTime = String.valueOf(rs.getInt(13) + " - " + rs.getInt(14));
total += rs.getInt(14) - rs.getInt(13);
r.sunTime = String.valueOf(rs.getInt(15) + " - " + rs.getInt(16));
total += rs.getInt(16) - rs.getInt(15);
r.totalTime = String.valueOf(total);
publish(r);
}
} catch (SQLException e) {
e.printStackTrace(System.err);
}
return data;
}
@Override
protected void process(List<Row> chunks) {
int n = getRowCount() + 1;
System.out.println("Row Count = " + n);
System.out.println("Chunks Size = " + chunks.size());
for (Row row : chunks) {
data.add(row);
}
fireTableDataChanged();
}
@Override
protected void done() {
jpb.setIndeterminate(false);
jpb.setValue(100);
}
}
}
//Creates the Test DB with test names and working hours
private static void createTestDatabase(int n) {
ThreadLocalRandom r = ThreadLocalRandom.current();
Connection conn = getConnection();
try {
Statement st = conn.createStatement();
st.execute("create table city(fname varchar(10), lname varchar(10), mons int(2), mone int(2), tues int(2), tuee int(2), weds int(2), wede int(2), thus int(2), thue int(2), fris int(2), frie int(2), sats int(2), sate int(2), suns int(2), sune int(2))");
Random gen = new Random();
PreparedStatement ps = conn.prepareStatement(
"insert into city values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
for (int i = 0; i < n; i++) {
ps.setString(1, "First" + i);
ps.setString(2, "Last" + i);
ps.setInt(3, r.nextInt(6, 12));
ps.setInt(4, r.nextInt(13, 22));
ps.setInt(5, r.nextInt(6, 12));
ps.setInt(6, r.nextInt(13, 22));
ps.setInt(7, r.nextInt(6, 12));
ps.setInt(8, r.nextInt(13, 22));
ps.setInt(9, r.nextInt(6, 12));
ps.setInt(10, r.nextInt(13, 22));
ps.setInt(11, r.nextInt(6, 12));
ps.setInt(12, r.nextInt(13, 22));
ps.setInt(13, r.nextInt(6, 12));
ps.setInt(14, r.nextInt(13, 22));
ps.setInt(15, r.nextInt(6, 12));
ps.setInt(16, r.nextInt(13, 22));
ps.execute();
}
} catch (SQLException ex) {
ex.printStackTrace(System.err);
}
}
private static Connection getConnection() {
try {
return DriverManager.getConnection(URL, "", "");
} catch (SQLException e) {
e.printStackTrace(System.err);
}
return null;
}
public static void main(String[] args) {
EventQueue.invokeLater(new WorkerTest()::display);
}
}