JPanel in the JComboBox dropdown, but not in the editor

What I want seems relatively simple, and I'm almost there. This will ultimately be used for expansion TableCellEditor, so size is important. I want something like this: Mock-up of ideal JPanelComboBox

With a combination of custom ComboBoxEditorand ListCellRendererI was able to get something like this:

Mock-up of best attempt at JPanelComboBox

Who has inconvenience:

  • Disabling any components beyond the original width JComboBox
  • When displaying the height, the JComboBoxheight JPanelin the drop-down list
  • Permission for only one (1) form modification before the drop-down list disappears.

, , , JComboBox , . (1) JPanel, , .

@ErkanHaspalut , . , JPanel JPopupMenu JTextField, , .

JComboBox, setMaximumSize height ( )

    Rectangle tmp = cboTest.getBounds();
    tmp.height = 24;
    cboTest.setBounds(tmp);

24 JComboBox.

/*
    * Program to test having a JPanel in the JComboBox drop-down but not the JComboBox editor.
    */
    package testdropdownsubform;

    import java.awt.Component;
    import java.awt.Rectangle;
    import java.awt.event.ActionListener;
    import java.awt.event.FocusEvent;
    import java.awt.event.FocusListener;
    import javafx.application.Application;
    import javafx.stage.Stage;
    import javax.swing.ComboBoxEditor;
    import javax.swing.JComboBox;
    import javax.swing.JList;
    import javax.swing.ListCellRenderer;
    import javax.swing.event.PopupMenuEvent;
    import javax.swing.event.PopupMenuListener;
    import javax.swing.JTextField;
    import javax.swing.plaf.basic.BasicComboBoxEditor;

    /**
    * @author Masked Coder
    */

    public class Dim {
        public Long DimWidth;
        public Long DimHeight;

        public Dim () {
            DimWidth = 1L;
            DimHeight = 1L;
        }

        @Override
        public String toString() {
            return DimWidth.toString() + "\' x " + DimHeight.toString() + "\'";
        }
    }

    public class DimPanel extends javax.swing.JPanel {

        public DimPanel() {
            spnDimWidth = new javax.swing.JSpinner();
            spnDimHeight = new javax.swing.JSpinner();

            spnDimWidth.setModel(new javax.swing.SpinnerNumberModel(Long.valueOf(1L), Long.valueOf(0L), null, Long.valueOf(1L)));
            spnDimWidth.setPreferredSize(new java.awt.Dimension(50, 24));
            addComponent(spnDimWidth);

            lblTween.setText(" x ");
            addComponent(lblTween);

            spnDimHeight.setModel(new javax.swing.SpinnerNumberModel(Long.valueOf(1L), Long.valueOf(0L), null, Long.valueOf(1L)));
            spnDimHeight.setPreferredSize(new java.awt.Dimension(50, 24));
            addComponent(spnDimHeight);
        }

        private javax.swing.JSpinner spnDimWidth;
        private javax.swing.JLabel lblTween;
        private javax.swing.JSpinner spnDimHeight;
    }


    public class DimListCellRenderer implements ListCellRenderer {
        private DimPanel dpDim;

        public DimListCellRenderer(DimPanel newDimPanel) {
            dpDim = newDimPanel;

        }

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            Dim dValue = (Dim) value;
            dpDim.setDim(dValue);
            return dpDim;
        }

    }

    public class DimComboBoxEditor extends BasicComboBoxEditor implements ComboBoxEditor {
        JTextField txtDim = new JTextField();
        Dim Item = new Dim();

        public DimComboBoxEditor() {
            txtDim.setEnabled(false);
            txtDim.setOpaque(true);
        }
        @Override
        public Component getEditorComponent() {
            txtDim.setText(Item.toString());
            return txtDim;
        }

        @Override
        public void setItem(Object anObject) {
            Item = (Dim) anObject;
        }

        @Override
        public Object getItem() {
            return Item;
        }

        @Override
        public void selectAll() {
            txtDim.selectAll();
        }

        @Override
        public void addActionListener(ActionListener l) {
            txtDim.addActionListener(l);
        }

        @Override
        public void removeActionListener(ActionListener l) {
            txtDim.removeActionListener(l);
        }

    }

    public class MainTestForm extends javax.swing.JFrame {
        public MainTestForm() {
            lblPrevComponent = new javax.swing.JLabel();
            chkPrevComponent = new javax.swing.JCheckBox();
            lblTest = new javax.swing.JLabel();
            cboTest = new JComboBox<testdropdownsubform.DicePanel>();
            lblNextComponent = new javax.swing.JLabel();
            scpNextComponent = new javax.swing.JScrollPane();
            txaNextComponent = new javax.swing.JTextArea();
            btnForceHeight = new javax.swing.JButton();

            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

            lblPrevComponent.setText("Prev. Component");

            chkPrevComponent.setText("jCheckBox1");

            lblTest.setText("Dimension");

            cboTest.setEditable(true);
            cboTest.setEditor(new DimComboBoxEditor());
            cboTest.setRenderer(new DimListCellRenderer(new DimPanel()));
            cboTest.addItem(new Dim());

            lblNextComponent.setText("Next Component");

            txaNextComponent.setColumns(20);
            txaNextComponent.setRows(5);
            scpNextComponent.setViewportView(txaNextComponent);

            btnForceHeight.setText("Force");
            btnForceHeight.setToolTipText("Force test combobox height");
            btnForceHeight.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    btnForceHeightActionPerformed(evt);
                }
            });

            .addComponent(lblPrevComponent)
            .addComponent(chkPrevComponent))
            .addComponent(lblTest)
            .addComponent(cboTest)
            .addComponent(lblNextComponent)
            .addComponent(scpNextComponent)
            .addComponent(btnForceHeight))

        }

    private void btnForceHeightActionPerformed(java.awt.event.ActionEvent evt) {                                               
            Rectangle tmp = cboTest.getBounds();
            tmp.height = 24;
            cboTest.setBounds(tmp);
    }                                              

        /**
        * @param args the command line arguments
        */
        public static void main(String args[]) {
            /* Create and display the form */
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    new MainTestForm().setVisible(true);
                }
            });
        }

        private javax.swing.JButton btnForceHeight;
        private javax.swing.JComboBox cboTest;
        private javax.swing.JCheckBox chkPrevComponent;
        private javax.swing.JLabel lblNextComponent;
        private javax.swing.JLabel lblPrevComponent;
        private javax.swing.JLabel lblTest;
        private javax.swing.JScrollPane scpNextComponent;
        private javax.swing.JTextArea txaNextComponent;
    }

    public class TestDropdownSubform extends Application {

        @Override
        public void start(Stage primaryStage) {
            MainTestForm mtfMain = new MainTestForm();

            mtfMain.setVisible(true);
        }

        /**
        * @param args the command line arguments
        */
        public static void main(String[] args) {
            launch(args);
        }

    }

