4

Have one JTable on my swing screen. While loading screen, I am setting one table model which is created for this table only. And at run time if there is any data change I am recreating the same model and again set it using objJTable.setModel(objCustTableModel).

Now the problem is table model which is loaded at the time of screen load, same model object get called while setting objJTable.setModel(objCustTableModel) at run time which called getColumnClass(int col) method from CustTableModel class. After this object call, my new model object get called. Again if I set another new table model, by using same code objJTable.setModel(objCustTableModel2), model call's functions get called first from objCustTableModel and then objCustTableModel2.

In short setModel() function first call previous model object and then current model object. How can I restrict to call of previous model object?

For example

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();
    }
}

at this time swing first internally called getColumnClass function on the basis of objCustTableModel and after that using objCustTableModel2 object. I want to restrict call which is on the basis of objCustTableModel.

4

3 回答 3

4

从这个例子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()truesetModel()则尝试恢复RowSorter使用旧模型创建的。

  • 您可以在更改模型setAutoCreateRowSorter(true) 指定,如下所示,或者扩展您TableModel以更新模型,如下所示

  • 使用ActionListenerforJButton代替MouseListener.

  • 使用TableCellEditor表格中的 for 按钮,如此此处所示。

代码:

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);
    }
});
于 2013-04-16T17:15:22.017 回答
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()});

    }                
于 2014-03-13T07:28:15.637 回答
0

我之前遇到过类似的问题,因为我在 jtable 的 ListSelectionListener 中调用 jTable.getValueAt(jTable.getSelectedRow(),col),并且在更改 jtable 的模型后,它在调用 jTable.setModel 后抛出无效索引,超出范围异常(模型)在行选择之​​后,它通过确保调用值和选定的行获取器来解决 - jTable.getValueAt(jTable.getSelectedRow(),col) - 不是来自仍在制作的旧事件,通过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 的模型设置为新模型后,我们会遇到异常

于 2018-03-29T09:38:54.950 回答