Friday, September 4, 2015

Extended JComboBox to support multiple JCheckBox elements

Implement JQuery style MultiSelect JComboBox with JCheckBox
Use {@link #getSelectedItems() getSelectedItems} method. to get the selected item list
See  http://www.erichynds.com/examples/jquery-ui-multiselect-widget/demos/
for the referenced JQuery implementation.

package combo;

import javax.swing.JFrame;

public class MultiCheckComboTEst extends JFrame{

private static final long serialVersionUID = -3578706354915513446L;

public static void main(String[] args) throws Exception {
MultiCheckComboTEst frame = new MultiCheckComboTEst();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
}

public MultiCheckComboTEst() throws Exception
    {
        String[] ids = { "ALL","FX", "IR", "EQ", "BOND" };
        MultiCheckComboBox comboBox = new MultiCheckComboBox( ids );
        add( comboBox );
    }

}

////////////////////////////
package combo;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.plaf.basic.ComboPopup;

/**
 * Implement JQuery style MultiSelect JComboBox with JCheckBox
 * Use {@link #getSelectedItems() getSelectedItems} method. to get the selected item list
 * <p>
 * See <a href="http://www.erichynds.com/examples/jquery-ui-multiselect-widget/demos/">Basic Demo</a>
 * for the referenced JQuery implementation.
 * <p>
 * @author pengp2
 *
 */

public class MultiCheckComboBox extends JComboBox {

private static final long serialVersionUID = 4735456197188571568L;
private MultiCheckComboModel[] models;
    public MultiCheckComboBox(final Object items[]) {
    this(items,null);
    }
    public MultiCheckComboBox(final Object items[],Boolean states[]){
    super();
    if(items==null){
    System.err.println("items cannot be null.");
    return;
    }
    if(states==null){
    states = new Boolean[items.length];
    Arrays.fill(states, false);
    }
    if(items.length!=states.length){
        System.err.println("Unexpected parameters for MultiCheckComboBox.");
    return;
    }
        models = new MultiCheckComboModel[items.length];
        for(int i=0;i<items.length;i++){
        models[i] = new MultiCheckComboModel(items[i].toString(),states[i]);
        }
        setModel(new DefaultComboBoxModel(models));
    }
    
    @Override
    public void updateUI() {
    super.updateUI();
    final MultiCheckComboRenderer render = new MultiCheckComboRenderer();
    setRenderer(render);
    setUI(new MultiCheckComboBoxUI());
    addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
       MultiCheckComboModel comboModel = (MultiCheckComboModel) MultiCheckComboBox.this.getModel().getSelectedItem();
       comboModel.setIsSelected(!comboModel.getIsSelected());
       render.getCheckBox().setSelected(comboModel.getIsSelected());

       if (comboModel.getId().equalsIgnoreCase("ALL")){
           for (int i = 0; i < getItemCount(); i++){
               ((MultiCheckComboModel)getItemAt(i)).setIsSelected(render.getCheckBox().isSelected());
           }
       }
       int selectedNum = 1;
           for (int i = 1; i < getItemCount(); i++){
            if(((MultiCheckComboModel)getItemAt(i)).getIsSelected()){
            selectedNum++;
            }
           }
           ((MultiCheckComboModel)getItemAt(0)).setIsSelected(selectedNum==getItemCount());
           getModel().setSelectedItem(selectedNum-1+" selected");
           getEditor().getEditorComponent().repaint();
       repaint();
       ((ComboPopup) getUI().getAccessibleChild(MultiCheckComboBox.this, 0)).getList().repaint();
       
//        MultiCheckComboModel[] selected = MultiCheckComboBox.this.getModels();
//        for(MultiCheckComboModel selectedO:selected){
//         System.out.println("selectedO="+selectedO);
//        }
       
}
});
    }

public MultiCheckComboModel[] getSelectedItems() {
return models;
}

}


