小编典典

设置JComboBox PopupMenu的大小

java

我正在编程扩展JComboBox的自定义组件。我的问题是,如果我要添加或删除项目,PopupMenu不会实现其大小。因此,例如,列表中有2个项目,但是如果在PopupMenu中还有2个“空”项目之前还有4个项目。

我发现的唯一解决方法是(在JIntelligentComboBox.java第213行中)

this.setPopupVisible(false); this.setPopupVisible(true);

但结果将是闪烁的PopupMenu :-(

那么我还能做些什么来刷新/重画PopupMenu而不会闪烁呢?

对于测试:组件和一些测试程序
要产生我的问题,您可以例如:

  • 输入“ e”
  • 按“返回”
  • 输入“ m”

提前致谢

编辑:我的目标是一个ComboBox,其行为类似于例如Firefox或Chrome中的adressbar,我想显示包含类型字符的PopupMenu的所有项目。

cboxtester.java:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.plaf.basic.BasicComboBoxRenderer;


public class cboxtester extends JFrame {

    private DefaultComboBoxModel dcm = new DefaultComboBoxModel(new Object[][] {new Object[] {"Mittagessen", "", 0}, 
                                                                                new Object[] {"Essen", "", 0}, 
                                                                                new Object[] {"Frühstück", "", 0}, 
                                                                                new Object[] {"Abendessen", "", 0}});

    private JIntelligentComboBox icb = new JIntelligentComboBox(dcm);

    private cboxtester(){
        this.add(icb, BorderLayout.CENTER);

        this.add(new JButton("bla"), BorderLayout.EAST);

        this.pack();
        this.setVisible(true);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        cboxtester cbt = new cboxtester();
    }

}

JIntelligentComboBox.java:

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Vector;

import javax.swing.ComboBoxEditor;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultRowSorter;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.MutableComboBoxModel;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import javax.swing.plaf.metal.MetalComboBoxEditor;


public class JIntelligentComboBox extends JComboBox {

    private ArrayList<Object> itemBackup = new ArrayList<Object>();

    /**  Initisiert die JIntelligentComboBox */
    private void init(){

        class searchComboBoxEditor extends BasicComboBoxEditor {
            public searchComboBoxEditor(){
                super();
            }

            @Override
            public void setItem(Object anObject){
                if (anObject == null) {
                    super.setItem(anObject);
                } else {
                    Object[] o = (Object[]) anObject;
                    super.setItem(o[0]);
                }
            }

            @Override
            public Object getItem(){
                return new Object[]{super.getItem(), super.getItem(), 0};
            }
        }

        this.setEditor(new searchComboBoxEditor());

        this.setEditable(true);

        class searchRenderer extends BasicComboBoxRenderer {

            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus){
                if (index == 0) {
                    setText("");
                    this.setPreferredSize(new Dimension(1, 1));
                    return this;
                }

                this.setPreferredSize(new Dimension(160, 17));

                if (index == list.getModel().getSize() - 1) {
                    this.setBorder(new EmptyBorder(0, 3, 1, 3));
                } else {
                    this.setBorder(new EmptyBorder(0, 3, 0, 3));
                }

                Object[] v = (Object[]) value;
                //System.out.println(v[0]);
                this.setFont(new Font("Arial", Font.PLAIN, 12));
                this.setBackground(Color.white);

                String s = (String) v[0];
                String lowerS = s.toLowerCase();
                String sf = (String) v[1];
                String lowerSf = sf.toLowerCase();
                ArrayList<String> notMatching = new ArrayList<String>();

                if (!sf.equals("")){
                    int fs = -1;
                    int lastFs = 0;
                    while ((fs = lowerS.indexOf((String) lowerSf, (lastFs == 0) ? -1 : lastFs)) > -1) {
                        notMatching.add(s.substring(lastFs, fs));
                        lastFs = fs + sf.length();
                        //System.out.println(fs+sf.length());
                    }
                    notMatching.add(s.substring(lastFs));
                    //System.out.println(notMatching);
                }

                String html = "";

                if (notMatching.size() > 1) {
                    html = notMatching.get(0);
                    int start = html.length();
                    int sfl = sf.length();
                    for (int i = 1; i < notMatching.size(); i++) {
                        String t = notMatching.get(i);
                        html += "<b style=\"color: black;\">" + s.substring(start, start + sfl) + "</b>" + t;
                        start += sfl + t.length();
                    }
                }

                System.out.println(index + html);

                this.setText("<html><head></head><body style=\"color: gray;\">" + html + "</body></head>");
                return this;
            }

        }

        this.setRenderer(new searchRenderer());

        // leeres Element oben einfügen
        int size = this.getModel().getSize();
        Object[] tmp = new Object[this.getModel().getSize()];

        for (int i = 0; i < size; i++) {
            tmp[i] = this.getModel().getElementAt(i);
            itemBackup.add(tmp[i]);
        }

        this.removeAllItems();

        this.getModel().addElement(new Object[]{"", "", 0});
        for (int i = 0; i < tmp.length; i++) {
            this.getModel().addElement(tmp[i]);
        }

        // keylistener hinzufügen
        this.getEditor().getEditorComponent().addKeyListener(new KeyListener() {

            @Override
            public void keyPressed(KeyEvent e) {
                // TODO Auto-generated method stub
            }

            @Override
            public void keyReleased(KeyEvent e) {
                // TODO Auto-generated method stub
                searchAndListEntries(((JTextField)JIntelligentComboBox.this.getEditor().getEditorComponent()).getText());
                //System.out.println(((JTextField)JIntelligentComboBox.this.getEditor().getEditorComponent()).getText());
            }

            @Override
            public void keyTyped(KeyEvent e) {
                // TODO Auto-generated method stub
            }
        });
    }

    public JIntelligentComboBox(){
        super();
    }

    public JIntelligentComboBox(MutableComboBoxModel aModel){
        super(aModel);
        init();
    }

    public JIntelligentComboBox(Object[] items){
        super(items);
        init();
    }

    public JIntelligentComboBox(Vector<?> items){
        super(items);
        init();
    }

    @Override
    public MutableComboBoxModel getModel(){
        return (MutableComboBoxModel) super.getModel();
    }

    private void searchAndListEntries(Object searchFor){        
        ArrayList<Object> found = new ArrayList<Object>();

        //System.out.println("sf: "+searchFor);

        for (int i = 0; i < this.itemBackup.size(); i++) {
            Object tmp = this.itemBackup.get(i);
            if (tmp == null || searchFor == null) continue;

            Object[] o = (Object[]) tmp;
            String s = (String) o[0];
            if (s.matches("(?i).*" + searchFor + ".*")){
                found.add(new Object[]{((Object[])tmp)[0], searchFor, ((Object[])tmp)[2]});
            }
        }

        this.removeAllItems();

        this.getModel().addElement(new Object[] {searchFor, searchFor, 0});

        for (int i = 0; i < found.size(); i++) {
            this.getModel().addElement(found.get(i));
        }

        this.setPopupVisible(true);     
    }



}

