Java 如何在MacOS上使用分隔符固定JComboBox弹出窗口的垂直位置?

Java 如何在MacOS上使用分隔符固定JComboBox弹出窗口的垂直位置?,java,macos,swing,jcombobox,separator,Java,Macos,Swing,Jcombobox,Separator,我使用“将JSepator与ComboBoxItem一起添加到JPanel上渲染”ListCellRenderer方法在JComboBox中显示分隔符 我注意到,MacOS上垂直居中弹出窗口中所选项目的算法被JSepator ComboxItems的高度变化搞糊涂了 有没有办法修复此屏幕截图右侧显示的弹出窗口的错误位置?如果选择了“西班牙”-项目,则该项目的油漆稍微过高;“汽车”-项目太高了 源代码: import java.awt.BorderLayout; import java.awt.

我使用“将JSepator与ComboBoxItem一起添加到JPanel上渲染”ListCellRenderer方法在JComboBox中显示分隔符

我注意到,MacOS上垂直居中弹出窗口中所选项目的算法被JSepator ComboxItems的高度变化搞糊涂了

有没有办法修复此屏幕截图右侧显示的弹出窗口的错误位置?如果选择了“西班牙”-项目,则该项目的油漆稍微过高;“汽车”-项目太高了

源代码:

import java.awt.BorderLayout;
import java.awt.Component;
import java.util.Arrays;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.ListCellRenderer;

public class JComboBoxSeparatorMacOs {

    public static void main(String[] args) {
    JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(new JComboBox<String>("A,Normal,Combo Box,without Separators".split(",")), BorderLayout.WEST);

        JComboBox<String> comboBox = new JComboBox<String>("Spain,Italy,Car,Peru".split(","));
        ListCellRenderer<String> renderer = new SeparatorListCellRenderer<String>(comboBox.getRenderer(), 0);
        comboBox.setRenderer(renderer);
        frame.add(comboBox);

        frame.pack();
        frame.setVisible(true);
    }
}

class SeparatorListCellRenderer<E> implements ListCellRenderer<E> {
    private final ListCellRenderer<? super E> delegate;
    private final int[] indexes;
    private final JPanel panel = new JPanel(new BorderLayout());

    public SeparatorListCellRenderer(ListCellRenderer<? super E> delegate, int... indexes) {
        Arrays.sort(indexes);
        this.delegate = delegate;
        this.indexes = indexes;
        panel.setOpaque(false);  //for rendering of selected item on MSWindows
    }

    @Override
    public Component getListCellRendererComponent(JList list, E value, int index, boolean isSelected, boolean cellHasFocus) {
        panel.removeAll();
        panel.add(delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus));
        if (Arrays.binarySearch(indexes, index) >= 0)
            panel.add(new JSeparator(), BorderLayout.PAGE_END);

        return panel;
    }
}
导入java.awt.BorderLayout;
导入java.awt.Component;
导入java.util.array;
导入javax.swing.JComboBox;
导入javax.swing.JFrame;
导入javax.swing.JList;
导入javax.swing.JPanel;
导入javax.swing.jsepator;
导入javax.swing.ListCellRenderer;
公共类JComboxSeparatorMacos{
公共静态void main(字符串[]args){
JFrame=新JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(新的JComboBox(“A,普通,组合框,不带分隔符”).split(“,”),BorderLayout.WEST);
JComboBox组合框=新的JComboBox(“西班牙、意大利、汽车、秘鲁”)。拆分(“,”);
ListCellRenderer=new SeparatorListCellRenderer(comboBox.getRenderer(),0);
setRenderer(渲染器);
frame.add(组合框);
frame.pack();
frame.setVisible(true);
}
}
类分隔符ListCellRenderer实现ListCellRenderer{
私人最终清单
  • 我认为这个问题与本机操作系统的外观无关

  • JComboBox
    JPopup
    可以/不能被限制、更改或覆盖某些Swing GUI构建器中的某些方法

  • 对于
    @camickr

  • 也许
    Renderer
    中的
    jsepator
    可能有点不同

    a) 查看
    ActionListener
    itemstener

    b) 请注意,对于添加到派生的
    JList
    (可能不重要)中的正确
    KeyListener
    ,此功能不起作用

图像

代码

