-1

这将是我在 StackOverflow 上的第一个问题,但肯定不是第一次有帮助。但是,到目前为止,我没有进一步尝试我发现的不同可能的解决方案。

我目前正在实习并创建一个实用程序来可视化通过 USB-to-CAN 接口读取的信息 - “控制器区域网络”。简而言之:它从嵌入式系统上的 CAN 连接器读取消息。每条消息由一个标识符字段(包含源地址、目标地址、标识符等)+ 最多 8 个数据字节组成。这些字段被转换为字符串,我想在每次收到新消息时将它们添加到 JList 中。JList 'log_listview' 使用新的 DefaultListModel 'listModel' 进行初始化,并将其添加到 ContentPane 'Can_Panel'。读取发生在一个名为“vci_thread”的单独线程中,该线程在创建面板后立即初始化并启动。

大约 5 秒后才开始读取,这是初始化 USB-to-CAN 接口所需的时间。乍一看,JList 表现良好。每条收到的消息都正确添加到 listModel 中,我什至没有注意到有错误,因为程序只是继续运行,没有丢失元素,自动滚动并在 listModel.size() > 99 时自动删除第一个元素...

不时出现以下错误(“大小:#”是 JList 中实际元素数量的调试输出):

Size: 60
Size: 61
Size: 62
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at javax.swing.BufferStrategyPaintManager.flushAccumulatedRegion(Unknown Source)
    at javax.swing.BufferStrategyPaintManager.endPaint(Unknown Source)
    at javax.swing.RepaintManager.endPaint(Unknown Source)
    at javax.swing.JComponent._paintImmediately(Unknown Source)
    at javax.swing.JComponent.paintImmediately(Unknown Source)
    at javax.swing.RepaintManager$3.run(Unknown Source)
    at javax.swing.RepaintManager$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.access$1000(Unknown Source)
    at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(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)
Size: 63
Size: 64
Size: 65
Size: 66

此外,当大量消息快速传入时,我经常会收到以下错误。我认为这与删除第一个索引有关,因为当前大小为 100:

Size: 100
Size: 100
Size: 100
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 99 >= 99
    at java.util.Vector.elementAt(Unknown Source)
    at javax.swing.DefaultListModel.getElementAt(Unknown Source)
    at javax.swing.plaf.basic.BasicListUI.paintCell(Unknown Source)
    at javax.swing.plaf.basic.BasicListUI.paintImpl(Unknown Source)
    at javax.swing.plaf.basic.BasicListUI.paint(Unknown Source)
    at javax.swing.plaf.ComponentUI.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.BufferStrategyPaintManager.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$3.run(Unknown Source)
    at javax.swing.RepaintManager$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.access$1000(Unknown Source)
    at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(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)
Size: 100
Size: 100

以下是在读取新 CAN 消息并将字节转换为字符串后执行的代码

    // Add a new element containing the strings:
    listModel.addElement(counter + ": " + src_addr_hex + " " + dest_addr_hex + " - " + predef_hex + " - " + str_data);

    // Auto scroll down after the element has been added
    if (listModel.size()-1 >= 0) {
        try {
            log_listview.ensureIndexIsVisible(listModel.size()-1);
        } catch (Exception ex) {
        //
        }
    }

    // When listModel contains 100 elements, remove the first index
    if (listModel.size()>99) {
        listModel.remove(0);
    }

这个读数和这段代码在一个while()循环中执行,并且每次都包含一个Thread.sleep(1)来限制cpu的使用。我通过 try{} catch() 确保当没有新消息要读取时,字符串转换和添加到 JList 的操作会被简单地跳过。当消息进来的速度快于这个循环的一个周期时,它们会被简单地缓存并一一处理,直到我的程序最终赶上。这是一个相当广泛的问题,但我希望有人能帮助我。

更新:我已将代码迁移到一个新的可运行“update_JList”中,并在读取一行后立即使用 SwingUtilities.invokeLater 方法调用它。我没有收到任何错误,很高兴看到 GUI 更新有多流畅。但是,现在我面临 JList 中重复或缺失元素的另一个问题:

截屏

左侧是调试输出,一一显示每条传入消息。右边是显示源地址为 45 的消息 14 次的 JList。

4

1 回答 1

1

读取发生在一个名为“vci_thread”的单独线程中,该线程在创建面板后立即初始化并启动。

GUI 的更新必须在 EDT 上完成,而不是单独的线程。阅读 Swing 教程中关于并发的部分以获取更多信息。

您可以使用 SwingWorker,或者如果您想继续使用现有的线程,那么您需要在想要更新模型时使用 SwingUtilities.invokeLater()。

于 2013-04-17T15:05:26.207 回答