【问题标题】:JTable - Adding row to sorted table gives NullPointerExceptionJTable - 向排序表添加行会产生 NullPointerException
【发布时间】:2015-06-24 21:54:48
【问题描述】:

我在 GUI 中创建了一个 JTable,并在该 JTable 上方创建了 8 个不同的按钮。 根据您按下的按钮,表格将填充不同的数据(始终相同的列),并且在此之前它会删除所有旧数据(来自按下之前的按钮)

一切正常 - 直到我对列进行排序。

我正在使用此代码为我的表设置排序器:

    TableRowSorter<DefaultTableModel> sorter = new TableRowSorter<DefaultTableModel>(model);
    table.setRowSorter(sorter);

这个代码来计算/添加新行:

button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {

            model.setRowCount(0);

            new Thread(new Runnable(){
                public void run(){

                    // Here is a call to another class which is calculating 
                    // the values and adding the row, but basically it is just.. 
                    // adding a row , so i exchanged it with this:

                    model.addRow(Object[]);

                }
            }).start();
        }
    });

正如我所说,异常在我对列进行排序时出现,默认排序不会引发异常。

我已经阅读了有关 EDT 的信息,并且使用这种代码我正在编辑它之外的表格,并且可能使用 InvokeLater。 尝试使用它并阅读了一些关于它的文档,但我无法让它工作。

从这里获取信息: Sorting JTable causes NullPointerException

这对我来说是一个新领域,所以告诉我“只添加 xyz 或执行 xyz”对我没有帮助,因为我不知道该怎么做,这意味着如果有人可以给我,那就太好了它的示例,甚至将其添加到我的代码中

这是我得到的异常(重复多次):

线程“AWT-EventQueue-0”中的异常 java.lang.NullPointerException 在 javax.swing.DefaultRowSorter.convertRowIndexToModel(未知 来源)在 javax.swing.JTable.convertRowIndexToModel(未知来源) 在 javax.swing.JTable.getValueAt(Unknown Source) 在 javax.swing.JTable.prepareRenderer(未知来源)在 javax.swing.plaf.basic.BasicTableUI.paintCell(未知来源)在 javax.swing.plaf.basic.BasicTableUI.paintCells(未知来源)在 javax.swing.plaf.basic.BasicTableUI.paint(未知来源)在 javax.swing.plaf.ComponentUI.update(未知来源)在 javax.swing.JComponent.paintComponent(Unknown Source) 在 javax.swing.JComponent.paint(Unknown Source) 在 javax.swing.JComponent.paintChildren(未知来源)在 javax.swing.JComponent.paint(Unknown Source) 在 javax.swing.JViewport.paint(未知来源)在 javax.swing.JComponent.paintChildren(未知来源)在 javax.swing.JComponent.paint(Unknown Source) 在 javax.swing.JComponent.paintToOffscreen(未知来源)在 javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(未知 来源)在 javax.swing.RepaintManager$PaintManager.paint(Unknown 源)在 javax.swing.RepaintManager.paint(未知源)在 javax.swing.JComponent._paintImmediately(Unknown Source) at javax.swing.JComponent.paintImmediately(Unknown Source) at javax.swing.RepaintManager$4.run(Unknown Source) at javax.swing.RepaintManager$4.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) 在 java.security.ProtectionDomain$1.doIntersectionPrivilege(未知 来源)在 javax.swing.RepaintManager.paintDirtyRegions(未知 来源)在 javax.swing.RepaintManager.paintDirtyRegions(未知 来源)在 javax.swing.RepaintManager.prePaintDirtyRegions(未知 来源)在 javax.swing.RepaintManager.access$1300(未知来源)在 javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source) at java.awt.event.InvocationEvent.dispatch(未知来源)在 java.awt.EventQueue.dispatchEventImpl(未知来源)在 java.awt.EventQueue.access$500(未知来源)在 java.awt.EventQueue$3.run(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) 在 java.security.ProtectionDomain$1.doIntersectionPrivilege(未知 源)在 java.awt.EventQueue.dispatchEvent(未知源)在 java.awt.EventDispatchThread.pumpOneEventForFilters(未知来源) 在 java.awt.EventDispatchThread.pumpEventsForFilter(未知来源) 在 java.awt.EventDispatchThread.pumpEventsForHierarchy(未知 来源)在 java.awt.EventDispatchThread.pumpEvents(未知来源) 在 java.awt.EventDispatchThread.pumpEvents(Unknown Source) 在 java.awt.EventDispatchThread.run(未知来源)

