java - JTable 渲染有时会停止渲染,但会在调整窗口大小时恢复

标签 java swing jtable rendering

我的自定义 JTable 和自定义 TableRenderer 遇到了一个神秘的问题。 在 95%-99,99% 的情况下,它可以完美工作,但有时渲染器会停止执行其工作,并将表格的一部分(位于 JScrollPane 内)留空。

问题案例如下: rednering has terminated to early

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

现在两列都有一个关联的 TextAreaCellRenderer,其工作原理如下:

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 方法,以便能够根据内容计算单元格的高度。自定义表格如下所示:

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

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

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

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

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

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

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

现在有人知道是什么原因导致了所描述的渲染问题吗?

感谢您的建议。

最佳答案

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 中,并根据面板的首选大小设置行高。这样,布局管理器将为您完成任务,并且所有单元格的内容都将可见:

@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 扩展:单个变量即可工作。记住这一点,根据您的工作查看此实现:

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

}

屏幕截图

enter image description here

关于java - JTable 渲染有时会停止渲染,但会在调整窗口大小时恢复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20332134/

相关文章:

java - BigDecimal setScale 方法语法不起作用

java - 如何将javabean转换为post参数字符串?

java - 捕获异常时是否有理由不使用 final 关键字?

Java Swing 变量不递增

java - 如何在 netbeans 的 jtable 中显示查询结果

java - 将数据库中的图像添加到 JTable

Java DOM - NULL 指针异常

java - 添加叠加的 JLabel

java - 我的 GUI 代码有什么问题?

java - 检查组件何时从 JTable 中删除