java - JComboBox 单元渲染器在 Windows 外观和感觉下失败

标签 java windows swing jcombobox listcellrenderer

我正在编写一个使用本地系统外观的 Java 应用程序。在程序中,有一个 ListCellRenderer,它渲染一个彩色点(自定义 JComponment),后跟给定对象的一些文本。当使用 Swing 的默认 Metal 外观和感觉时,这效果很好。

但是,当我使用 Windows 外观时,单元格在下拉列表中正确呈现,但所选项目(当用户未选择其他选项时显示的项目)仅呈现文本并忽略彩色点。如果我更改渲染器来设置字体,则在下拉列表和所选项目中都会观察到正确的字体,因此我知道单元格渲染器正在被使用,至少是部分使用。

我在网上读过一些关于不同 LAF 导致此类问题的帖子,但没有遇到任何人讨论我的特定问题。

如果有人好奇,这里是代码:

.

@Override
public Component getListCellRendererComponent(JList<? extends ColoredDisplayable> jlist, ColoredDisplayable e, int i, boolean isSelected, boolean hasFocus) {

    JPanel cell = new JPanel(new GridBagLayout());
    cell.setOpaque(false);

    JLabel label = new JLabel(e.getDisplayString());
    label.setOpaque(false);
    label.setBorder(BorderFactory.createEmptyBorder(1, 4, 1, 4));
    label.setHorizontalAlignment(JLabel.LEFT);

    Color deselectedBackground = cell.getBackground();
    Color deselectedTextColor = cell.getForeground();

    // LAYOUT COMPONENTS
    // Dot
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.insets = INSETS;
    gbc.anchor = GridBagConstraints.LINE_START;
    gbc.weightx = 0.0f;
    gbc.fill = GridBagConstraints.NONE;
    cell.add(new Dot(e.getColor()), gbc);

    // Label
    gbc.gridx = 1;
    gbc.weightx = 1.0f;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    cell.add(label, gbc);


    if (isSelected){
        cell.setOpaque(true);
        cell.setBackground(MetalLookAndFeel.getTextHighlightColor());
    } else {
        cell.setBackground(deselectedBackground);
        cell.setForeground(deselectedTextColor);
    }

    return cell;
}

此外,这是自定义组件的代码,任何人都想尝试一下,看看我是否只是在这里做了一些愚蠢的事情:

public class Dot extends JComponent {

    /** The size of the dot. */
    private static final int SIZE = 10;

    /** The size of the dot. */
    private static final int PAD = 4;

    private static final Dimension DIM = new Dimension(SIZE + PAD, SIZE + PAD);

    /** The Color to render the dot. */
    private final Color m_color;

    /** The Dot itself. */
    private static final Ellipse2D.Double DOT = new Ellipse2D.Double(PAD / 2, PAD / 2, SIZE, SIZE);

    /**
     * Creates a dot of the specified color.
     * @param color the color to make the dot.
     */
    public Dot(Color color) {
        m_color = color;
    }

    @Override
    public void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setColor(m_color);
        g2d.fill(DOT);
    }

    @Override
    public Dimension getPreferredSize() {
        return DIM;
    }
}

编辑:我刚刚在 Ubuntu 12.04 上测试了这一点,单元格渲染器按预期工作(尽管 JCombobox 没有像没有应用自定义渲染器时那样渲染其外部边框)。

编辑:随着我越来越多地研究这一点,似乎 JComboBox 上的 setEditor 方法可能有一些东西,但是当不可编辑时,渲染器应该用作 javadoc该方法指出:

Sets the editor used to paint and edit the selected item in the JComboBox field. The editor is used only if the receiving JComboBox is editable. If not editable, the combo box uses the renderer to paint the selected item.

这似乎不是我所看到的行为。我必须做什么才能让 Windows LAF 用户观察到单元格渲染器的所有部分?

最佳答案

深入研究后,我发现对于 Windows LAF,我需要设置一个 ComboBoxEditor 并将 JComboBox 设置为可编辑,以便所选单元格能够正确呈现。

在我看来,这是一个特定于 Windows 外观和感觉的错误/意外函数,因为 JComboBox 的 setEditor 方法的 API 声明,当不可编辑时,将使用渲染器 - 并且在默认 Metal LAF 中运行时也是如此以及 Ubuntu 上。

除此之外,我无法像在 ListCellRenderer 中那样每次调用 getEditorComponent 时都让编辑器返回一个新单元格。我认为这是有道理的。

这个网站提供了一个如何创建编辑器的示例(尽管有点平淡):

JComboBox 和 BasicComboBox 的 API 也很有帮助:

最后,我的编辑器代码:

public class ColoredDisplayableComboBoxEditor extends BasicComboBoxEditor {

    private ColoredDisplayable m_cd = null;
    private static final Insets INSETS = new Insets(3, 1, 3, 1);
    private final JPanel m_cell;
    private final JLabel m_label;
    private final Dot m_dot;

    public ColoredDisplayableComboBoxEditor() {
        // INITIALIZE
        // Panel
        m_cell = new JPanel(new GridBagLayout());
        m_cell.setOpaque(false);

        // Label
        m_label = new JLabel();
        m_label.setOpaque(false);
        m_label.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4));
        m_label.setHorizontalAlignment(JLabel.LEFT);

        // Dot
        m_dot = new Dot(Color.BLACK);

        // LAYOUT
        // Dot
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets = INSETS;
        gbc.anchor = GridBagConstraints.LINE_START;
        gbc.weightx = 0.0f;
        gbc.fill = GridBagConstraints.NONE;
        m_cell.add(m_dot, gbc);

        // Label
        gbc.gridx = 1;
        gbc.weightx = 1.0f;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        m_cell.add(m_label, gbc);
    }

    @Override
    public Component getEditorComponent() {
        return m_cell;
    }

    @Override
    public Object getItem() {
        System.out.println("getting item.");
        return m_cd;
    }

    @Override
    public void setItem(Object item) {
        System.out.println("setting item.");
        if (item instanceof ColoredDisplayable) {
            ColoredDisplayable cd = (ColoredDisplayable)item;
            if (!cd.equals(m_cd)) {
                System.out.println("--item actually set.");
                m_cd = cd;
                m_label.setText(m_cd.getDisplayString());
                m_dot.setColor(m_cd.getColor());
            }            
        } else {
            throw new IllegalArgumentException("Parameter item must be a ColoredDisplayable.");
        }
    }
}

关于java - JComboBox 单元渲染器在 Windows 外观和感觉下失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30825527/

相关文章:

windows - 带有 bazel 的 Tensorflow : avx ignored?

java - 在 JCheckBox 中有一个左右对齐的标签

java - jframe组件布局

java - matlab中大小的java表示是什么

java - 从 MySQL 5.5 升级到 5.6 并获取 "SQLException: Connection is closed"

linux - 是否可以得到一个大页和一个连续的普通页

windows - 无法连接到 URL 'svn://localhost' 的存储库

java - 重写 SwingWorker 中的 process() 方法

Java 文件下载器不工作

java - 用Java中的所有枚举值填充列表