繁体   English   中英

JComboBox 单元格渲染器在 Windows 外观和感觉中失败

[英]JComboBox Cell Renderer Fails with Windows Look and Feel

我正在编写一个使用本地系统外观的 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:

设置用于在 JComboBox 字段中绘制和编辑所选项目的编辑器。 仅当接收 JComboBox 可编辑时才使用编辑器。 如果不可编辑,组合框将使用渲染器绘制所选项目。

这似乎不是我所看到的行为。 我必须做什么才能让 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.");
        }
    }
}

暂无
暂无

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

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