简体   繁体   English

JTable调用自定义单元格渲染器方法......连续

[英]JTable Calls Custom Cell Renderer Method… Continuously

Compilable source can be found at: http://www.splashcd.com/jtable.tar 可编辑的源代码可在以下网址找到: http//www.splashcd.com/jtable.tar

I'm new to the language, so I'm not sure if this is acceptable behavior or not. 我是这门语言的新手,所以我不确定这是否是可接受的行为。

I created a JTable to display a row for each message received (it receives about one every 20 seconds). 我创建了一个JTable来为每个收到的消息显示一行(它每20秒接收一次)。 One of the table columns can contain a large amount of text, so I created a custom cell renderer which word wraps and sets the row height accordingly. 其中一个表列可以包含大量文本,因此我创建了一个自定义单元格渲染器,该单词渲染器相应地包装并设置行高。

All that works as expected, except that once the table displays its first row, it calls the cell renderer about ten times a second... until the user closes the table. 所有这一切都按预期工作,除了表格显示第一行后,它每秒调用单元格渲染器大约十次......直到用户关闭表格。

Once I get approx 20 rows in there, the table gets fairly sluggish, taking 2-8 seconds to resize a column, scoll up or down, or render a selected row with the selected background color. 一旦我在那里得到大约20行,表格变得相当迟缓,需要2-8秒来调整列的大小,向上或向下scoll,或者使用所选的背景颜色渲染选定的行。

I inserted a print statement inside the renderer, so I can see how many times the getTableCellRendererComponent method is being called. 我在渲染器中插入了一个print语句,因此我可以看到调用getTableCellRendererComponent方法的次数。

I disabled tool tips, and disabled all cell editing. 我禁用了工具提示,并禁用了所有单元格编辑。 I do have a listener that scrolls the view to the last row when either a new row is added or the table is resized. 我有一个监听器,当添加新行或调整表格大小时,它会将视图滚动到最后一行。

Should the getTableCellRendererComponent method be called several times a second when I'm just viewing the screen (not touching mouse or keyboard)? 当我刚刚查看屏幕(不接触鼠标或键盘)时,是否应该每秒调用几次getTableCellRendererComponent方法?

TIA TIA

  • aaaaach aaaaach

  • you need doLayout() , 你需要doLayout()

  • next level :-), then there you can to set Maximum visible row s for JTextComponents too, with little effort 下一级:-),然后你可以轻松地为JTextComponents设置Maximum visible row

在此输入图像描述

doLayout() 的doLayout()

import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.*;
//http://tips4java.wordpress.com/2008/10/26/text-utilities/
public class AutoWrapTest {

    public JComponent makeUI() {
        String[] columnNames = {" Text Area Cell Renderer "};
        Object[][] data = {
            {"123456789012345678901234567890"},
            {"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddx"},
            {"----------------------------------------------0"},
            {">>>>>>>>>>>>>dddddddddddddddddddddddddddddddddddddddddddddddddd"
                + "dddddddxdddddddddddddddddddddddddddddddddddddddddddddd"
                + "dddddddddddx>>>>>>>>>>>>>>>>>>>>>>>>>|"},
            {">>>>>>>>>>>>ddddddddddddddddddddddddddddddddddddddddddddddddddd"
                + "ddddddx>>>>>>>>>>>>>>>>>>>>>>>>>>|"},
            {"a|"},
            {">>>>>>>>bbbb>>>>>>>>>>>>>>>>>>>|"},
            {">>>>>>>>>>>>>>>>>>|"},
            {">>>>>>>>>>>>>dddddddddddddddddddddddddddddddddddddddddddddddddd"
                + "dddddddxdddddddddddddd123456789012345678901234567890dddddd"
                + "dddddddddddddddddddddddddddddddddddddx>>>>>>>>>>>>>>>>>>>>"
                + ">>>>>|"},
            {">>>>>>>>>>>>>dddddddddddddd123456789012345678901234567890dddddd"
                + "dddddddddddddddddddddddddddddddddddddxdddddddddddddd123456"
                + "789012345678901234567890dddddddddddddddddddddddddddddddddd"
                + "ddddd123456789012345678901234567890ddddx>>>>>>>>>>>>>>>>>>"
                + ">>>>>>>|"},};
        TableModel model = new DefaultTableModel(data, columnNames) {

            private static final long serialVersionUID = 1L;

            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        JTable table = new JTable(model) {

            private static final long serialVersionUID = 1L;

            @Override
            public void doLayout() {
                TableColumn col = getColumnModel().getColumn(0);
                for (int row = 0; row < getRowCount(); row++) {
                    Component c = prepareRenderer(col.getCellRenderer(), row, 0);
                    if (c instanceof JTextArea) {
                        JTextArea a = (JTextArea) c;
                        int h = getPreferredHeight(a) + getIntercellSpacing().height;
                        if (getRowHeight(row) != h) {
                            setRowHeight(row, h);
                        }
                    }
                }
                super.doLayout();
            }

            private int getPreferredHeight(JTextComponent c) {
                Insets insets = c.getInsets();
                View view = c.getUI().getRootView(c).getView(0);
                int preferredHeight = (int) view.getPreferredSpan(View.Y_AXIS);
                return preferredHeight + insets.top + insets.bottom;
            }
        };
        table.setEnabled(false);
        table.setShowGrid(false);
        table.setTableHeader(null);
        table.getColumnModel().getColumn(0).setCellRenderer(new TextAreaCellRenderer());
        //table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane sp = new JScrollPane(table);
        sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        sp.setPreferredSize(new Dimension(250, 533));
        JPanel p = new JPanel(new BorderLayout());
        p.add(sp);
        return p;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }

    public static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(new AutoWrapTest().makeUI());
        f.setLocation(100, 100);
        f.pack();
        f.setVisible(true);
    }
}

