-1

I have a JTable in my application that has 100+ rows that are added dynamically one by one.

It stores data about clients that have ordered something and the more orders during the day the more rows there are. When we have a busy day with 100+ orders the JTable becomes extremely slow when scrolling.

I use a custom renderer to change the background color of a few cells and thats about it. I have tried using TableModelEvent to only alter the color of the rows that are visible.

Doing so has increased the speed a bit but still not enough to scroll smoothly. What are the options I have to try optimize my JTable that has/will have a lot of data?

EDIT: I can provide my Jtable and my CustomCellRenderer If needed.

private static class CustomRenderer extends DefaultTableCellRenderer {

        private static final long serialVersionUID = -5699527287605065L;

        public CustomRenderer() {
            setHorizontalAlignment(SwingConstants.CENTER);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {
            Component cellComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
                    column);
            vis.set(row, column);
            if (vis.isVisible(table)) {
                Object o = table.getValueAt(row, column);

                if (column != 1 && column != 5 && column != 10 && !isSelected) {
                    cellComponent.setBackground(Color.WHITE);
                    if ((row % 2) == 0) cellComponent.setBackground(Colors.gray);
                }

                if (o != null) {
                    if (o.toString().contains("Liqui") && !isSelected) {
                        cellComponent.setBackground(Colors.green);
                        cellComponent.setForeground(Color.BLACK);
                    } else if (o.toString().contains("Green Alert") && !isSelected) {
                        cellComponent.setBackground(Colors.yellow);
                        cellComponent.setForeground(Color.BLACK);
                    } else if (o.toString().contains("Red Alert") && !isSelected) {
                        cellComponent.setBackground(Colors.red);
                        cellComponent.setForeground(Color.WHITE);
                    } else if (column == 10 && o.toString().contains("Finalizado")
                            && !isSelected) {
                        cellComponent.setBackground(Colors.green);
                        cellComponent.setForeground(Color.BLACK);
                    } else if (column == 10 && o.toString().contains("Cancelado")
                            && !isSelected) {
                        cellComponent.setBackground(Colors.red);
                        cellComponent.setForeground(Color.WHITE);
                    } else if (column == 10
                            && o.toString().contains("Comprovante em analise")
                            && !isSelected) {
                        cellComponent.setBackground(Colors.yellow);
                        cellComponent.setForeground(Color.BLACK);
                    } else if (column == 10 && o.toString().contains("Aguardando retirada")
                            && !isSelected) {
                        cellComponent.setBackground(Colors.ltOrange);
                        cellComponent.setForeground(Color.BLACK);
                    } else if (column == 10 && o.toString().contains("Entrega agendada")
                            && !isSelected) {
                        cellComponent.setBackground(Colors.orange);
                        cellComponent.setForeground(Color.BLACK);
                    } else if (column == 1
                            && o.toString().toLowerCase().contains("test1")
                            && !isSelected) {
                        cellComponent.setBackground(Colors.test1);
                        cellComponent.setForeground(Color.BLACK);
                    } else if (column == 1 && o.toString().contains("test2")
                            && !isSelected) {
                        cellComponent.setBackground(Colors.test2);
                        cellComponent.setForeground(Color.WHITE);
                    } else if (column == 1 && o.toString().contains("test3")
                            && !isSelected) {
                        cellComponent.setBackground(Colors.test3);
                        cellComponent.setForeground(Color.WHITE);
                    } else if (!isSelected && (row % 2) == 0) {
                        cellComponent.setBackground(Colors.gray);
                        cellComponent.setForeground(Color.BLACK);
                    } else if (!isSelected) {
                        cellComponent.setBackground(Color.WHITE);
                        cellComponent.setForeground(Color.BLACK);
                    }

                    if (Lists.op_list != null) {
                        for (int i = 0; i < Lists.op_list.size(); i++) {
                            if (column == 8 && !isSelected) {
                                if (table.getValueAt(row, 8) != null && table.getValueAt(row, 7) != null) {
                                    if (Lists.op_list.get(i).getFornIDSent() == 1
                                            && (int) table.getValueAt(row, 7) == Lists.op_list.get(i)
                                                    .getOperationID()) {
                                        cellComponent.setBackground(Colors.green);
                                    } else if (Lists.op_list.get(i).getFornIDSent() == 2
                                            && (int) table.getValueAt(row, 7) == Lists.op_list.get(i)
                                                    .getOperationID()) {
                                        cellComponent.setBackground(Colors.yellow);
                                    } else if ((int) table.getValueAt(row, 7) == Lists.op_list.get(i)
                                            .getOperationID()) {
                                        cellComponent.setBackground(Color.WHITE);
                                        if ((row % 2) == 0) cellComponent.setBackground(Colors.gray);
                                    }
                                }
                            }

                            if (table.getValueAt(row, 10).toString().contains("Comprovante em analise") && column == 10
                                    && !isSelected) {
                                if (Lists.op_list.get(i).getSituation() == 1
                                        && (int) table.getValueAt(row, 7) == Lists.op_list.get(i).getOperationID()) {
                                    cellComponent.setBackground(Colors.green);
                                    cellComponent.setForeground(Color.BLACK);
                                } else if (Lists.op_list.get(i).getComprovanteAllowed() == 1
                                        && (int) table.getValueAt(row, 7) == Lists.op_list.get(i).getOperationID()) {
                                    cellComponent.setBackground(Colors.green_dark);
                                    cellComponent.setForeground(Color.BLACK);
                                } else if (Lists.op_list.get(i).getComprovanteAllowed() == 2
                                        && (int) table.getValueAt(row, 7) == Lists.op_list.get(i).getOperationID()) {
                                    cellComponent.setBackground(Colors.yellow_dark);
                                    cellComponent.setForeground(Color.WHITE);
                                }
                            }

                            if (column == 9 && !isSelected) {
                                if (Lists.op_list.get(i).getPreBolSent() == 1
                                        && (int) table.getValueAt(row, 7) == Lists.op_list.get(i).getOperationID()) {
                                    cellComponent.setBackground(Colors.green);
                                } else if (Lists.op_list.get(i).getPreBolSent() == 2
                                        && (int) table.getValueAt(row, 7) == Lists.op_list.get(i).getOperationID()) {
                                    cellComponent.setBackground(Colors.yellow);
                                } else if (Lists.op_list.get(i).getPreBolSent() == 0
                                        && (int) table.getValueAt(row, 7) == Lists.op_list.get(i).getOperationID()) {
                                    cellComponent.setBackground(Color.WHITE);
                                    if ((row % 2) == 0) cellComponent.setBackground(Colors.gray);
                                }
                            }
                        }
                    }
                }

            } else {
                cellComponent.setBackground(Color.WHITE);
                cellComponent.setForeground(Color.BLACK);
            }

            vis.reset();
            return cellComponent;
        }
    }
