使用大量列时 JTable 渲染器性能问题

JTable renderer performance issue when using lots of Columns

快速场景......

JTable 大约有 30 列。在不附加渲染器的情况下,我可以单击第 30 列并将其移动到任何位置,速度非常非常快。没有延迟或任何东西。

由于大多数列都是唯一的并且需要它们自己的渲染类型,无论是背景颜色、日期格式、字体还是其他,渲染器被分配给特定的列而不是 Table。现在发生的情况是将列移动到不同位置时存在巨大滞后。

这是一个基本示例,其中注释掉了渲染器以首先展示它有多快。

import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

public class LotsOfColumnsWithRenderer
{
    static JFrame f;
    static String data[][];
    static final int colums = 30;
    static final int rows = 100;
    static boolean skipThis = false;
    
      public static void main(String[] argv) throws Exception 
      {
          LotsOfColumnsWithRenderer x = new LotsOfColumnsWithRenderer();
      }

      public LotsOfColumnsWithRenderer()
      {
            f = new JFrame();
            populateData();
            String column[]={"Col 1","Col 2","Col 3", "Col 4", "Col 5", "Col 6", "Col 7","Col86","Col 9","Col 10","Col 11","Col 12","Col 13","Col 14","Col 15",
                    "Col 16","Col 17","Col 18","Col 19","Col 20","Col 21","Col 22","Col 23","Col 24","Col 25","Col 26","Col 27","Col 28","Col 29","Col 30",};         
        
            JTable table = new JTable(data,column);
            
            //for (int y=0; y < colums; y ++)
            //{
                //table.getColumnModel().getColumn(y).setCellRenderer(new MyTableCellRenderer());
            //}
            
            table.getTableHeader().addMouseListener(new MouseAdapter()
            {
                @Override
                public void mousePressed(MouseEvent e) 
                {
                    if (e.getButton() == MouseEvent.BUTTON1) 
                    {
                        skipThis = true;
                    }
                }

                @Override
                public void mouseReleased(MouseEvent e) 
                {
                    if (e.getButton() == MouseEvent.BUTTON1) 
                    {
                        skipThis = false;
                    }
                }
        
            });

            table.setBounds(30,40,200,300);          
            JScrollPane sp=new JScrollPane(table);    
            f.add(sp);  
            f.setSize(300,400);    
            f.setVisible(true); 
            
            MyTableCellRenderer xx = new MyTableCellRenderer();
            

      }
      

    private static void populateData() 
    {
        data = new String[rows][colums];
        
        for (int x=0; x < rows; x++)
        {
            for (int y=0; y < colums; y ++)
            {
                data[x][y] = "Data for ["+x+"]["+y+"]";
            }
        }
        
    }
    
    public class MyTableCellRenderer extends JLabel implements TableCellRenderer 
    {
        private static final long serialVersionUID = -6320757636864429128L;

        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
              boolean hasFocus, int rowIndex, int vColIndex) 
          {
              if (skipThis)
              {
                  System.out.println("Skipping");
                  return this;
              }
              
                setText(value.toString());
                setToolTipText((String) value);
                if (vColIndex == 1)
                    this.setBackground(Color.LIGHT_GRAY);
                else if (vColIndex == 3)
                    this.setBackground(Color.CYAN);
                else if (vColIndex == 7)
                    this.setBackground(Color.YELLOW);
                else if (vColIndex == 20)
                    this.setBackground(Color.GREEN);

                
                this.setOpaque(true);
                return this;
          }
    }
}

运行上面的代码。

双击 JFrame 的顶部以最大化 window 并查看全部 30 列。

单击 Col 30 列 header 并快速将其一直向左移动并一直向右移动,注意它移动得非常快。

现在取消注释以下代码行。

        //for (int y=0; y < colums; y ++)
        //{
            //table.getColumnModel().getColumn(y).setCellRenderer(new MyTableCellRenderer());
        //}

运行 再次应用程序并执行相同的步骤。

注意这次移动列有很大的延迟。

我确实尝试在移动列标题时设置一个布尔值以防止渲染器执行,但它仍然涉及并且似乎并没有真正帮助。

问题:

在开始影响性能之前,渲染器的数量是否有限制(或实现渲染器时要遵循的规则)?

由于列渲染器的种类繁多,字段数量众多,是否有更高效的实现渲染器的方法?

is there a more efficient way to implement renderers?

扩展 DefaultTableCellRenderer:

//public class MyTableCellRenderer extends JLabel implements TableCellRenderer
public class MyTableCellRenderer extends DefaultTableCellRenderer
{
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowIndex, int vColIndex)
      {
            super.getTableCellRendererComponent(table, value, isSelected, hasFocus, rowIndex, vColIndex);

            //setText(value.toString());
            setToolTipText((String) value);
            if (vColIndex == 1)
                this.setBackground(Color.LIGHT_GRAY);
            else if (vColIndex == 3)
                this.setBackground(Color.CYAN);
            else if (vColIndex == 7)
                this.setBackground(Color.YELLOW);
            else if (vColIndex == 20)
                this.setBackground(Color.GREEN);


            //this.setOpaque(true);
            return this;
      }
}

DefaultTableCellRenderer 覆盖 JLabel 的各种方法以提高绘制效率,因为它知道组件用作渲染器而不是真正的组件。

例如,当您调用 setText(..) 时,标签本身不需要 revalidate()

阅读 DefaultTableCellRenderer API 了解有关效率的更多信息。