![](/img/trans.png)
[英]JComboBox in JTable does not update table instantly on item change
[英]Change/Update JTable content with JComboBox(category)
我的JTable有问题。 我的JTable显示数据库的内容。 一个数据库表具有名称类别。 每个类别都显示在JComboBox中。 如果单击类别,则应该更新表内容。
这是我的代码的简短摘要,因此可以更轻松地为我提供帮助。 该代码应可运行:
(TestClass-主要)
package test;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class TestClass implements ActionListener{
String[] header = {"head", "head", "head"};
Object[][] data = {{Boolean.FALSE, "text", "text"}, {Boolean.FALSE, "text", "text"}, {Boolean.FALSE, "text", "text"}};
LinkedList<String> newdata = new LinkedList<String>();
String[] combolist = {"apple", "banana", "cranberry"};
JComboBox<String> combobox = new JComboBox<String>(combolist);
JTable table = new JTable(new TestTableModel(data, header));
JFrame frame = new JFrame();
JPanel panel = new JPanel(new GridLayout(1, 0, 1, 0));
public TestClass() {
combobox.addActionListener(this);
panel.add(combobox);
frame.add(panel, BorderLayout.NORTH);
frame.add(new JScrollPane(table), BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
frame.pack();
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == this.combobox) {
JComboBox<String> combobox = this.combobox;
newdata.add("Test1");
newdata.add("Test2");
TestTableModel model = (TestTableModel) table.getModel();
int i = 0;
for (String text : newdata) {
data[i][0] = Boolean.TRUE;
data[i][1] = text;
data[i][2] = text;
i++;
}
model.setData(data);
}
}
public static void main(String[] args) {
new TestClass();
}
}
(如果需要,则为TestTableModel-AbstractTableModel(您需要它来执行代码!)
package test;
import javax.swing.table.AbstractTableModel;
public class TestTableModel extends AbstractTableModel {
private static final long serialVersionUID = 5044877015250409328L;
private String[] header;
private Object[][] data;
public TestTableModel(Object[][] data, String[] header) {
this.header = header;
this.data = data;
}
public void setData(Object[][] data) {
this.data = data;
fireTableDataChanged();
}
@Override
public Class<?> getColumnClass(int column) {
if (column == 0) {
return Boolean.class;
}
return super.getColumnClass(column);
}
@Override
public int getColumnCount() {
return header.length;
}
@Override
public String getColumnName(int column) {
return header[column];
}
@Override
public int getRowCount() {
return data.length;
}
@Override
public Object getValueAt(int row, int column) {
return data[row][column];
}
@Override
public boolean isCellEditable(int row, int column) {
return column == 0;
}
@Override
public void setValueAt(Object value, int row, int column) {
data[row][column] = value;
}
}
使用此短代码,如果更改类别,表格将冻结。 在我的整个代码中,它也冻结了,但是当我调整窗口大小时(表调整为与框架相同的大小),我能够在后台看到更新的Table。 我不知道为什么它不被抢断。
编辑:更改内容的问题已解决。 源已更新。 但是获得正确表大小的问题已经解决。 在源代码中,首先使用3行数组,然后使用2行数组。 我想删除旧表并创建一个新表,所以行大小正确。
基本上,我只想用新内容更新表。
该代码有错误,因为每次调用actionPerformed()
,您都在创建一个新组件:
table = new JTable(new TestTableModel(data, header));
frame.add(new JScrollPane( table )); // <-- BTW: here you need to put the table otherwise you are adding an empty JScrollPane
frame.validate();
(注意:还有一个错误,@ mKorbel提到了)。
但是,您已经在框架中添加了带有JTable
的JScrollPane
,并且它们仍然存在。 (如果您尝试调整窗口大小,则会在旧表下方看到新表)。
更新表数据的正确方法是让其TableModel
进行模型中所需的任何修改,然后根据您所做的更改,触发适当的fireXXX()
方法来通知表重新绘制自身。
作为一个粗略的示例,您的代码将是:
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == this.combobox) {
JComboBox<String> combobox = this.combobox;
newdata.clear(); // Clear your list or create a new one otherwise data will keep piling up.
newdata.add("Test1");
newdata.add("Test2");
TestTableModel model = (TestTableModel) table.getModel();
// Since you need to replace the whole data create a new Object[][] each time
Object[][] newModelData = new Object[newdata.size()][3];
// Set whatever data to the new array
int i = 0;
for (String text : newdata) {
newModelData[i][0] = Boolean.TRUE;
newModelData[i][1] = text;
newModelData[i][2] = text;
i++;
}
// replace all data of the current model
model.setData(newModelData);
}
}
....
// Now inside your table model:
...
@Override
public Class<?> getColumnClass(int column) {
// if (column == 0) {
// return Boolean.class; // <-- this produces a ClassCastException with the data you aretrying to set
// }
return super.getColumnClass(column);
}
public void setData(Object[][] data) {
this.data = data; // <-- Update the data
fireTableDataChanged(); // <-- fire the event so the table is notified. If you change only one cell you need to call the appropriate fire event
}
...
更新1:新代码的问题已修复了更新模型中数据的方式。 但是,更新data
结构时存在逻辑缺陷。 此变量以3行的数组开始。 在actionPerformed()
方法中,对只有2个条目的newdata
列表的长度执行循环。 因此,您仅更新模型的前2行。
更新2:似乎您错过了重点。 在这里,如何更新模型很重要。 该表将显示您的模型拥有的所有数据。 如果您仅更新2行,但不更改第3行,则该表将显示3行(新2行和旧1行)。 由于每次都需要更改所有数据,因此需要完全替换模型中的数据 。 每次都需要重新创建您的数据,而不是表。 请参阅更新代码示例。 我添加了actionPerformed()
方法,该方法使用您当前的源代码重新初始化数据。 请阅读内联注释。
更改jtable中的数据后,请尝试以下代码。
model.fireTableDataChanged(); table.repaint();
其中model是tablemodel对象,而table是JTable对象
希望对您有所帮助!!!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.