///////
package combo;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
import javax.swing.plaf.metal.MetalComboBoxUI;
  
public class MultiCheckComboBoxUI extends MetalComboBoxUI {
  
   @Override
   protected ComboPopup createPopup() {
      return new BasicComboPopup(comboBox) {
private static final long serialVersionUID = -1657533899648565541L;
@Override
    protected MouseListener createListMouseListener() {
             return new MouseListener() {
@Override
public void mouseReleased(MouseEvent e) {
           if (e.getSource() == list) {
               if (list.getModel().getSize() > 0) {
                   // JList mouse listener
                   if (comboBox.getSelectedIndex() == list.getSelectedIndex()) {
                       comboBox.getEditor().setItem(list.getSelectedValue());
                   }
                   comboBox.setSelectedIndex(list.getSelectedIndex());
               }
//                comboBox.setPopupVisible(false);
               // workaround for cancelling an edited item (bug 4530953)
               if (comboBox.isEditable() && comboBox.getEditor() != null) {
                   comboBox.configureEditor(comboBox.getEditor(),
                                            comboBox.getSelectedItem());
               }
               return;
           }
           // JComboBox mouse listener
           Component source = (Component)e.getSource();
           Dimension size = source.getSize();
           Rectangle bounds = new Rectangle( 0, 0, size.width - 1, size.height - 1 );
           if ( !bounds.contains( e.getPoint() ) ) {
               MouseEvent newEvent = convertMouseEvent( e );
               Point location = newEvent.getPoint();
               Rectangle r = new Rectangle();
               list.computeVisibleRect( r );
               if ( r.contains( location ) ) {
                   if (comboBox.getSelectedIndex() == list.getSelectedIndex()) {
                       comboBox.getEditor().setItem(list.getSelectedValue());
                   }
                   comboBox.setSelectedIndex(list.getSelectedIndex());
               }
//                comboBox.setPopupVisible(false);
           }
           comboBox.setPopupVisible(true);
           hasEntered = false;
           stopAutoScrolling();
}
@Override
public void mousePressed(MouseEvent e) {
           if (e.getSource() == list) {
               return;
           }
           if (!SwingUtilities.isLeftMouseButton(e) || !comboBox.isEnabled())
               return;

           if ( comboBox.isEditable() ) {
               Component comp = comboBox.getEditor().getEditorComponent();
               if ((!(comp instanceof JComponent)) || ((JComponent)comp).isRequestFocusEnabled()) {
                   comp.requestFocus();
               }
           }
           else if (comboBox.isRequestFocusEnabled()) {
               comboBox.requestFocus();
           }
           togglePopup();
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
}
};
    }
      };
   }
   
}

/////
package combo;

public class MultiCheckComboModel {
    private String id;
    Boolean isSelected;

    public MultiCheckComboModel(String id, Boolean isSelected) {
        this.id = id;
        this.isSelected = isSelected;
    }

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public Boolean getIsSelected() {
return isSelected;
}

public void setIsSelected(Boolean isSelected) {
this.isSelected = isSelected;
}
@Override
public String toString() {
return id+(isSelected?" is selected":" is not selected");
}
    
}


///////
package combo;

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

import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;

public class MultiCheckComboRenderer implements ListCellRenderer{
private JCheckBox checkBox;
public MultiCheckComboRenderer() {
checkBox = new JCheckBox();
}

@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
    if(value instanceof MultiCheckComboModel){
    MultiCheckComboModel comboModel = (MultiCheckComboModel) value;
            checkBox.setText(comboModel.getId());
            checkBox.setSelected(((Boolean) comboModel.getIsSelected()).booleanValue());
            checkBox.setBackground(isSelected ? Color.LIGHT_GRAY : Color.white);
            checkBox.setForeground(isSelected ? Color.white : Color.black);
            return checkBox;
    }
    return new JLabel(value.toString());
}

public JCheckBox getCheckBox() {
return checkBox;
}

}

No comments:

Post a Comment