步进组合框刷新

Stepped ComboBox refresh

A Stepped ComboBox 对于使下拉弹出窗口比文本字段更宽非常有用。但是,当新内容添加到列表时,弹出窗口会恢复其初始宽度。

默认

刷新后(新元素)

SSCCE

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
import javax.swing.plaf.metal.MetalComboBoxUI;

public class SteppedComboBoxRefresh extends JFrame {
    private List<String> list;
    private final SteppedComboBox combo;

    public SteppedComboBoxRefresh() {
        super("SteppedComboBox Refresh");

        this.list = new ArrayList<String>(Arrays.asList(new String[]{
                "AAA", "AAAAAA"
        }));

        this.combo = new SteppedComboBox(this.list.toArray());
        this.combo.setDimensions(50);

        JButton addButton = new JButton("Add longer string");
        addButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                list.add(list.get(list.size()-1) + "AAA");
                combo.setModel(new DefaultComboBoxModel(list.toArray()));
                combo.setDimensions(50);
            }
        });

        getContentPane().setLayout(new FlowLayout());
        getContentPane().add(this.combo);
        getContentPane().add(addButton);
    }

    public static void main (String args[]) {
        SteppedComboBoxRefresh f = new SteppedComboBoxRefresh();
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        f.setSize (300, 100);
        f.setVisible(true);
    }
}

class SteppedComboBoxUI extends MetalComboBoxUI {
    @Override
    protected ComboPopup createPopup() {
        BasicComboPopup popup = new BasicComboPopup( this.comboBox ) {

            @Override
            public void show() {
                Dimension popupSize = ((SteppedComboBox)this.comboBox).getPopupSize();
                popupSize.setSize( popupSize.width,
                        getPopupHeightForRowCount( this.comboBox.getMaximumRowCount() ) );
                Rectangle popupBounds = computePopupBounds( 0,
                        this.comboBox.getBounds().height, popupSize.width, popupSize.height);
                this.scroller.setMaximumSize( popupBounds.getSize() );
                this.scroller.setPreferredSize( popupBounds.getSize() );
                this.scroller.setMinimumSize( popupBounds.getSize() );
                this.list.invalidate();
                int selectedIndex = this.comboBox.getSelectedIndex();
                if ( selectedIndex == -1 ) {
                    this.list.clearSelection();
                } else {
                    this.list.setSelectedIndex( selectedIndex );
                }
                this.list.ensureIndexIsVisible( this.list.getSelectedIndex() );
                setLightWeightPopupEnabled( this.comboBox.isLightWeightPopupEnabled() );

                show( this.comboBox, popupBounds.x, popupBounds.y );
            }
        };
        popup.getAccessibleContext().setAccessibleParent(this.comboBox);
        return popup;
    }
}

class SteppedComboBox extends JComboBox {
    protected int popupWidth;

    public SteppedComboBox(ComboBoxModel aModel) {
        super(aModel);
        setUI(new SteppedComboBoxUI());
        this.popupWidth = 0;
    }

    public SteppedComboBox(final Object[] items) {
        super(items);
        setUI(new SteppedComboBoxUI());
        this.popupWidth = 0;
    }

    public SteppedComboBox(Vector items) {
        super(items);
        setUI(new SteppedComboBoxUI());
        this.popupWidth = 0;
    }

    public void setPopupWidth(int width) {
        this.popupWidth = width;
    }

    public Dimension getPopupSize() {
        Dimension size = getSize();
        if (this.popupWidth < 1) {
            this.popupWidth = size.width;
        }
        return new Dimension(this.popupWidth, size.height);
    }

    public void setDimensions(int width) {
        Dimension d = getPreferredSize();
        setPreferredSize(new Dimension(width, d.height));
        setPopupWidth(d.width);
    }
}

ComboBox 仍然使用其以前的 PreferredSize。需要将首选大小设置回 null,以便我们获得列表中新内容首选的大小。

void javax.swing.JComponent.setPreferredSize(Dimension preferredSize)

Sets the preferred size of this component. If preferredSize is null, the UI will be asked for the preferred size.

public void setDimensions(int width) {
    setPreferredSize(null);
    Dimension d = getPreferredSize();
    setPreferredSize(new Dimension(width, d.height));
    setPopupWidth(d.width);
}

结果

您可以使用 Combo Box Popup

它是阶梯式组合框的更灵活的版本。最重要的是,它可以用于任何组合框,因为逻辑是在“PopupMenuListener”中实现的。

您可以控制弹出窗口的最大宽度。您甚至可以将弹出窗口显示在组合框上方而不是下方。