: , - ? .

: JComboBox

JComboBox cboTest = new JComboBox<DimPanel>() {
    private boolean layingOut = false; 

    @Override
    public void doLayout(){ 
        try{ 
        layingOut = true; 
        super.doLayout(); 
        }finally{ 
        layingOut = false; 
        } 
    } 

        @Override
        public Dimension getSize(){ 
            Dimension dim = super.getSize(); 
            if(!layingOut) {
                dim.width = Math.max(dim.width, dpThis.getPreferredSize().width); 
            }
            return dim; 
        } 
};

.

JComboBox cboTest = new JComboBox<testdropdownsubform.DicePanel>() {
    private boolean layingOut = false; 

    @Override
    public void doLayout(){ 
        try{ 
        layingOut = true; 
        super.doLayout(); 
        }finally{ 
        layingOut = false; 
        } 
    } 

        @Override
        public Dimension getSize(){ 
            Dimension dim = super.getSize(); 
            if(!layingOut) {
                Dimension dim2 = dpThis.getPreferredSize(); 
                dim.width = Math.max(dim.width, dim2.width); 
    //          dim.height = dim2.height; 
            }
            return dim; 
        } 

    @Override
    public DimPanel getPrototypeDisplayValue() {
        DimPanel tmpPanel = new DimPanel();
        if(isCalledFromComboPopup()) {
        //
        }
        else {
        Dimension r = dcbeEditor.getPreferredSize();
        tmpPanel.setPreferredSize(r);
        }
        return tmpPanel;
    }

    /**
    * Hack method to determine if called from within the combo popup UI.
    */
    public boolean isCalledFromComboPopup() {
        try {
        final Throwable t = new Throwable();
        t.fillInStackTrace();
        StackTraceElement[] st = t.getStackTrace();
        // look only at top 5 elements of call stack
        int max = Math.min(st.length, 5);
        for (int i=0; i<max; ++i) {
            final String name = st[i].getClassName();
            System.out.println(i + ")  " + name);
            return ((name != null) && name.contains("ComboPopup"));
        }
        } catch (final Exception e) {
        // if there was a problem, assume not called from combo popup
        }
        return false;
    }
};