【问题讨论】:

  • 这是作为评论发布的,因为我不能 100% 确定它是否回答了这个问题,但我觉得你打电话给 model.setRowCount(0),然后向模型中添加项目很有趣。您最好创建一个新的表模型并向其中添加项目。顺便说一句,您的线程代码违反了 Swing 线程规则,因为您正在从事件线程中更改 Swing 模型的状态。如需更好的帮助,请考虑创建并发布Minimal, Complete, and Verifiable Example Program
  • @HovercraftFullOfEels 假设 OP 使用DefaultTableModel,将行数设置为 0,然后添加一个新行“应该”没问题......在 EDT 之外进行,这更像是一个问题......理论上;)
  • @MadProgrammer:感谢您澄清这一点。我没有查看源代码,所以我在这方面的知识有点粗略。总是很高兴看到您对这类问题的回答!
  • @HovercraftFullOfEels 教会了我这个巧妙的技巧(使用 DefaultTableModel)

标签: java nullpointerexception jtable tablesorter event-dispatch-thread


【解决方案1】:

别这样……

        new Thread(new Runnable(){
            public void run(){

                // Here is a call to another class which is calculating 
                // the values and adding the row, but basically it is just.. 
                // adding a row , so i exchanged it with this:

                model.addRow(Object[]);

            }
        }).start();

这是在事件调度线程的上下文之外修改 UI 的状态,这会导致 UI、模型和排序器之间的竞争条件。

Swing 不是线程安全的,对 UI 的任何修改(或任何可能影响 UI 的内容)都应在 EDT 的上下文中完成。

使用SwingUtilities.invokeLaterSwingWorker

详情请见Concurrency in Swing

【讨论】:

  • 我现在尝试使用invokeLater,正如史蒂夫郭在他的回答中所展示的那样。是的,异常消失了,但我实际上添加了一个新线程的原因是因为我有一个进度条,没有到目前为止它就无法工作。添加 invokeLater 只是创建了与根本没有新线程相同的行为。使用新线程,您可以看到如何添加行以及进度条从 1 到 100。没有(或使用invokeLater)几秒钟没有任何反应,并且blop突然出现在100%的进度条,我实际上只希望进度条工作
  • 但是,您可以只在 InvokeLater 中调用 addRow 部分,但更好的想法是使用 SwingWorker,它允许您在后台运行进程,但它允许您发布和处理上下文的 EDT 并且内置了进度支持
  • 是的,我目前正在尝试使用 SwingWorker 以及您在答案中提供的文档,但到目前为止我还没有让它工作。在我计算列的类中,主要处理 3 个任务。首先计算列,然后添加新行,并设置进度条的值。我现在用一个新的 swingworker 和 doInBackground 包围了它。我会在swingworker的过程中返回进度的整数,设置进度条,但是什么也没有发生.. :(
  • 对于exampleexampleexample
  • 非常感谢您提供的示例,我很确定 Swingworker 可以正常工作,但目前我无法使其正常工作。由于值已显示并正确计算,我将暂时保留它,稍后再回来以防止这些异常..
【解决方案2】:

model.addRow(Object[]); 看起来很可疑。您正在添加没有数据的行。

另外,你真的应该在 UI 线程中执行此操作。使用SwingUtilities.invokeLater

代替

new Thread(new Runnable(){
    public void run(){

SwingUtilities.invokeLater(new Runnable(){
    public void run(){

【讨论】:

  • 虽然这是一个有效的评论,convertRowIndexToModel 不应该关心行的内容,理论上,你应该能够在列中拥有 null 值(ps-我没有证明这不是问题的证据,但这不是我首先关心的问题;))
  • 但是甚至没有空值,因为它是一个空数组
  • 它当然不是一个空对象,正如我上面提到的,有一个完整的类计算列的值,所以我只是添加了 Object[] 作为填充符。实际上它是 Object[]{value1 , value2 , values3 ... } 我目前正在尝试 invokeLater,但到目前为止感谢示例!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-06
  • 2012-11-22
  • 2016-02-13
相关资源
最近更新 更多