在我的秋千屏幕上有一个JTable
。在加载屏幕时,我正在设置一个仅为此表创建的表模型。
在运行时,如果有任何数据更改,我正在重新创建相同的模型,并再次使用objJTable.setModel(objCustTableModel)
进行设置。
现在问题是在屏幕加载时加载的表模型,在运行时设置objJTable.setModel(objCustTableModel)
时调用相同的模型对象,该方法从CustTableModel
类调用getColumnClass(int col)方法。在此对象调用之后,我的新模型对象被调用。如果我再设置一个新的话
表模型,通过使用相同的代码objJTable.setModel(objCustTableModel2)
,模型调用的函数首先从objCustTableModel
调用然后
objCustTableModel2
。
简而言之setModel()
函数首先调用前一个模型对象,然后调用当前模型对象。如何限制调用以前的模型对象?
例如
import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
/**
* Steps to reproduce issue.
* 1. Run this program.
* 2. There will be two rows in table. Delete all rows one by one.
* 3. Now click on Add button and see the exception.
*
* I come to know that this exception is because of table.setAutoCreateRowSorter(true); line, which is there in TestCustTableModel's constructor
* If you comment this line, then issue got resolved.
* But I want to apply sorting on columns so this line is required.
*/
public class TestCustTableModel extends JPanel{
JTable table = new JTable();
public TestCustTableModel() {
Object[][] data = new Object[2][3];
data[0][0] = "1";
data[0][1] = "User1";
data[0][2] = "Delete";
data[1][0] = "2";
data[1][1] = "User2";
data[1][2] = "Delete";
JButton addButton = new JButton("Add");
addButton.addMouseListener(new AddListener());
table.setModel(new CustModel(data));
table.addMouseListener(new TableListener());
/**#################################
* Following line throws ArrayIndexOutOfBoundsException. Please comment or Uncomment following line and see the difference.
*/
table.setAutoCreateRowSorter(true);
table.getTableHeader().setCursor(new Cursor(Cursor.HAND_CURSOR));
JScrollPane scrollPane = new JScrollPane(table);
this.add(addButton);
this.add(scrollPane);
}
class TableListener extends MouseAdapter {
public void mouseClicked(MouseEvent evnt) {
Point p = evnt.getPoint();
if(table.columnAtPoint(p) == 2) {
Object[][] data = null;
if(table.getModel().getRowCount() == 2 && table.rowAtPoint(p) == 0) {
data = new Object[1][3];
data[0][0] = "2";
data[0][1] = "User2";
data[0][2] = "Delete";
}else if(table.getModel().getRowCount() == 2 && table.rowAtPoint(p) == 1) {
data = new Object[1][3];
data[0][0] = "1";
data[0][1] = "User1";
data[0][2] = "Delete";
}else {
data = new Object[0][];
}
table.setModel(new CustModel(data));
}
}
}
class AddListener extends MouseAdapter{
@Override
public void mouseClicked(MouseEvent evnt) {
if(table.getModel().getRowCount() == 2) {
return;
}
Object[][] data = new Object[table.getModel().getRowCount() + 1][3];
for(int i = 0; i <= table.getModel().getRowCount(); i++) {
data[i][0] = i;
data[i][1] = "User" + i;
data[i][2] = "Delete";
}
table.setModel(new CustModel(data));
}
}
class CustModel extends AbstractTableModel {
private String[] columnNames = {"ID", "NAME", "DELETE"};
private Object[][] data = null;
public CustModel(Object[][] data) {
this.data = data;
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public Class getColumnClass(int col) {
return getValueAt(0, col).getClass();
}
}
private void display() {
JFrame f = new JFrame("SwapTableModel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
TestCustTableModel obj = new TestCustTableModel();
obj.display();
}
}
此时首先在getColumnClass
的基础上首先在内部调用objCustTableModel
函数,之后
使用objCustTableModel2
对象。我想限制基于objCustTableModel
的呼叫。
答案 0 :(得分:4)
从这个example开始,我看到下面显示的getColumnClass()
实现没有出现意外行为。
private Model() {
final Object[] data = {this.toString()};
this.model = new DefaultTableModel(data, 1){
@Override
public Class<?> getColumnClass(int columnIndex) {
System.out.println(data[0]);
return super.getColumnClass(columnIndex);
}
};
model.addRow(data);
}
请注意JTable
可以在确定单元格需要渲染时随时调用getColumnClass()
。如有必要,您可以使用EventQueue.invokeLater()
来安排“在处理完所有待处理事件后发生的事情。”
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// do something
}
});
附录:
如果getAutoCreateRowSorter()
为true
,则setModel()
会尝试恢复使用旧模型创建的RowSorter
。
您可以在更改模型后指定setAutoCreateRowSorter(true)
,如下所示,或者扩展您的TableModel
以更新模型,如图所示{{3 }}
ActionListener
使用JButton
代替MouseListener
。
代码:
addButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (table.getModel().getRowCount() == 2) {
return;
}
Object[][] data = new Object[table.getModel().getRowCount() + 1][5];
table.setRowSorter(null);
for (int i = 0; i <= table.getModel().getRowCount(); i++) {
data[i][0] = i;
data[i][6] = "User" + i;
data[i][7] = "Delete";
}
table.setModel(new CustModel(data));
table.setAutoCreateRowSorter(true);
}
});
答案 1 :(得分:3)
DefaultTableModel model ;
/** Creates new form DynRowAdd */
public DynRowAdd() {
initComponents();
model = new DefaultTableModel();
jTable1.setModel(model);
model.addColumn("Id");
model.addColumn("First Name");
model.addColumn("Last Name");
model.addColumn("Company Name");
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
model.addRow(new Object[]{jTextField1.getText(), jTextField2.getText(),jTextField3.getText(),jTextField4.getText()});
}
答案 2 :(得分:0)
之前我遇到过类似的问题,因为我在jtable的ListSelectionListener中调用了jTable.getValueAt(jTable.getSelectedRow(),col),并且在更改了jtable的模型后,它抛出了无效的索引在行选择之后调用jTable.setModel(Model)之后,超出绑定异常,并通过确保调用值和所选行getter来解决它 - jTable.getValueAt(jTable.getSelectedRow(),col) - wasn&# 39;来自他们仍在制作的旧事件,由jtable的ListSelectionListener中的!event.getValueIsAdjusting(),我通过这个问题理解这个符号,它是不试图调用值和在jtable的集合模型调用中调用旧模型中选择的行getter - 如果你有更好的知识,请纠正我,如果我错了或不精确 - ,这是我之前问题的一个例子,您可以尝试评论!event.getValueIsAdjusting()if条件,以查看符号:
package testingsetmodel;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class TestingSetModel extends javax.swing.JFrame implements ItemListener {
TestingSetModel() {
init();
}
private void init()
{
northPanel = new JPanel( ); // for adding jtable6
eastPanel = new JPanel( ); // for adding jtable7
southPanel = new JPanel( ); // for adding 2 jradiobuttons
first = new JRadioButton("1st");
second = new JRadioButton("2nd", true);
rg = new ButtonGroup( );
rg.add( first ) ; rg.add( second ) ;
first.addItemListener(this); second.addItemListener(this);
jScrollPane6 = new JScrollPane();
jScrollPane7 = new JScrollPane();
northPanel.add(jScrollPane6); eastPanel.add(jScrollPane7);
southPanel.add(first); southPanel.add(second);
jTable6 = new javax.swing.JTable(){
DefaultTableCellRenderer renderRight = new DefaultTableCellRenderer();
{ // initializer block
renderRight.setHorizontalAlignment(SwingConstants.RIGHT);
}
@Override
public TableCellRenderer getCellRenderer (int arg0, int arg1) {
return renderRight;
}
@Override
public boolean isCellEditable(int row, int col) {
switch (col) {
case 0:
return false;
default:
return true;
}
}
};
jTable6.setAutoCreateRowSorter(false);
jTable6.setFont(new java.awt.Font("Traditional Arabic", 0, 19));
jTable6.setEnabled(true);
jTable6.setRowHeight(25);
((DefaultTableCellRenderer)jTable6.getTableHeader().getDefaultRenderer()).setHorizontalAlignment(JLabel.RIGHT);
jTable6.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jScrollPane6.setViewportView(jTable6);
jTable6.setSelectionBackground(new Color(0,100,255,7)); // cutomize selection color
jTable6.setSelectionForeground(Color.black);
jTable6.setRowSelectionAllowed(true);
setTheDefaultJTable6Model();
if(jTable6.getRowCount()>0)
{
for(int i = 0; i<jTable6.getRowCount(); i++)
{
if(jTable6.getValueAt(i,0).toString().equalsIgnoreCase("4"))
{
jTable6.setRowSelectionInterval(i, i);
jTable6.scrollRectToVisible(new Rectangle(jTable6.getCellRect(i, 0, true)));
}
}
}
jTable7 = new javax.swing.JTable(){
DefaultTableCellRenderer renderRight = new DefaultTableCellRenderer();
{ // initializer block
renderRight.setHorizontalAlignment(SwingConstants.RIGHT);
}
@Override
public TableCellRenderer getCellRenderer (int arg0, int arg1) {
return renderRight;
}
@Override
public boolean isCellEditable(int row, int col) {
switch (col) {
case 0:
return false;
default:
return true;
}
}
};
jTable7.setAutoCreateRowSorter(false);
jTable7.setFont(new java.awt.Font("Traditional Arabic", 0, 19));
jTable7.setEnabled(true);
jTable7.setRowHeight(25);
jTable7.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jScrollPane7.setViewportView(jTable7);
jTable7.setSelectionBackground(new Color(0,100,255,7)); // cutomize selection color for lite one for writting under selection
jTable7.setSelectionForeground(Color.black);
jTable7.setRowSelectionAllowed(true);
jTable6.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
@Override
public void valueChanged(ListSelectionEvent event) {
// try to comment the following if condition, and setting the model through changing the jradiobuttons
if(!event.getValueIsAdjusting() && jTable6.getSelectedRow() != -1 && jTable6.getSelectedRowCount() == 1)
{
DefaultTableModel clinicsSpecsJtableModel = new DefaultTableModel(); // the model
Object[] clinicsSpecsJtableColumnsNames = new Object[2]; // the four showable columns from the jtable model
clinicsSpecsJtableColumnsNames[0] = "name" ;
clinicsSpecsJtableColumnsNames[1] = "address" ;
clinicsSpecsJtableModel.setColumnIdentifiers(clinicsSpecsJtableColumnsNames);
Object[] clinicsSpecsJtableRowData = new Object[2];
ArrayList<String> clinicsNames = new ArrayList<>();
ArrayList<String> clinicsAddresses = new ArrayList<>();
clinicsNames.add("J34hp "+jTable6.getValueAt(jTable6.getSelectedRow(), 0).toString());
clinicsNames.add("J34df "+jTable6.getValueAt(jTable6.getSelectedRow(), 0).toString());
clinicsNames.add("J34as "+jTable6.getValueAt(jTable6.getSelectedRow(), 0).toString());
clinicsNames.add("J34gh "+jTable6.getValueAt(jTable6.getSelectedRow(), 0).toString());
clinicsNames.add("J45hj "+jTable6.getValueAt(jTable6.getSelectedRow(), 0).toString());
clinicsNames.add("J56gr "+jTable6.getValueAt(jTable6.getSelectedRow(), 0).toString());
clinicsNames.add("J34mn "+jTable6.getValueAt(jTable6.getSelectedRow(), 0).toString());
clinicsNames.add("J56vr "+jTable6.getValueAt(jTable6.getSelectedRow(), 0).toString());
clinicsNames.add("J45pi "+jTable6.getValueAt(jTable6.getSelectedRow(), 0).toString());
clinicsAddresses.add("21 Tmk st");
clinicsAddresses.add("13 bcv st");
clinicsAddresses.add("67 rfb st");
clinicsAddresses.add("81 Tmk st");
clinicsAddresses.add("31 Tmk st");
clinicsAddresses.add("23 Jkl st");
clinicsAddresses.add("54 IUR st");
clinicsAddresses.add("51 Jkl st");
clinicsAddresses.add("71 rfb st");
for( int i=0 ; i<clinicsNames.size() ; i++ )
{
clinicsSpecsJtableRowData[0] = clinicsNames.get(i);
clinicsSpecsJtableRowData[1] = clinicsAddresses.get(i);
clinicsSpecsJtableModel.addRow(clinicsSpecsJtableRowData); // adding the row to the model
}
jTable7.setModel(clinicsSpecsJtableModel); // setting the model to the jtable
for (int column = 0; column < jTable7.getColumnCount(); column++)
{
TableColumn tableColumn = jTable7.getColumnModel().getColumn(column);
int preferredWidth = tableColumn.getMinWidth();
int maxWidth = tableColumn.getMaxWidth();
for (int row = 0; row < jTable7.getRowCount(); row++)
{
TableCellRenderer cellRenderer = jTable7.getCellRenderer(row, column);
Component c = jTable7.prepareRenderer(cellRenderer, row, column);
int width = c.getPreferredSize().width + jTable7.getIntercellSpacing().width;
preferredWidth = Math.max(preferredWidth, width);
// We've exceeded the maximum width, no need to check other rows
if (preferredWidth >= maxWidth)
{
preferredWidth = maxWidth;
break;
}
}
tableColumn.setPreferredWidth( preferredWidth );
}
jTable7.getTableHeader().setFont(new Font("Traditional Arabic", 0, 17)); // assure the column headers font and text size
((DefaultTableCellRenderer)jTable7.getTableHeader().getDefaultRenderer()).setHorizontalAlignment(JLabel.RIGHT); // align right
jTable7.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // set single selection only enabled
jScrollPane7.setViewportView(jTable7); // draw jtable
}
}
});
Container cont = getContentPane();
cont.add(northPanel, BorderLayout.NORTH);
cont.add(eastPanel, BorderLayout.EAST);
cont.add(southPanel, BorderLayout.SOUTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // to close the JFrame
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
EventQueue.invokeLater(() -> {
JFrame f = new TestingSetModel();
f.setSize(800, 600);
f.setVisible(true);
});
}
private javax.swing.JPanel northPanel, southPanel, eastPanel;
private javax.swing.JRadioButton first, second;
private javax.swing.ButtonGroup rg;
private javax.swing.JTable jTable6;
private javax.swing.JScrollPane jScrollPane6;
private javax.swing.JTable jTable7;
private javax.swing.JScrollPane jScrollPane7;
@Override
public void itemStateChanged(ItemEvent e) {
if(first.isSelected())
{
setTheDefaultJTable6Model();
removeJTable7Rows();
}else if(second.isSelected())
{
setTheCustomizedJTable6Model();
removeJTable7Rows();
}
}
private void removeJTable7Rows()
{
DefaultTableModel defaultModel = (DefaultTableModel) jTable7.getModel();
defaultModel.setRowCount(0);
}
private void setTheDefaultJTable6Model()
{
DefaultTableModel numbersJtableModel = new DefaultTableModel(); // the model
Object[] numbersJtableColumnsNames = new Object[1]; // the four showable columns from the jtable model
numbersJtableColumnsNames[0] = "number" ;
numbersJtableModel.setColumnIdentifiers(numbersJtableColumnsNames);
Object[] numbersJtableRowData = new Object[1];
ArrayList<String> numbers = new ArrayList<>();
numbers.add("1");
numbers.add("2");
numbers.add("3");
numbers.add("4");
numbers.add("5");
numbers.add("6");
for( int i=0 ; i<numbers.size() ; i++ ) // feeding array of object with numbers data
{
numbersJtableRowData[0] = numbers.get(i);
numbersJtableModel.addRow(numbersJtableRowData); // adding the row to the model
}
jTable6.setModel(numbersJtableModel); // setting the model to the jtable
for (int column = 0; column < jTable6.getColumnCount(); column++)
{
TableColumn tableColumn = jTable6.getColumnModel().getColumn(column);
int preferredWidth = tableColumn.getMinWidth();
int maxWidth = tableColumn.getMaxWidth();
for (int row = 0; row < jTable6.getRowCount(); row++)
{
TableCellRenderer cellRenderer = jTable6.getCellRenderer(row, column);
Component c = jTable6.prepareRenderer(cellRenderer, row, column);
int width = c.getPreferredSize().width + jTable6.getIntercellSpacing().width;
preferredWidth = Math.max(preferredWidth, width);
// We've exceeded the maximum width, no need to check other rows
if (preferredWidth >= maxWidth)
{
preferredWidth = maxWidth;
break;
}
}
tableColumn.setPreferredWidth( preferredWidth );
}
jTable6.getTableHeader().setFont(new Font("Traditional Arabic", 0, 17)); // assure the column headers font and text size
((DefaultTableCellRenderer)jTable6.getTableHeader().getDefaultRenderer()).setHorizontalAlignment(JLabel.RIGHT); // align right
jTable6.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // set single selection only enabled
jScrollPane6.setViewportView(jTable6); // draw jtable
}
private void setTheCustomizedJTable6Model()
{
DefaultTableModel numbersJtableModel = new DefaultTableModel(); // the model
Object[] numbersJtableColumnsNames = new Object[1]; // the four showable columns from the jtable model
numbersJtableColumnsNames[0] = "number" ;
numbersJtableModel.setColumnIdentifiers(numbersJtableColumnsNames);
Object[] numbersJtableRowData = new Object[1];
ArrayList<String> numbers = new ArrayList<>();
numbers.add("10");
numbers.add("20");
numbers.add("30");
numbers.add("40");
numbers.add("50");
numbers.add("60");
for( int i=0 ; i<numbers.size() ; i++ ) // feeding array of object with numbers data
{
numbersJtableRowData[0] = numbers.get(i);
numbersJtableModel.addRow(numbersJtableRowData); // adding the row to the model
}
jTable6.setModel(numbersJtableModel); // setting the model to the jtable
for (int column = 0; column < jTable6.getColumnCount(); column++)
{
TableColumn tableColumn = jTable6.getColumnModel().getColumn(column);
int preferredWidth = tableColumn.getMinWidth();
int maxWidth = tableColumn.getMaxWidth();
for (int row = 0; row < jTable6.getRowCount(); row++)
{
TableCellRenderer cellRenderer = jTable6.getCellRenderer(row, column);
Component c = jTable6.prepareRenderer(cellRenderer, row, column);
int width = c.getPreferredSize().width + jTable6.getIntercellSpacing().width;
preferredWidth = Math.max(preferredWidth, width);
// We've exceeded the maximum width, no need to check other rows
if (preferredWidth >= maxWidth)
{
preferredWidth = maxWidth;
break;
}
}
tableColumn.setPreferredWidth( preferredWidth );
}
jTable6.getTableHeader().setFont(new Font("Traditional Arabic", 0, 17)); // assure the column headers font and text size
((DefaultTableCellRenderer)jTable6.getTableHeader().getDefaultRenderer()).setHorizontalAlignment(JLabel.RIGHT); // align right
jTable6.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // set single selection only enabled
jScrollPane6.setViewportView(jTable6); // draw jtable
}
}
此示例应通过setTheDefaultJTable6Model()方法中的setModel()方法选择单选按钮组中的其他单选按钮来更改jTable6的模型。所以在这样的情况下,我们与jtable模型有一定的联系而不确保它不是来自之前仍在进行更改的任何事件,我们会在将jtable的模型设置为新模型后得到异常