阅读 193

收藏
2020-09-26

共1个答案

小编典典

以下解决方案的基础是每次调用时都要调整弹出窗口的大小searchAndListRoutine。您需要考虑的是,当弹出窗口显示在父框架的边界之外时,该弹出窗口可以显示在其自己的窗口中,或者可以将其显示在父框架的分层窗格中:

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Vector;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.plaf.basic.*;
import javax.swing.plaf.metal.*;
import javax.swing.plaf.basic.*;


public class JIntelligentComboBox extends JComboBox {

    private ArrayList<Object> itemBackup = new ArrayList<Object>();

    /**  Initisiert die JIntelligentComboBox */
    private void init(){

        class searchComboBoxEditor extends BasicComboBoxEditor {
            public searchComboBoxEditor(){
                super();
            }

            @Override
            public void setItem(Object anObject){
                if (anObject == null) {
                    super.setItem(anObject);
                } else {
                    Object[] o = (Object[]) anObject;
                    super.setItem(o[0]);
                }
            }

            @Override
            public Object getItem(){
                return new Object[]{super.getItem(), super.getItem(), 0};
            }
        }

        this.setEditor(new searchComboBoxEditor());

        this.setEditable(true);

        class searchRenderer extends BasicComboBoxRenderer {

            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus){
                if (index == 0) { 
                    setText(""); 
                    this.setPreferredSize(new Dimension(1, 1)); 
                    return this; 
                }

                this.setPreferredSize(new Dimension(160, 17));

                if (index == list.getModel().getSize() - 1) { 
                    this.setBorder(new EmptyBorder(0, 3, 1, 3)); 
                } else { 
                    this.setBorder(new EmptyBorder(0, 3, 0, 3)); 
                }

                Object[] v = (Object[]) value; 
                //System.out.println(v[0]);
                this.setFont(new Font("Arial", Font.PLAIN, 12));
                this.setBackground(Color.white);

                String s = (String) v[0];
                String lowerS = s.toLowerCase();
                String sf = (String) v[1];
                String lowerSf = sf.toLowerCase();
                ArrayList<String> notMatching = new ArrayList<String>();

                if (!sf.equals("")){
                    int fs = -1;
                    int lastFs = 0;
                    while ((fs = lowerS.indexOf((String) lowerSf, (lastFs == 0) ? -1 : lastFs)) > -1) {
                        notMatching.add(s.substring(lastFs, fs));
                        lastFs = fs + sf.length();
                        //System.out.println(fs+sf.length());
                    }
                    notMatching.add(s.substring(lastFs));
                    //System.out.println(notMatching);
                }

                String html = "";

                if (notMatching.size() > 1) {
                    html = notMatching.get(0);
                    int start = html.length();
                    int sfl = sf.length();
                    for (int i = 1; i < notMatching.size(); i++) {
                        String t = notMatching.get(i);
                        html += "<b style=\"color: black;\">" + s.substring(start, start + sfl) + "</b>" + t;
                        start += sfl + t.length();
                    }
                }

                this.setText("<html><head></head><body style=\"color: gray;\">" + html + "</body></head>");
                return this;
            }

        }

