且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

刷新JTable在Swing中提供异常

更新时间:2023-12-03 13:11:16

看到你没有将表绑定到你的数据,然后刷新单元格,因为它们更改,你每次按下一个键时,从桌子下方更改整个数据模型。



我猜测你遇到一个种族的状况。你按下一个键,这就开始重建你的表和它的模型的过程。部分方式通过重建(记住,Swing使用线程,所以表更新仍然发生你键入,)你要去触发另一个重建,这将改变模型从第一次刷新仍在运行。当然,没有看到你所有的代码,我不能肯定,但是我可以提出几件事情,使事情变得更清洁,并不容易出现并发问题。

而不是编写代码,您可以将模型数据转换为简单的表模型,每个关键笔划都可以创建自己的表模型类,并实现它直接查看模型。这样你就不会在模型和数组之间不断地重新传输数据。



为了制作自己的表格模型,你可以从AbstractTableModel( http://download.oracle.com /javase/6/docs/api/javax/swing/table/AbstractTableModel.html )。在原始Java教程中有一个很好的例子( http://下载.oracle.com / javase / tutorial / uiswing / components / table.html#data ),如果您不确定该怎么做。对于你最重要的是getValueAt方法,它接受一行和一列,并返回该单元格应该包含的值。这就是你想要放置代码,看看你的Order对象并生成你想要的输出。



一旦你有你自定义的TableModel对象,只需传递一个新的当你第一次初始化它的时候,它的实例就是这个表的setModel方法。



一旦完成,你将要处理 em>模型刷新。要刷新表中的所有数据,您可以触发fireTableDataChanged事件。或者,您只能刷新表中实际需要更改的部分,而不是每次刷新整个事物。而不是在这里进入细微的细节,我只是指出你完美的Java教程页面: http://download.oracle.com/javase/tutorial/uiswing/components/table.html#fire


So I'm essentially trying to refresh my JTable every time a keystroke is hit, or when there's an update on the observer's part. Occasionally what I get is a frozen application and this stack trace...

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 5 >= 5 at java.util.Vector.elementAt(Unknown Source) at javax.swing.table.DefaultTableColumnModel.getColumn(Unknown Source) at javax.swing.plaf.synth.SynthTableUI.paintCells(Unknown Source) at javax.swing.plaf.synth.SynthTableUI.paint(Unknown Source) at javax.swing.plaf.synth.SynthTableUI.update(Unknown Source) at javax.swing.JComponent.paintComponent(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JComponent.paintToOffscreen(Unknown Source) at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source) at javax.swing.RepaintManager$PaintManager.paint(Unknown Source) at javax.swing.RepaintManager.paint(Unknown Source) at javax.swing.JComponent._paintImmediately(Unknown Source) at javax.swing.JComponent.paintImmediately(Unknown Source) at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source) at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source) at java.awt.event.InvocationEvent.dispatch(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source) Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 4 >= 4 at java.util.Vector.elementAt(Unknown Source) at javax.swing.table.DefaultTableColumnModel.getColumn(Unknown Source) at sun.swing.SwingUtilities2.convertColumnIndexToModel(Unknown Source) at javax.swing.JTable.convertColumnIndexToModel(Unknown Source) at javax.swing.JTable.getColumnClass(Unknown Source) at javax.swing.plaf.synth.SynthTableUI$SynthTableCellRenderer.getTableCellRendererComponent(Unknown Source) at javax.swing.JTable.prepareRenderer(Unknown Source) at javax.swing.plaf.synth.SynthTableUI.paintCell(Unknown Source) at javax.swing.plaf.synth.SynthTableUI.paintCells(Unknown Source) at javax.swing.plaf.synth.SynthTableUI.paint(Unknown Source) at javax.swing.plaf.synth.SynthTableUI.update(Unknown Source) at javax.swing.JComponent.paintComponent(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JComponent.paintToOffscreen(Unknown Source) at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source) at javax.swing.RepaintManager$PaintManager.paint(Unknown Source) at javax.swing.RepaintManager.paint(Unknown Source) at javax.swing.JComponent._paintImmediately(Unknown Source) at javax.swing.JComponent.paintImmediately(Unknown Source) at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source) at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source) at java.awt.event.InvocationEvent.dispatch(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source)

