JTable渲染有时会停止渲染,但会在调整窗口大小时恢复 [英] JTable render stops rendering sometimes but resumes on window resize

查看:93
本文介绍了JTable渲染有时会停止渲染,但会在调整窗口大小时恢复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的自定义JTable和自定义TableRenderer遇到了一个神秘的问题. 在95%-99,99%的环境中,它可以完美工作,但有时渲染器只是停止执行工作,而将表格的一部分(位于JScrollPane内)留空.

I`ve got a mysterious problem with my custom JTable and a custom TableRenderer. In 95%-99,99% it works perfectly, but sometimes the renderer just stops doing his job, and leaves a portion of the table (which is inside a JScrollPane) blank.

问题案例如下所示:

The problem case looks like that:

在所有其他情况下,在稍微调整窗口大小之后,表格看起来像这样:

In all other cases, and after a slight resize of the window, the Table look like that:

现在两列都有关联的TextAreaCellRenderer,其工作方式如下:

Now both columns has a TextAreaCellRenderer associated to, which works as follows:

public class TextAreaCellRenderer extends JTextArea implements TableCellRenderer {

    private final Color evenColor = new Color(252, 248, 202);


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


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

我还必须重写JTable的doLayout方法,以便能够根据内容计算单元格的高度.自定义表如下所示:

I also have to override the doLayout method of the JTable to be able to calculate the hight of a cell depending on the content. The custom table looks like that:

public class MediaMetaDataTable extends JTable {

    @Override
    public void doLayout() {
        TableColumn col = getColumnModel().getColumn(1);
        for (int row = 0; row < getRowCount(); row++) {
            Component c = prepareRenderer(col.getCellRenderer(), row, 1);
            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(final 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;
    }
}

该表使用以下参数实例化一次:

The table is instantiated once with the following parameters:

metaTable = new MediaMetaDataTable();
metaTable.setModel(new MediaMetaDataTableModel());
metaTable.setEnabled(false);
metaTable.setShowGrid(false);
metaTable.setTableHeader(null);
metaTable.getColumnModel().getColumn(0).setCellRenderer(new TextAreaCellRenderer());
metaTable.getColumnModel().getColumn(1).setCellRenderer(new TextAreaCellRenderer());
metaTable.setPreferredScrollableViewportSize(new Dimension(-1, -1));
metaTable.setShowHorizontalLines(false);
metaTable.setShowVerticalLines(false);

每次显示数据更改时,我都会通过替换基础模型数据来更新表:

Each time the data to show changes i update table by replacing the underlying models data:

List<MediaMetaData> metaInformation = mediaSearchHit.getMetaInformation();
        if (metaInformation != null) {
            ((MediaMetaDataTableModel) metaTable.getModel()).replaceMetaInfos(metaInformation);
        }

在更新时,模型本身会触发表数据更改事件:

On update the model itself fires a table data changed event:

public class MediaMetaDataTableModel extends AbstractTableModel {

    private List<MediaMetaData> metaInfos = new LinkedList<MediaMetaData>();

    public static final int COL_INDEX_NAME = 0;
    public static final int COL_INDEX_VALUE = 1;


    public void replaceMetaInfos(final List<MediaMetaData> metaInfos) {
        this.metaInfos = null;
        this.metaInfos = metaInfos;
        fireTableDataChanged();
    }
...

现在有人有想法吗,什么原因导致了所描述的渲染问题?

Now does anybody has a idea, what causes the described rendering problem?

感谢您的任何建议.

推荐答案

我还必须重写JTabledoLayout方法,以便能够 根据内容计算单元格的高度.

I also have to override the doLayout method of the JTable to be able to calculate the hight of a cell depending on the content.

要实现此目标,无需重写doLayout()方法.我认为最简单的方法是通过使用BorderLayout将用于渲染单元格内容的文本区域添加到JPanel中,并根据面板的首选大小设置行高.这样,布局管理器将为您解决问题,并且所有单元格的内容都将可见:

To achieve this goal there's no need to override doLayout() method. I think the simplest way to do this is by adding the text area used to render the cell content into a JPanel with BorderLayout and set the row height based on the panel's preferred size. This way the layout manager will do the trick for you and all the cell's content will be visible:

@Override
public Component getTableCellRendererComponent(...) {
    ...
    JPanel contentPane = new JPanel(new BorderLayout());            
    contentPane.add(this);
    table.setRowHeight(row, contentPane.getPreferredSize().height); // sets row's height
    return contentPane;
}

正如@mKorbel指出的那样,无需使渲染器从JTextArea扩展:单个变量将起作用.请牢记这一点,请根据您的工作来查看此实现:

As @mKorbel pointed out, there's no need to make the renderer extend from JTextArea: a single variable will work. Keeping this in mind take a look to this implementation based on your work:

class TextAreaRenderer implements TableCellRenderer {

    private JTextArea renderer;
    private final Color evenColor = new Color(252, 248, 202);

    public TextAreaRenderer() {
        renderer = new JTextArea();            
        renderer.setLineWrap(true);
        renderer.setWrapStyleWord(true);
        renderer.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) {
            renderer.setForeground(table.getSelectionForeground());
            renderer.setBackground(table.getSelectionBackground());
        } else {
            renderer.setForeground(table.getForeground());
            renderer.setBackground((row % 2 == 0) ? evenColor : table.getBackground());
        }            
        renderer.setFont(table.getFont());
        renderer.setText((value == null) ? "" : value.toString());
        JPanel contentPane = new JPanel(new BorderLayout());            
        contentPane.add(renderer);
        table.setRowHeight(row, contentPane.getPreferredSize().height); // sets row's height
        return contentPane;
    }

}

屏幕截图

这篇关于JTable渲染有时会停止渲染,但会在调整窗口大小时恢复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