SunnyH
  • 67
  • 11
  • 5
    *"I can provide my Jtable and my CustomCellRenderer If needed."* No thanks. For better help sooner, post a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). BTW - I would expect good response from a table until it had a few **tens of thousands** of rows. It definitely seems something is wrong. Be sure to generate the rows in code.. – Andrew Thompson Jun 08 '16 at 18:16
  • Hmmm thats good to know, I think its something to do with my renderer then, How Im making it know which color to render in which cell. – SunnyH Jun 08 '16 at 18:21
  • Including the code for your renderer would be a good start. We don’t need to see your JTable unless you’re subclassing JTable. More useful would be the code for your TableModel. – VGR Jun 08 '16 at 20:56
  • 1
    This [example](http://stackoverflow.com/a/17384208/230513) uses a `SwingWorker` to add & render `1_000_000` rows. – trashgod Jun 09 '16 at 04:27
  • I have added my renderer which is in my JTable class. I believe its due to me iterating through my list to know which object is which to provide info if certain actions were sucuessful. – SunnyH Jun 09 '16 at 11:28
  • *"I have added my renderer which is in my JTable class."* Did you actually *read* the document describing the MCVE? If there is anything in it you do not understand, myself or @trashgod should be able to explain. Each of us has worked on and written, many such example MCVEs. – Andrew Thompson Jun 09 '16 at 15:22
  • As an aside, I had an MCVE to post that creates an almost 1/4 million row table from the Unicode charset that was around 165 lines of Java code. Now the question is closed, I'm bummed I cannot post it! :-( Oh wait.. it already has 4 re-open votes... hmmm. – Andrew Thompson Jun 09 '16 at 15:25

1 Answers1

3

Here is an MCVE that puts a ¼ million rows (249,698 records) of a table on-screen & uses a renderer.

It appears quickly and shows no lag or delay in scrolling.

So this supports the idea that this must be a problem in code that we have not yet been able to test..

enter image description here

import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.table.*;
import java.util.ArrayList;

public class UnicodeTable {

    private JComponent ui = null;

    UnicodeTable() {
        initUI();
    }

    public final void initUI() {
        if (ui != null) {
            return;
        }

        ui = new JPanel(new BorderLayout(4, 4));
        ui.setBorder(new EmptyBorder(4, 4, 4, 4));

        ArrayList<Integer> definedCharacters = new ArrayList<Integer>();
        for (int codePoint = 0; codePoint < Character.MAX_CODE_POINT; codePoint++) {
            if (Character.isDefined(codePoint)) {
                definedCharacters.add(codePoint);
            }
        }
        System.out.println("Number of codepoints: " + definedCharacters.size());
        TableModel tm = new UnicodeTableModel(definedCharacters);
        JTable table = new JTable(tm);
        table.setAutoCreateRowSorter(true);
        ui.add(new JScrollPane(table));
        table.setDefaultRenderer(String.class, new UnicodeTableCellRenderer());
    }

    public JComponent getUI() {
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception useDefault) {
                }
                UnicodeTable o = new UnicodeTable();

                JFrame f = new JFrame(o.getClass().getSimpleName());
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setLocationByPlatform(true);

                f.setContentPane(o.getUI());
                f.pack();
                f.setMinimumSize(f.getSize());

                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

class UnicodeTableModel extends AbstractTableModel {

    ArrayList<Integer> codePoints;

    String[] colNames = {
        "Number", "Name", "Alphabetic", "Digit", "ISO Control"
    };

    Class[] colClass = {
        Integer.class, String.class, 
        Boolean.class, Boolean.class, Boolean.class
    };

    public UnicodeTableModel(ArrayList<Integer> codePoints) {
        this.codePoints = codePoints;
    }

    @Override
    public int getRowCount() {
        return codePoints.size();
    }

    @Override
    public int getColumnCount() {
        return colNames.length;
    }

    @Override
    public String getColumnName(int columnIndex) {
        return colNames[columnIndex];
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return colClass[columnIndex];
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Integer codePoint = codePoints.get(rowIndex);
        switch (columnIndex) {
            case 0:
                return codePoint;
            case 1:
                return Character.getName(codePoint);
            case 2:
                return Character.isAlphabetic(codePoint);
            case 3:
                return Character.isDigit(codePoint);
            case 4:
                return Character.isISOControl(codePoint);
            default:
                return new Object();
        }
    }
}

class UnicodeTableCellRenderer extends DefaultTableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        Component c = super.getTableCellRendererComponent(
                table, value, isSelected, hasFocus, row, column);
        if (column == 1) {
            JLabel l = (JLabel) c;
            Font f = l.getFont();
            f = new Font(Font.MONOSPACED, Font.ITALIC, f.getSize());
            l.setFont(f);
        }
        return c;
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • 1
    No [*screenshot*](http://meta.stackoverflow.com/questions/99734/how-do-i-create-a-screenshot-to-illustrate-a-post)? `extends AbstractTableModel` is a tad shorter. – trashgod Jun 09 '16 at 20:14
  • 1
    @trashgod *"No screenshot?"* Aw heck.. why not? *"`extends AbstractTableModel` is a tad shorter."* Hmm.. good point. I'll think about changing it. – Andrew Thompson Jun 09 '16 at 20:42