1

I have a JTable created and 8 different buttons above this JTable in the GUI. Depending on which button you press, the table will be filled with different data (always same columns) and before doing that it deletes all the old data (from before-pressed buttons)

Everything is working fine - until i am sorting a column.

I am using this code to set a sorter to my table:

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

And this code to calculate/add the new rows:

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

As i said, the exception only appears when i am sorting a column, with default sorting no exception is thrown.

I have read already about EDT and with this kind of code i am editing the table outside of it and maybe to use InvokeLater. Tried to use it and also read some documentation about it but i can't get it working.

Got the information from here: Sorting JTable causes NullPointerException

This is a new area for me so telling me to "just add xyz or do xyz" won't help me since i do not know how i should do it, which means it would be really nice if someone can give me examples of it or even add it to my code

This is the exception i get (It repeats several times):

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException at javax.swing.DefaultRowSorter.convertRowIndexToModel(Unknown Source) at javax.swing.JTable.convertRowIndexToModel(Unknown Source) at javax.swing.JTable.getValueAt(Unknown Source) at javax.swing.JTable.prepareRenderer(Unknown Source) at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source) at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source) at javax.swing.plaf.basic.BasicTableUI.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.paintChildren(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JViewport.paint(Unknown Source) at javax.swing.JComponent.paintChildren(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$4.run(Unknown Source) at javax.swing.RepaintManager$4.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$1300(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$500(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)

Community
  • 1
  • 1
BlackOutDev
  • 99
  • 1
  • 1
  • 12
  • 1
    This is posted as a comment since I am not 100% sure if it answers the question, but I feel funny about your calling `model.setRowCount(0)`, and then adding items to the model. You might be better off creating a new table model and adding items to it. As an aside, your threading code violates Swing threading rules since you're changing the state of a Swing model off of the event thread. For better help, consider creating and posting a [Minimal, Complete, and Verifiable Example Program](http://stackoverflow.com/help/mcve). – Hovercraft Full Of Eels Apr 17 '15 at 21:22
  • @HovercraftFullOfEels Assuming the OP is using a `DefaultTableModel`, setting the row count to 0 and then adding a new row "should" be fine...doing it outside the EDT, that's more of an issue...in theory ;) – MadProgrammer Apr 17 '15 at 21:26
  • @MadProgrammer: thanks for clarifying this. I hadn't looked at the source, and so my knowledge in this area is a bit sketchy. Always glad to see your answers on these types of questions! – Hovercraft Full Of Eels Apr 17 '15 at 21:28
  • @HovercraftFullOfEels taught me that neat trick (with DefaultTableModel) – MadProgrammer Apr 17 '15 at 22:01

2 Answers2

1

model.addRow(Object[]); looks suspect. You are adding a row with no data.

Also you should really be doing this in the UI thread. Use SwingUtilities.invokeLater.

Instead of

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

do

SwingUtilities.invokeLater(new Runnable(){
    public void run(){
Steve Kuo
  • 61,876
  • 75
  • 195
  • 257
  • 2
    While that's a valid comment, `convertRowIndexToModel` shouldn't care about the contents of the row and, in theory, you should be able to have `null` values in columns (ps- I have no evidence that it's not a problem, but it wouldn't be my first concern ;)) – MadProgrammer Apr 17 '15 at 21:23
  • But there's not even a null value as it's an empty array – Steve Kuo Apr 17 '15 at 21:24
  • It's not an empty object of course, as i mentioned above there is a whole class calculating values for the columns, so i just added Object[] as a filler. In reality it is Object[]{value1 , value2 , values3 ... } I am currently trying the invokeLater, but thanks so far for the example! – BlackOutDev Apr 17 '15 at 21:32
1

Don't do this...

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

This is modifying the state of the UI outside of the context of the Event Dispatching Thread, which is leading to a race condition between the UI, the model and the sorter.

Swing is not thread safe and any modifications of the UI (or anything that might affect the UI) should be done from within the context of the EDT.

Either use SwingUtilities.invokeLater or a SwingWorker

See Concurrency in Swing for more details

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I tried now to use invokeLater as Steve Kuo showed in his answer. Yes the exception is gone, but the reason why i actually added a new thread was because i have a progress bar which won't work without so far. Adding invokeLater just created the same behavior as not having a new thread at all. With the new thread you can see how the rows get added and the progress bar is going from 1-100. Without (or with invokeLater) several seconds nothing happens and *blop* suddenly there with progress bar at 100%, i actually only want the progress bar working – BlackOutDev Apr 17 '15 at 21:41
  • But, you could just call the addRow part in InvokeLater, but a better idea would be to use a SwingWorker, which allows you to run process in the background, but which allows you to publish and process context of the EDT AND has progress support built in – MadProgrammer Apr 17 '15 at 22:05
  • Yes i am currently trying to work with SwingWorker and the documentation you have provided in your answer, but so far i didn't get it working. In the class where i am calculating the columns mainly 3 tasks will be processed. First the calculation of the columns, then adding the new row, and setting the value for the progressBar. I have now surrounded it with a new swingworker and doInBackground. I will give back the integer of the progress and set the progress bar in the process of the swingworker, but nothing happens.. :( – BlackOutDev Apr 17 '15 at 22:33
  • For [example](http://stackoverflow.com/questions/15124904/populating-jtable-using-database-data/15125161#15125161) and [example](http://stackoverflow.com/questions/17414109/populate-jtable-with-large-number-of-rows/17415635#17415635) and [example](http://stackoverflow.com/questions/23125642/swingworker-in-another-swingworkers-done-method/23126410#23126410) – MadProgrammer Apr 18 '15 at 00:10
  • Thanks so much for the examples, i am pretty sure with the swingworker it will work, but for now i was not able to get it working. Since the values are displayed and correctly calculated i will leave it for now and come back later to prevent these exceptions.. – BlackOutDev Apr 18 '15 at 18:51