, .

+4
1

, , -combobox JTextField JButton JPanel. , . -, AbstractPopupPanel ( NetBeans, ):

package complexcombobox;

/**
*
* @author MaskedCoder
*
* @param E - the object to be edited in the panel
*/
public abstract class AbstractPopupPanel<E> extends javax.swing.JPanel {

    /**
    * Creates new form PopupPanel
    */
    public AbstractPopupPanel() {
        initComponents();
    }

    public abstract boolean isChanged();

    public abstract E getValue();

    public abstract void setValue(E newValue);

    private void initComponents() {
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }                        
}

:

package complexcombobox;

import javax.swing.JPopupMenu;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

/**
*
* @author MaskedCoder
* 
* @param E - the object to be edited
* @param P - the extension of AbstractPopupPanel that will display the object as you wish
*/
public class ComplexPopup<E, P extends AbstractPopupPanel<E>> extends JPopupMenu {

    /*
    * Interface to notify user of editing
    */
    public interface EditListener<E> {
        // return the object value to be edited.
        // if the user returns null, the existing Dice is used.
        public E beforeEdit(); 

        // receives the new value
        // called *only* when the object has actually changed.
        public void afterEdit(E newValue);  
    }

    /*
    *internal variables
    */
    private P thisPanel;
    private EditListener<E> userListener;
//  private Class<E> eClass;
//  private Class<P> pClass;
    private PopupMenuListener myPopupListener = new PopupMenuListener() {

        @Override
        public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
            if(userListener != null) {
                E tmpSize = userListener.beforeEdit();
                if(tmpSize != null) thisPanel.setValue(tmpSize);
            }
        }

        @Override
        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
            if(userListener != null) {
//              if(thisPanel.isChanged())
                    userListener.afterEdit((E) thisPanel.getValue());
            }
        }

        @Override
        public void popupMenuCanceled(PopupMenuEvent e) {
            popupMenuWillBecomeInvisible(e);
        }
    };

    /* 
    * Constructors
    */

    public ComplexPopup(E iniValue, P iniDropdownPanel, EditListener<E> iniListener) {
        super();

        init(iniValue, iniDropdownPanel, iniListener);
    }

    private void init(E iniValue, P iniDropdownPanel, EditListener<E> iniListener) {
        thisPanel = iniDropdownPanel;
        thisPanel.setValue(iniValue);
        add(thisPanel);
        userListener = iniListener;
        this.addPopupMenuListener(myPopupListener);
    }

    /* 
    * Public Properties 
    */
    public E getValue() {
        return (E) thisPanel.getValue();
    }
    public void setValue(E newObjectSize) {
        thisPanel.setValue(newObjectSize);
    }

    public EditListener getUserListener() {
        return userListener;
    }

    public void setEditListener(EditListener newListener) {
        userListener = newListener;
    }

    /*
    * functional extensions
    */
    public void afterEdit(E newValue) {
        if(userListener != null) {
            if(thisPanel.isChanged())
                userListener.afterEdit((E) thisPanel.getValue());
        }
    }
}

JPopupMenu , . JComboBox, , , , :

package complexcombobox;

/**
*
* @author MaskedCoder
* 
* @param <I> the Item (Object) to be edited
* @param <Q> the AbstractPopupPanel to be used to do the editing. 
*/
public class ComplexComboBox<I, Q extends AbstractPopupPanel<I>> extends javax.swing.JPanel {
    private ComplexPopup<I, Q> thePopup;
    private ComplexPopup.EditListener<I> myListener = new ComplexPopup.EditListener<I>() {

        @Override
        public I beforeEdit() {
            return null; // no changes so, just let it ride.
        }

        @Override
        public void afterEdit(I newValue) {
            txtEditor.setText(thePopup.getValue().toString());
        }
    };

    /**
    * Creates new form ObjectSizeComboBox
    */
    public ComplexComboBox(I iniValue, Q iniPanel) {
        initComponents();
        thePopup = new ComplexPopup<I, Q>(iniValue, iniPanel, myListener);
    }

    public I getValue() {
        return thePopup.getValue();
    }

    public void setValue(I newValue) {
        thePopup.setValue(newValue);
    }

    private void initComponents() {

        txtEditor = new javax.swing.JTextField();
        btnShowPanel = new javax.swing.JButton();

        setBackground(new java.awt.Color(255, 255, 255));
        setMinimumSize(new java.awt.Dimension(40, 19));

        txtEditor.setEditable(false);
        txtEditor.setToolTipText("");
        txtEditor.setOpaque(false);

        btnShowPanel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/testpopupsubform/art/dropdownarrow.png"))); // NOI18N
        btnShowPanel.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            btnShowPanelActionPerformed(evt);
        }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addComponent(txtEditor, javax.swing.GroupLayout.DEFAULT_SIZE, 115, Short.MAX_VALUE)
            .addGap(1, 1, 1)
            .addComponent(btnShowPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
        layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addComponent(btnShowPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(txtEditor)
        );
    }                        

    private void btnShowPanelActionPerformed(java.awt.event.ActionEvent evt) {                                             
            thePopup.show(txtEditor, 0, txtEditor.getHeight());
    }                                            

    private javax.swing.JButton btnShowPanel;
    private javax.swing.JTextField txtEditor;
}

, , , . JComboBox, :

package complexcombobox;

import java.awt.Component;
import javax.swing.AbstractCellEditor;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;

/**
*
* @author MaskedCoder
*
* @param <E> the Element (Object) to be edited
* @param <P> the AbstractPopupPanel to be used to do the editing. 
*/
public class ComplexCellEditor<E, P extends AbstractPopupPanel<E>> extends AbstractCellEditor
            implements TableCellEditor {
    private ComplexComboBox<E, P> ComplexEditor;

    /*
    * Constructors
    */
    public ComplexCellEditor(E iniValue, P iniPanel) { 
        super();

        ComplexEditor = new ComplexComboBox<E, P>(iniValue, iniPanel);
    }

    /*
    * AbstractCellEditor Extensions
    */
    @Override
    public boolean stopCellEditing() {
            return super.stopCellEditing();
    }

    /*
    * TableCellEditor Implementation
    */
        @Override
    public E getCellEditorValue() {
            return ComplexEditor.getValue();
    }

    @Override
    public Component getTableCellEditorComponent(JTable iniTable, Object iniValue, boolean isSelected, int row, int column) {
            ComplexEditor.setValue((E) iniValue);

            return ComplexEditor;
    }
}

, :  - JComboBox ,  - AbstractPopupPanel, , , ComplexComboBox ComplexCellEditor. , ComplexPopup . , Generic. Pass-through , , , , .

Generics , , , .

0

All Articles