This would be my first question on StackOverflow, but certainly not the first time it's been helpful. However I didn't get any further trying the different possible solutions I found until now.
I'm currently fulfilling an internship and creating a utility to visualise the information read through a USB-to-CAN interface - 'controller area network'. Simply put: it reads out messages from the CAN connector on an embedded system. Each message consists of an identifier field (containing a source address, destination address, identifier and so on) + 8 data bytes max. These fields are converted into strings and I want to add them to a JList every time a new message is received. The JList 'log_listview' is initialized with a new DefaultListModel 'listModel' and it's added to the 'Can_Panel', the ContentPane. The reading happens in a separate thread called 'vci_thread', which is initialized and started right after creating the panel.
Reading starts only after about 5 seconds, the time it takes to initialize the USB-to-CAN interface. At first sight, the JList performs well. Each received message is correctly added to the listModel and I didn't even notice there were errors because the program simply continues with no missing elements, auto scrolling and autmatic removal of the first element when listModel.size() > 99...
Now and then I get the following error (The "Size: #" is the debug output of the actual number of elements in the 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
Also, when a lot of messages are coming in quickly, i regularily get the following error. I believe it has something to do with the removal of the first index as the size is currently 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
Here's the code that's executed after a new CAN message is read and the bytes have been converted into strings:
// 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);
}
This the reading, together with this code is executed inside a while() loop and incorporates a Thread.sleep(1) every time to limit cpu usage. I've ensured with a try{} catch() that when there's no new message to be read, the string conversion and the addition to the JList is simply skipped. When messages come in faster than one cycle of this loop, they are simply cached and handled one by one until eventually my program catches up. It's a rather extensive question, but I'm hoping one could help me out.
Update: I've migrated the code into a new runnable 'update_JList' and calling it with the SwingUtilities.invokeLater method right after reading a line. I'm not getting any errors and it's great to see how smooth the GUI updates. However, now I'm facing another problem of duplicates or missing elements in the JList:
On the left is the debug output showing every incoming message one by one. On the right is the JList showing the message with source address 45 14 times.