4

「JPanelでComboBoxItem-to-renderと一緒にJSeparatorを追加する」 -ListCellRendererアプローチを使用して、JComboBoxにセパレーターを表示しています。

ポップアップで選択したアイテムを垂直方向に中央揃えにする MacOS のアルゴリズムが、JSeparator-ComboBoxItems の高さの変更によって混乱することに気付きました。

このスクリーンショットの右側に表示されるポップアップの間違った位置を修正する方法はありますか? "Spain"-Item を選択すると、ペイントが少し高すぎます。「車」-項目が高すぎます。

JComboBox Separator MacOs バグ

ソースコード:

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

2 に答える 2

2

これは、現在の選択を取り巻くcom.apple.laf.AquaComboBoxUIリストの多くを公開しようとする機能のように見えます。リストに.aを持つaaが含まれることを期待していません。JSeparatorcom.apple.laf.AquaPopupMenuSeparatorUI

別の方法として、次のいずれかのアプローチを検討してください。

  • HTMLを使用してエントリを装飾します。例:

    new JComboBox("<html><b>Spain</b></html>,Italy,Car,Peru"…
    
  • ここFontに示すように、レンダラーでを変更します。

于 2012-10-09T16:55:03.467 に答える
1
  • Platoformこの問題は//とは何もないと思いNative OSますLook and Feel

  • JComboBoxJPopup一部の Swing GUI ビルダーで一部のメソッドを制限、変更、オーバーライドできた/できなかった

  • コンボ ボックス ポップアップJComboBoxes JPopup使用するための@camickr

  • たぶん少し違うJSeparatorかもしれませんRenderer

    ActionListenera)またはからの可能な出力ItemListener

    KeyListenerb) これは、派生物に適切に追加された場合には機能しないことに注意してくださいJList(重要ではないかもしれません) 。

画像

ここに画像の説明を入力ここに画像の説明を入力

コード

import 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;
            }
        }
    }
}
于 2012-10-09T11:43:54.470 に答える