class TextAreaCellRenderer extends JTextArea implements TableCellRenderer {

    private static final long serialVersionUID = 1L;
    private final Color evenColor = new Color(230, 240, 255);

    public TextAreaCellRenderer() {
        super();
        setLineWrap(true);
        setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        if (isSelected) {
            setForeground(table.getSelectionForeground());
            setBackground(table.getSelectionBackground());
        } else {
            setForeground(table.getForeground());
            setBackground(table.getBackground());
            setBackground((row % 2 == 0) ? evenColor : getBackground());
        }
        setFont(table.getFont());
        setText((value == null) ? "" : value.toString());
        return this;
    }
}

To get the most performance out of a TableCellRenderer , make sure you're not creating a new instance of a component every time getTableCellRenderer is called. 要从TableCellRenderer获得最佳性能,请确保每次调用getTableCellRenderer都不创建组件的新实例。 Make the components once and save them as fields of the class. 制作一次组件并将其保存为类的字段。

Also, you'll want to make sure each of the Components you use have the following methods overridden to do nothing: 此外,您还需要确保使用的每个组件都覆盖以下方法,不执行任何操作:

  • validate 验证
  • invalidate 废止
  • revalidate 重新验证
  • repaint 重绘
  • firePropertyChange 中的firePropertyChange

(and you probably want to hard code isOpaque ). (你可能想要硬代码isOpaque )。

For more information see: http://docs.oracle.com/javase/6/docs/api/javax/swing/tree/DefaultTreeCellRenderer.html 有关更多信息,请参阅: http//docs.oracle.com/javase/6/docs/api/javax/swing/tree/DefaultTreeCellRenderer.html

The problem seems to stem from having JTable's setRowHeight() inside the custom cell renderer, as it calls the custom cell renderer, throwing it into an infinite loop. 问题似乎源于在自定义单元格渲染器中具有JTable的setRowHeight() ,因为它调用自定义单元格渲染器,将其抛入无限循环。

I had to add in a check to see if the current row height matched the calculated word wrapped row height. 我必须添加一个检查,以查看当前行高是否与计算出的字包裹行高相匹配。 If it did, I didnt try to setRowHeight() again. 如果是这样,我没有尝试再次setRowHeight()。

Corrected Code: 更正代码:

import java.awt.Component;

import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.table.TableCellRenderer;

//custom cell renderer for word wrapping, but if you use, you have to
//implement zebra striping functionality which the default renderer has
public class LineWrapCellRenderer extends JTextArea implements TableCellRenderer
{
    private int numOfTimesCalled;
    @Override
    public Component getTableCellRendererComponent(
            JTable table,
            Object value,
            boolean isSelected,
            boolean hasFocus,
            int row,
            int column)
    {
        System.out.println("Line Wrap Cell Renderer Called: " + numOfTimesCalled++);
        System.out.println("row:"+ row + ", col:" + column);
//set up the row size based on the number of newlines in the text in the cell
        int fontHeight = this.getFontMetrics(this.getFont()).getHeight();
        int numWraps = value.toString().split("\r\n|\r|\n").length;
        int rowHeight = fontHeight * numWraps;
//if the calculated rowHeight is the same as the row height of row,
// then don't call setRowHeight again, as doing so will throw us into
// an infinite loop
        if(rowHeight != table.getRowHeight(row))
        {
            table.setRowHeight(row, rowHeight);

//configure word wrapping
            setWrapStyleWord(true);
            setLineWrap(true);
//use the table's font
            setFont(table.getFont());
        }
//zebra striping, because whatever cell uses this renderer loses the
//default cell renderer zebra striping
        if(isSelected)
        {
            setBackground(table.getSelectionBackground());
        }
        else
        {
            if(row%2 == 1)
            {
                setBackground(UIManager.getColor("Table.alternateRowColor"));
            }
            else
            {
                setBackground(table.getBackground());
            }
        }
        this.setText(value.toString());
        return this;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM