[英]Java JTable column loses TableCellRenderer when AbstractTableModel calls fireTableStructureChanged
我有一個 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
中為第一列提供一個唯一的 class 值。 然后,我可以將JProgressBar
渲染器設置為該列作為默認渲染器。
它使閱讀您的代碼的人更容易分離您的類並組織代碼,以便重要部分放在首位,然后是更詳細的部分。
無需擴展JPanel
或JProgressBar
。 The only time you should extend a Swing component, or any Java class, is when you want to override one or more of the class methods.
這是完整的可運行代碼。
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;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.