If it helps, here is my code for refreshing the table:

public synchronized void refreshTable()
{
    Customer cust = custManager.getCustomer(phoneNumber.getText());

    if (cust == null)
    {
        table.setModel(new DefaultTableModel(new Object[][] {}, tableHeader) {
                @SuppressWarnings("rawtypes")
                Class[] columnTypes = new Class[] {Integer.class, String.class,
                                                   Object.class, Object.class, 
                                                   Object.class, Object.class};
                @SuppressWarnings({ "unchecked", "rawtypes" })
                public Class getColumnClass(int columnIndex) {
                    return columnTypes[columnIndex];
                }

                public boolean isCellEditable(int row, int column) {
                    return false;
                }
        });
        table.getColumnModel().getColumn(0).setPreferredWidth(40);
        table.getColumnModel().getColumn(1).setPreferredWidth(120);
        return;
    }

    Object[][] grid = new Object[cust.getOrderHistory().size()][6];

    SimpleDateFormat sdf = new SimpleDateFormat("MMM/dd/yyyy HH:mm");
    NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();

    int i = 0;
    for (Entry<GregorianCalendar, Order> orderEntry : cust.getOrderHistory())
    {
        Order order = orderEntry.getValue();

        grid[i][0] = order.getOrderID();
        grid[i][1] = sdf.format((order.getProcessedTimestamp().getTime()));
        grid[i][2] = currencyFormat.format(order.getSubTotal()/100.00);
        grid[i][3] = currencyFormat.format(order.getTaxedAmount()/100.00);
        grid[i][4] = currencyFormat.format(order.getTotal()/100.00);
        grid[i][5] = order.getOrderStatus();

        i++;
    }

    DefaultTableModel dft = new DefaultTableModel(grid, tableHeader) {
            @SuppressWarnings("rawtypes")
            Class[] columnTypes = new Class[] {Integer.class, String.class, 
                                               Object.class, Object.class, 
                                               Object.class, Object.class};
            @SuppressWarnings({ "unchecked", "rawtypes" })
            public Class getColumnClass(int columnIndex) {
                return columnTypes[columnIndex];
            }

            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };

    table.setModel(dft);
    table.getColumnModel().getColumn(0).setPreferredWidth(40);
    table.getColumnModel().getColumn(1).setPreferredWidth(120);
}

For the record, I have tried wrapping it around in a try/catch, and no that will not help. I also have tried changing the default exception handler, and that has been unsuccessful as well.

One of the biggest problems I can see is that you are not binding the table to your data then refreshing cells as they change, you are changing the whole data model out from under the table every time you press a key.

I'd hazard a guess that you're experiencing a "race" condition. You press a key, and that starts off the process of rebuilding your table and its model. Part way through that rebuild (remember, Swing uses threads, so the table update is still happening while you type,) you're going and triggering another rebuild, which changes the model out from under the first refresh which is still running. Of course, without seeing all of your code I can't be certain about that, but I can suggest a few things to make things a bit cleaner and less prone to concurrency issues.

Rather than writing code which takes your model data and translates it into a simple table model every key stroke, you can create your own table model class, and implement it to look directly at your model. That way you don't have the problem of constantly re-transferring data between your model and the array.

To make your own table model, you can just extend from the AbstractTableModel ( http://download.oracle.com/javase/6/docs/api/javax/swing/table/AbstractTableModel.html ). There's a great example in the original Java Tutorial ( http://download.oracle.com/javase/tutorial/uiswing/components/table.html#data ) if you're not sure how to go about it. The most important thing for you is the "getValueAt" method, which takes a row and a column and returns what value that cell should contain. That's where you want to put the code which looks at your "Order" object and produces the output you want.

Once you have your custom TableModel object, just pass a new instance of it into the "setModel" method of the table when you first initialize it.

Once that is done, you'll want to handle sensible model refreshes. To refresh all of the data in the table, you can trigger a "fireTableDataChanged" event. Alternatively, you can refresh only the parts of your table which actually need to be changed, not the whole thing every time. Rather than go into the fine grain details here, I'll just point you to the excellent Java Tutorial page on doing exactly that: http://download.oracle.com/javase/tutorial/uiswing/components/table.html#fire