如何解决当 AbstractTableModel 调用 fireTableStructureChanged 时,Java JTable 列丢失 TableCellRenderer
我有一个 JTable,我想在其中使用 JProgressBar 来呈现其中一列中的数据。我可以通过调用 setCellRenderer() 来做到这一点。
但是,我还有一个 SwingWorker,它可以修改我的 AbstractTableModel 以向表中添加一列,在这种情况下,我调用了 fireTableStructureChanged()。不幸的是,这会导致我的列丢失自定义 TableCellRenderer。
我尝试过 setautocreateColumnsFromModel(false),但这会阻止我的 AbstractTableModel 添加新列。这是我的代码:
package components;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
public class LostRenderer extends JPanel {
private static final long serialVersionUID = 1L;
// Make the JTable a field,so inner class TableCellTask can access it
private final JTable table;
public class ProgressBarCellRenderer extends JProgressBar implements TableCellRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) {
setValue((int) value);
return this;
}
}
public LostRenderer() {
super(new GridLayout(1,0));
MyTableModel myTableModel = new MyTableModel();
table = new JTable(myTableModel);
table.setPreferredScrollableViewportSize(new Dimension(500,70));
table.setFillsViewportHeight(true);
table.getColumn("Progress").setCellRenderer(new ProgressBarCellRenderer());
/*
* NOTE: table.setautocreateColumnsFromModel(true); (or commenting out the call)
* results in the column renderer getting lost when table structure is changes.
* Setting it to false maintains column renderer,but no new columns get added.
*/
table.setautocreateColumnsFromModel(true);
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
//Add the scroll pane to this panel.
add(scrollPane);
new TableCellTask(myTableModel).execute();
}
private class TableCellTask extends SwingWorker<Void,Integer> {
private final MyTableModel myTableModel;
public TableCellTask(MyTableModel myTableModel) {
this.myTableModel = myTableModel;
}
@Override
protected Void doInBackground() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
publish(new Integer( 0));
return null;
}
@Override
protected void process(List<Integer> tableCells) {
for (int tableCell : tableCells) {
myTableModel.process(tableCell);
}
}
}
class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private List<Integer> data = new ArrayList<Integer>();
public int getColumnCount() {
return data.size() + 1;
}
public int getRowCount() {
return 1;
}
public String getColumnName(int col) {
if (col == 0) {
return "Progress";
} else {
return "Data" + col;
}
}
public Object getValueAt(int row,int col) {
if (col == 0) {
return 50;
} else {
return data.get(col - 1);
}
}
public Class<?> getColumnClass(int c) {
return getValueAt(0,c).getClass();
}
public void process(int value) {
data.add(value);
fireTableStructureChanged();
}
}
/**
* Create the GUI and show it. For thread safety,* this method should be invoked from the
* event-dispatching thread.
*
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("LostRenderer");
frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
LostRenderer newContentPane = new LostRenderer();
newContentPane.setopaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokelater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
这是表格开始时的样子(使用正确的 JProgressBar 渲染):
这是我添加列后的样子(列丢失了 JProgressBar 渲染):
如有任何建议,我们将不胜感激。
解决方法
我不得不重新排列您的代码,但我想出了以下 GUI。
2 秒后。
我所做的主要更改是在您的 TableModel
中为第一列指定一个唯一的类值。然后,我可以将 JProgressBar
渲染器设置为该列作为默认渲染器。
它使阅读您代码的人更容易分离您的类并组织代码,以便重要的部分在前,更详细的部分在后。
无需扩展 JPanel
或 JProgressBar
。您应该扩展 Swing 组件或任何 Java 类的唯一时间是当您想要覆盖一个或多个类方法时。
这是完整的可运行代码。
import java.awt.BorderLayout;
import java.awt.Component;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
public class JTableRendererGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new JTableRendererGUI());
}
private JTable table;
private MyTableModel myTableModel;
public JTableRendererGUI() {
this.myTableModel = new MyTableModel();
}
@Override
public void run() {
JFrame frame = new JFrame("JTable Renderer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(),BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
new TableCellTask(myTableModel).execute();
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
table = new JTable(myTableModel);
table.setDefaultRenderer(MyTableModel.class,new ProgressBarCellRenderer());
table.setAutoCreateColumnsFromModel(true);
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
panel.add(scrollPane,BorderLayout.CENTER);
return panel;
}
public class TableCellTask extends SwingWorker<Void,Integer> {
private final MyTableModel myTableModel;
public TableCellTask(MyTableModel myTableModel) {
this.myTableModel = myTableModel;
}
@Override
protected Void doInBackground() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
publish(0);
return null;
}
@Override
protected void process(List<Integer> tableCells) {
for (int tableCell : tableCells) {
myTableModel.process(tableCell);
}
}
}
public class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private List<Integer> data = new ArrayList<Integer>();
public int getColumnCount() {
return data.size() + 1;
}
public int getRowCount() {
return 1;
}
public String getColumnName(int col) {
if (col == 0) {
return "Progress";
} else {
return "Data" + col;
}
}
public Object getValueAt(int row,int col) {
if (col == 0) {
return 50;
} else {
return data.get(col - 1);
}
}
public Class<?> getColumnClass(int c) {
if (c == 0) {
return MyTableModel.class;
} else {
return getValueAt(0,c).getClass();
}
}
public void process(int value) {
data.add(value);
fireTableStructureChanged();
}
}
public class ProgressBarCellRenderer implements TableCellRenderer {
private JProgressBar progressBar;
public ProgressBarCellRenderer() {
this.progressBar = new JProgressBar();
}
@Override
public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) {
progressBar.setValue((int) value);
return progressBar;
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。