        this.setRenderer(new searchRenderer());

        //
        int size = this.getModel().getSize();
        Object[] tmp = new Object[this.getModel().getSize()];

        for (int i = 0; i < size; i++) {
            tmp[i] = this.getModel().getElementAt(i);
            itemBackup.add(tmp[i]);
        }

        this.removeAllItems();

        this.getModel().addElement(new Object[]{"", "", 0});
        for (int i = 0; i < tmp.length; i++) {
            this.getModel().addElement(tmp[i]);
        }

        //
        this.getEditor().getEditorComponent().addKeyListener(new KeyListener() {

            @Override 
            public void keyPressed(KeyEvent e) { 
                // TODO Auto-generated method stub 
            }

            @Override 
            public void keyReleased(KeyEvent e) { 
                // TODO Auto-generated method stub 
                searchAndListEntries(((JTextField)JIntelligentComboBox.this.getEditor().getEditorComponent()).getText()); 
                //System.out.println(((JTextField)JIntelligentComboBox.this.getEditor().getEditorComponent()).getText()); 
            }

            @Override 
            public void keyTyped(KeyEvent e) {
                // TODO Auto-generated method stub 
            }
        });
    }

    public JIntelligentComboBox(){ 
        super(); 
    }

    public JIntelligentComboBox(MutableComboBoxModel aModel){
        super(aModel); 
        init(); 
    }

    public JIntelligentComboBox(Object[] items){
        super(items);
        init();
    }

    public JIntelligentComboBox(Vector<?> items){
        super(items);
        init();
    }

    @Override
    public MutableComboBoxModel getModel(){
        return (MutableComboBoxModel) super.getModel();
    }

    private void searchAndListEntries(Object searchFor){
        ArrayList<Object> found = new ArrayList<Object>();

        //System.out.println("sf: "+searchFor);

        for (int i = 0; i < this.itemBackup.size(); i++) {
            Object tmp = this.itemBackup.get(i);
            if (tmp == null || searchFor == null) continue;

            Object[] o = (Object[]) tmp;
            String s = (String) o[0];
            if (s.matches("(?i).*" + searchFor + ".*")){
                found.add(new Object[]{((Object[])tmp)[0], searchFor, ((Object[])tmp)[2]});
            }
        }

        this.removeAllItems();

        this.getModel().addElement(new Object[] {searchFor, searchFor, 0});

        for (int i = 0; i < found.size(); i++) {
            this.getModel().addElement(found.get(i));
        }

        //this.setPopupVisible(true);
        int size = this.getModel().getSize() - 1;

        System.out.println("Elements: " + size);

        if (size == 0)
        {
            this.setPopupVisible( false );
            return;
        }

        this.setPopupVisible(true);

        BasicComboPopup popup =
            (BasicComboPopup)this.getAccessibleContext().getAccessibleChild(0);
        Window popupWindow = SwingUtilities.windowForComponent(popup);
        Window comboWindow = SwingUtilities.windowForComponent(this);

        if (comboWindow.equals(popupWindow))
        {
            Component c = popup.getParent();
            Dimension d = c.getPreferredSize();
            c.setSize(d);
        }
        else
        {
            popupWindow.pack();
        }
    }
}

一个问题是,当组合框字段为空时,模型包含4个条目。我想这与您的匹配逻辑有关。

2020-09-26