Java 如何使用setAutoCreateColumnsFromModel(false)从TableModel和TableColumnModel中删除JTable列?
请参见最后的我的SSCCE代码。我想要实现的是:Java 如何使用setAutoCreateColumnsFromModel(false)从TableModel和TableColumnModel中删除JTable列?,java,swing,jtable,Java,Swing,Jtable,请参见最后的我的SSCCE代码。我想要实现的是: 数据模型和列模型中的列数相等 使用setAutoCreateColumnsFromModel(false)避免在数据/表模型添加或删除列时重新创建列模型 移动列的能力 “大”按钮会在末尾添加一个新列。每个新列都获得一个唯一标识符 标题有一个右键单击菜单HeaderMenu,可以删除列。计时器调用table.tableModel.addRow()在顶部插入新行。每列的数据由classcolumn生成。在这个演示中,值只是一个带有列标识符的行计
- 数据模型和列模型中的列数相等
- 使用
避免在数据/表模型添加或删除列时重新创建列模型setAutoCreateColumnsFromModel(false)
- 移动列的能力
HeaderMenu
,可以删除列。计时器调用table.tableModel.addRow()
在顶部插入新行。每列的数据由classcolumn
生成。在这个演示中,值只是一个带有列标识符的行计数器
在实际表格中(不是本演示)
- 每个列都是
的子类,并生成有意义的数据column
- 该菜单还包含“插入左/右”和“替换”。这是通过使用与演示的添加/删除方法类似的方法以及将列移动到所需位置来实现的
- 数据模型可能包含十几列和超过一百万行
- 行的添加时间间隔可能在毫秒到几秒之间,即性能问题
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 2 >= 2
at java.util.Vector.elementAt(Vector.java:477)
at javax.swing.table.DefaultTableModel.getValueAt(DefaultTableModel.java:649)
at javax.swing.JTable.getValueAt(JTable.java:2720)
at javax.swing.JTable.prepareRenderer(JTable.java:5712)
at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2114)
...
请告知如何修理。以下是完整的代码:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
@SuppressWarnings("serial")
public class TableDemo extends JTable {
private static class Column {
private int rowsCounter = 0;
private final String identifier;
public Column(String identifier) {
this.identifier = identifier;
}
private String nextCellValue() {
return (rowsCounter++) + ", id: " + identifier;
}
}
private static class MyTableModel extends DefaultTableModel {
private final List<Column> columns = new ArrayList<>();
private int nextColumnIdentifier = 0;
private void addRow() {
Object[] row = columns.stream().map(Column::nextCellValue).toArray();
insertRow(0, row);
}
private TableColumn addColumn() {
String identifier = String.valueOf(nextColumnIdentifier++);
columns.add(new Column(identifier));
addColumn(identifier);
TableColumn tc = new TableColumn();
tc.setIdentifier(identifier);
tc.setHeaderValue(identifier);
tc.setModelIndex(columns.size() - 1);
return tc;
}
private void removeColumn(int idx) {
columns.remove(idx);
columnIdentifiers.remove(idx);
for (Object row : dataVector) {
((Vector<?>) row).remove(idx);
}
fireTableStructureChanged();
}
}
private static class HeaderMenu extends JPopupMenu {
private int columnViewIndex;
private HeaderMenu(final TableDemo table) {
JMenuItem item = new JMenuItem("Delete column");
item.addActionListener(e -> table.deleteColumn(columnViewIndex));
add(item);
final MouseAdapter ma = new MouseAdapter() {
boolean dragged = false;
@Override
public void mouseReleased(MouseEvent e) {
if (!dragged && e.getButton() == MouseEvent.BUTTON3) {
final Point p = e.getPoint();
SwingUtilities.invokeLater(() -> {
columnViewIndex = table.columnAtPoint(p);
show(e.getComponent(), p.x, p.y);
});
}
dragged = false;
}
@Override
public void mouseDragged(MouseEvent e) {
dragged = true;
}
};
table.getTableHeader().addMouseListener(ma);
table.getTableHeader().addMouseMotionListener(ma);
}
}
private MyTableModel tableModel = new MyTableModel();
private TableDemo() {
new HeaderMenu(this);
setModel(tableModel);
setAutoCreateColumnsFromModel(false);
setDefaultEditor(Object.class, null);
}
private void addColumn() {
TableColumn tc = tableModel.addColumn();
addColumn(tc);
}
void deleteColumn(int idxView) {
TableColumn tc = getColumnModel().getColumn(idxView);
tableModel.removeColumn(tc.getModelIndex());
removeColumn(tc);
}
private static void buildAndShowGui() {
TableDemo table = new TableDemo();
table.setPreferredScrollableViewportSize(new Dimension(800, 300));
table.setFillsViewportHeight(true);
JScrollPane tableScrollPane = new JScrollPane(table);
JButton buttonAdd = new JButton("Add column");
buttonAdd.addActionListener(e -> table.addColumn());
int gaps = 10;
JPanel panel = new JPanel(new BorderLayout(gaps, gaps));
panel.setBorder(BorderFactory.createEmptyBorder(gaps, gaps, gaps, gaps));
panel.add(buttonAdd, BorderLayout.NORTH);
panel.add(tableScrollPane, BorderLayout.CENTER);
JFrame frame = new JFrame(table.getClass().getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
new Timer().schedule(new TimerTask() {
@Override
public void run() {
SwingUtilities.invokeLater(() -> table.tableModel.addRow());
}
}, 500, 100);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> buildAndShowGui());
}
}
导入java.awt.BorderLayout;
导入java.awt.Dimension;
导入java.awt.Point;
导入java.awt.event.MouseAdapter;
导入java.awt.event.MouseEvent;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.Timer;
导入java.util.TimerTask;
导入java.util.Vector;
导入javax.swing.BorderFactory;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.JMenuItem;
导入javax.swing.JPanel;
导入javax.swing.jpopmenu;
导入javax.swing.JScrollPane;
导入javax.swing.JTable;
导入javax.swing.SwingUtilities;
导入javax.swing.table.DefaultTableModel;
导入javax.swing.table.TableColumn;
@抑制警告(“串行”)
公共类TableDemo扩展了JTable{
私有静态类列{
私有int行中心=0;
私有最终字符串标识符;
公共列(字符串标识符){
this.identifier=标识符;
}
私有字符串nextCellValue(){
返回(RowsCenter++++),id:“+标识符;
}
}
私有静态类MyTableModel扩展了DefaultTableModel{
private final List columns=new ArrayList();
private int nextColumnIdentifier=0;
私有void addRow(){
Object[]row=columns.stream().map(Column::nextCellValue.toArray();
插入行(0,行);
}
私有表列addColumn(){
字符串标识符=String.valueOf(nextColumnIdentifier++);
添加(新列(标识符));
addColumn(标识符);
TableColumn tc=新的TableColumn();
设置标识符(标识符);
tc.setHeaderValue(标识符);
tc.setModelIndex(columns.size()-1);
返回tc;
}
私有void removeColumn(int idx){
列。删除(idx);
列标识符。删除(idx);
用于(对象行:数据向量){
((矢量)行)。删除(idx);
}
firetablestructured();
}
}
私有静态类HeaderMenu扩展了JPopupMenu{
私有int columnViewIndex;
private HeaderMenu(最终表格演示表格){
JMenuItem项目=新的JMenuItem(“删除列”);
item.addActionListener(e->table.deleteColumn(columnViewIndex));
增加(项目);
最终MouseAdapter ma=新MouseAdapter(){
布尔值=假;
@凌驾
公共无效MouseEvent(MouseEvent e){
如果(!拖动(&e.getButton()==MouseEvent.BUTTON3){
终点p=e.getPoint();
SwingUtilities.invokeLater(()->{
columnViewIndex=表列点(p);
显示(e.getComponent(),p.x,p.y);
});
}
拖动=假;
}
@凌驾
公共无效鼠标标记(鼠标事件e){
拖动=真;
}
};
table.getTableHeader().addMouseListener(ma);
table.getTableHeader().addMouseMotionListener(ma);
}
}
私有MyTableModel tableModel=新MyTableModel();
私有TableDemo(){
新校长(本);
setModel(tableModel);
setAutoCreateColumnsFromModel(假);
setDefaultEditor(Object.class,null);
}
私有void addColumn(){
TableColumn tc=tableModel.addColumn();
addColumn(tc);
}
void delete列(int idxView){
TableColumn tc=getColumnModel().getColumn(idxView);
tableModel.removeColumn(tc.getModelIndex());
去除柱(tc);
}
私有静态void buildAndShowGui(){
TableDemo table=新TableDemo();
table.setPreferredScrollableViewportSize(新维度(800300));
表.setFillsViewPerthweight(真);
JScrollPane tableScrollPane=新的JScrollPane(表);
JButton buttonad=新JButton(“添加列”);
addActionListener(e->table.addColumn());
整数间隔=10;
JPanel面板=新JPanel(新边界布局(间隙,间隙));
panel.setOrder(BorderFactory.createEmptyByOrder(间隙、间隙、间隙、间隙));
面板。添加(按钮添加,边界布局。北);
添加(tableScrollPane、BorderLayout.CENTER);
for (int i = 0; i < getColumnModel().getColumnCount(); i++) {
System.out.print(getColumnModel().getColumn(i).getModelIndex() + " ");
}
private static class MyColumnsModel extends DefaultTableColumnModel {
private TableColumn deleteColumn(int idxView) {
if (selectionModel != null) {
selectionModel.removeIndexInterval(idxView, idxView);
}
TableColumn tc = tableColumns.remove(idxView);
tc.removePropertyChangeListener(this);
for (TableColumn tableColumn : tableColumns) {
if (tableColumn.getModelIndex() > tc.getModelIndex()) {
tableColumn.setModelIndex(tableColumn.getModelIndex() - 1);
}
}
return tc;
}
}
private void addColumn() {
TableColumn tc = tableModel.addColumn();
addColumn(tc); // equal to columnsModel.addColumn(tc);
}
private void deleteColumn(int idxView) {
TableColumn tc = columnsModel.deleteColumn(idxView);
tableModel.removeColumn(tc.getModelIndex());
}
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
@SuppressWarnings("serial")
public class TableDemo extends JTable {
private static class Column {
private int rowsCounter = 0;
private final String identifier;
public Column(String identifier) {
this.identifier = identifier;
}
private String nextCellValue() {
return (rowsCounter++) + ", id: " + identifier;
}
}
private static class MyTableModel extends DefaultTableModel {
private final List<Column> columns = new ArrayList<>();
private int nextColumnIdentifier = 0;
private void addRow() {
Object[] row = columns.stream().map(Column::nextCellValue).toArray();
insertRow(0, row);
}
private TableColumn addColumn() {
String identifier = String.valueOf(nextColumnIdentifier++);
columns.add(new Column(identifier));
addColumn(identifier);
TableColumn tc = new TableColumn();
tc.setIdentifier(identifier);
tc.setHeaderValue(identifier);
tc.setModelIndex(columns.size() - 1);
return tc;
}
private void removeColumn(int idx) {
columns.remove(idx);
columnIdentifiers.remove(idx);
for (Object row : dataVector) {
((Vector<?>) row).remove(idx);
}
fireTableStructureChanged();
}
}
private static class MyColumnsModel extends DefaultTableColumnModel {
private TableColumn deleteColumn(int idxView) {
if (selectionModel != null) {
selectionModel.removeIndexInterval(idxView, idxView);
}
TableColumn tc = tableColumns.remove(idxView);
tc.removePropertyChangeListener(this);
for (TableColumn tableColumn : tableColumns) {
if (tableColumn.getModelIndex() > tc.getModelIndex()) {
tableColumn.setModelIndex(tableColumn.getModelIndex() - 1);
}
}
return tc;
}
}
private static class HeaderMenu extends JPopupMenu {
private int columnViewIndex;
private HeaderMenu(final TableDemo table) {
JMenuItem item = new JMenuItem("Delete column");
item.addActionListener(e -> table.deleteColumn(columnViewIndex));
add(item);
final MouseAdapter ma = new MouseAdapter() {
boolean dragged = false;
@Override
public void mouseReleased(MouseEvent e) {
if (!dragged && e.getButton() == MouseEvent.BUTTON3) {
final Point p = e.getPoint();
SwingUtilities.invokeLater(() -> {
columnViewIndex = table.columnAtPoint(p);
show(e.getComponent(), p.x, p.y);
});
}
dragged = false;
}
@Override
public void mouseDragged(MouseEvent e) {
dragged = true;
}
};
table.getTableHeader().addMouseListener(ma);
table.getTableHeader().addMouseMotionListener(ma);
}
}
private MyTableModel tableModel = new MyTableModel();
private MyColumnsModel columnsModel = new MyColumnsModel();
private TableDemo() {
new HeaderMenu(this);
setModel(tableModel);
setColumnModel(columnsModel);
setAutoCreateColumnsFromModel(false);
setDefaultEditor(Object.class, null);
}
private void addColumn() {
TableColumn tc = tableModel.addColumn();
addColumn(tc); // equal to columnsModel.addColumn(tc);
}
private void deleteColumn(int idxView) {
TableColumn tc = columnsModel.deleteColumn(idxView);
tableModel.removeColumn(tc.getModelIndex());
}
private static void buildAndShowGui() {
TableDemo table = new TableDemo();
table.setPreferredScrollableViewportSize(new Dimension(800, 300));
table.setFillsViewportHeight(true);
JScrollPane tableScrollPane = new JScrollPane(table);
JButton buttonAdd = new JButton("Add column");
buttonAdd.addActionListener(e -> table.addColumn());
int gaps = 10;
JPanel panel = new JPanel(new BorderLayout(gaps, gaps));
panel.setBorder(BorderFactory.createEmptyBorder(gaps, gaps, gaps, gaps));
panel.add(buttonAdd, BorderLayout.NORTH);
panel.add(tableScrollPane, BorderLayout.CENTER);
JFrame frame = new JFrame(table.getClass().getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
new Timer().schedule(new TimerTask() {
@Override
public void run() {
SwingUtilities.invokeLater(() -> table.tableModel.addRow());
}
}, 500, 100);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> buildAndShowGui());
}
}