JTable 不遵守单元格渲染器的必要高度

JTable not honoring cell renderer's necessary height

这应该很简单,但我不知道哪里出了问题。我需要我的 table 以相当大的字体显示,但 table 画家不遵守单元格渲染器的高度。

我已经看到 this post 并且当我的首选项 window 被赋予更改的字体大小时,它的工作非常出色。但是,尽管渲染器知道要使用的字体大小,但 table 在初始显示 上使用的是标准行高 (16)。当然 table 画家应该自动考虑渲染器的首选高度?或者我实际上必须手动告诉它使用什么高度?

我试过调用 doLayout(),如下所示,但没有任何区别。

这里有一个 SSCCE 来演示这个问题:

public class IncorrectRowHeight extends JPanel
{
    private class MyCellRenderer extends JTextField implements TableCellRenderer
    {
        private MyCellRenderer()
        {
            setFont(new Font("SansSerif", Font.PLAIN, 30));
            setBorder(BorderFactory.createEmptyBorder());
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                                                       int row, int column)
        {
            setText(value.toString());
            return this;
        }
    }

    public IncorrectRowHeight()
    {
        super(new BorderLayout());

        add(new JTextField(25), BorderLayout.PAGE_START);

        String[][] data = {
                {"a", "b", "c", "d", "e"},
                {"f", "g", "h", "i", "j"},
                {"k", "l", "m", "n", "o"},
                {"p", "q", "r", "s", "t"}
        };
        String[] cols = {"h1", "h2", "h3", "h4", "h5"};
        JTable t = new JTable(data, cols);
        t.setGridColor(Color.GRAY);
        t.setPreferredScrollableViewportSize(new Dimension(300, 65));
        TableColumnModel model = t.getColumnModel();
        for (int i = 0; i < model.getColumnCount(); i++)
        {
            TableColumn column = model.getColumn(i);
            column.setCellRenderer(new MyCellRenderer());
        }
        JScrollPane scroller = new JScrollPane(t);
        add(scroller, BorderLayout.CENTER);

        //t.doLayout();  // doesn't help matters
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("IncorrectRowHeight");
        JComponent newContentPane = new IncorrectRowHeight();
        newContentPane.setOpaque(true);
        frame.setContentPane(newContentPane);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        javax.swing.SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}

它产生以下内容:

这不是火箭科学!我做错了什么?

可能这个方法对你有帮助

public static void updateRowHeight(JTable table, int margin) {
    final int rowCount = table.getRowCount();
    final int colCount = table.getColumnCount();
    for (int i = 0; i < rowCount; i++) {
        int maxHeight = 0;
        for (int j = 0; j < colCount; j++) {
            final TableCellRenderer renderer = table.getCellRenderer(i, j);
            maxHeight = Math.max(maxHeight, table.prepareRenderer(renderer, i, j).getPreferredSize().height);
        }
        table.setRowHeight(i, maxHeight + margin);
    }
}

在 table 填充数据后使用此方法。 margin 参数用于额外增加行高。如果不需要 - 使用 0.

这是单元格高度正确的示例。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

/**
 * <code>IncorrectRowHeight</code>.
 */
public class IncorrectRowHeight extends JPanel {
    private class MyCellRenderer extends JTextField implements TableCellRenderer {
        private MyCellRenderer() {
            setFont(new Font("SansSerif", Font.PLAIN, 30));
            setBorder(BorderFactory.createEmptyBorder());
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
                int column) {
            setText(value.toString());
            return this;
        }
    }

    public IncorrectRowHeight() {
        super(new BorderLayout());

        add(new JTextField(25), BorderLayout.PAGE_START);

        String[][] data = {{"a", "b", "c", "d", "e"}, {"f", "g", "h", "i", "j"}, {"k", "l", "m", "n", "o"}, {"p", "q", "r", "s", "t"}};
        String[] cols = {"h1", "h2", "h3", "h4", "h5"};
        JTable t = new JTable(data, cols);
        t.setGridColor(Color.GRAY);
        t.setPreferredScrollableViewportSize(new Dimension(300, 65));
        TableColumnModel model = t.getColumnModel();
        for (int i = 0; i < model.getColumnCount(); i++) {
            TableColumn column = model.getColumn(i);
            column.setCellRenderer(new MyCellRenderer());
        }
        updateRowHeight(t, 0);
        JScrollPane scroller = new JScrollPane(t);
        add(scroller, BorderLayout.CENTER);
    }

    public static void updateRowHeight(JTable table, int margin) {
        final int rowCount = table.getRowCount();
        final int colCount = table.getColumnCount();
        for (int i = 0; i < rowCount; i++) {
            int maxHeight = 0;
            for (int j = 0; j < colCount; j++) {
                final TableCellRenderer renderer = table.getCellRenderer(i, j);
                maxHeight = Math.max(maxHeight, table.prepareRenderer(renderer, i, j).getPreferredSize().height);
            }
            table.setRowHeight(i, maxHeight + margin);
        }
    }

    private static void createAndShowGUI() {
        JFrame frame = new JFrame("IncorrectRowHeight");
        JComponent newContentPane = new IncorrectRowHeight();
        newContentPane.setOpaque(true);
        frame.setContentPane(newContentPane);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

使用table.setRowHeight(table.getFontMetrics(font).getHeight());

package com.logicbig.example;

import javax.swing.*;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.*;

public class IncorrectRowHeight extends JPanel {
private static final Font font = new Font("SansSerif", Font.PLAIN, 30);
private class MyCellRenderer extends JTextField implements TableCellRenderer {
    private MyCellRenderer() {
        setFont(font);
        setBorder(BorderFactory.createEmptyBorder());
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                                                   int row, int column) {
        setText(value.toString());
        return this;
    }
}

public IncorrectRowHeight() {
    super(new BorderLayout());

    add(new JTextField(25), BorderLayout.PAGE_START);

    String[][] data = {
            {"a", "b", "c", "d", "e"},
            {"f", "g", "h", "i", "j"},
            {"k", "l", "m", "n", "o"},
            {"p", "q", "r", "s", "t"}
    };
    String[] cols = {"h1", "h2", "h3", "h4", "h5"};
    JTable t = new JTable(data, cols);
    t.setRowHeight(t.getFontMetrics(font).getHeight());
    t.setGridColor(Color.GRAY);
    t.setPreferredScrollableViewportSize(new Dimension(300, 65));
    TableColumnModel model = t.getColumnModel();
    for (int i = 0; i < model.getColumnCount(); i++) {
        TableColumn column = model.getColumn(i);
        column.setCellRenderer(new MyCellRenderer());
    }
    JScrollPane scroller = new JScrollPane(t);
    add(scroller, BorderLayout.CENTER);

    //t.doLayout();  // doesn't help matters
}

private static void createAndShowGUI() {
    JFrame frame = new JFrame("IncorrectRowHeight");
    JComponent newContentPane = new IncorrectRowHeight();
    newContentPane.setOpaque(true);
    frame.setContentPane(newContentPane);
    frame.pack();
    frame.setVisible(true);
}

public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
  }
 }