import java.util.*;
导入java.awt.*;
导入java.awt.event.*;
导入javax.swing.*;
导入javax.swing.border.*;
公共类ComboBoxWithSeparator扩展JFrame{
私有静态最终长serialVersionUID=1L;
最终字符串分隔符=“分隔符”;
公共ComboxWithSeparator(){
超级(“块组合框示例”);
字符串[][]str={{“A”、“B”、“C”}、{“1”、“2”、“3”}、{“abc”、“def”、“ghi”};
JComboBox组合=新的JComboBox(makeVectorData(str));
setRenderer(新的ComboBoxRenderer());
addActionListener(新的BlockComboListener(combo));
combo.setPrototypeDisplayValue(“XXXXXXXXXXXXXXXXXX”);
setLayout(新的FlowLayout());
JComboBox combo1=新的JComboBox(makeVectorData(str));
combo1.setRenderer(新的ComboBoxRenderer());
combo1.addActionListener(新的BlockComboListener(combo));
combo1.setPrototypeDisplayValue(“XXXXXXXXXXXXXX”);
BoundsPopupMenuListener侦听器=新的BoundsPopupMenuListener(true,true);
combo1.addPopupMenuListener(侦听器);
combo1.setPrototypeDisplayValue(“ItemWWW”);
添加(组合);
增加(1);
包装();
setVisible(真);
}
专用向量makeVectorData(字符串[][]str){
布尔值=false;
向量数据=新向量();
对于(int i=0;iimport java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class ComboBoxWithSeparator extends JFrame {

    private static final long serialVersionUID = 1L;
    final String SEPARATOR = "SEPARATOR";

    public ComboBoxWithSeparator() {
        super("Block ComboBox Example");
        String[][] str = {{"A", "B", "C"}, {"1", "2", "3"}, {"abc", "def", "ghi"}};
        JComboBox combo = new JComboBox(makeVectorData(str));
        combo.setRenderer(new ComboBoxRenderer());
        combo.addActionListener(new BlockComboListener(combo));
        combo.setPrototypeDisplayValue("XXXXXXXXXXXXXXXXX");
        setLayout(new FlowLayout());
        JComboBox combo1 = new JComboBox(makeVectorData(str));
        combo1.setRenderer(new ComboBoxRenderer());
        combo1.addActionListener(new BlockComboListener(combo));
        combo1.setPrototypeDisplayValue("XXXXXXXXXXXXXXXXX");
        BoundsPopupMenuListener listener = new BoundsPopupMenuListener(true, true);
        combo1.addPopupMenuListener(listener);
        combo1.setPrototypeDisplayValue("ItemWWW");
        add(combo);
        add(combo1);
        pack();
        setVisible(true);
    }

    private Vector<String> makeVectorData(String[][] str) {
        boolean needSeparator = false;
        Vector<String> data = new Vector<String>();
        for (int i = 0; i < str.length; i++) {
            if (needSeparator) {
                data.addElement(SEPARATOR);
            }
            for (int j = 0; j < str[i].length; j++) {
                data.addElement(str[i][j]);
                needSeparator = true;
            }
        }
        return data;
    }

    public static void main(String args[]) {
        try {
            for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(laf.getName())) {
                    UIManager.setLookAndFeel(laf.getClassName());
                    //UIManager.getLookAndFeelDefaults().put("Panel.background", Color.white);
                    //UIManager.getLookAndFeelDefaults().put("Button.contentMargins", new InsetsUIResource(0,0,0,0));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        ComboBoxWithSeparator frame = new ComboBoxWithSeparator();
        frame.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }

    private class ComboBoxRenderer extends JLabel implements ListCellRenderer {

        private static final long serialVersionUID = 1L;
        private JSeparator separator;

        public ComboBoxRenderer() {
            setOpaque(true);
            setBorder(new EmptyBorder(1, 1, 1, 1));
            separator = new JSeparator(JSeparator.HORIZONTAL);
        }

        @Override
        public Component getListCellRendererComponent(JList list, Object value,
                int index, boolean isSelected, boolean cellHasFocus) {
            String str = (value == null) ? "" : value.toString();
            if (SEPARATOR.equals(str)) {
                return separator;
            }
            if (isSelected) {
                setBackground(list.getSelectionBackground());
                setForeground(list.getSelectionForeground());
            } else {
                setBackground(list.getBackground());
                setForeground(list.getForeground());
            }
            setFont(list.getFont());
            setText(str);
            return this;
        }
    }

    private class BlockComboListener implements ActionListener {

        private JComboBox combo;
        private Object currentItem;

        BlockComboListener(JComboBox combo) {
            this.combo = combo;
            combo.setSelectedIndex(0);
            currentItem = combo.getSelectedItem();
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            String tempItem = (String) combo.getSelectedItem();
            if (SEPARATOR.equals(tempItem)) {
                combo.setSelectedItem(currentItem);
            } else {
                currentItem = tempItem;
            }
        }
    }
}
new JComboBox("<html><b>Spain</b></html>,Italy,Car,Peru"…