Reputation: 81
I have a jComboBox with a few items. The goal is to add an option "All" so when the user select it all the items available would be selected.
Is it possible to do it with a jComboBox or I better use another jComponent (recommendations are welcome). It's required that it's a dropdown list (because it must fit inside a table row) so I guess it could be a menu with checkboxes or something similar.
NK
EDID: I've tried to put a fake object in the model which would be handled specifically (to get all other elements from the model) but it's really not a good idea as this fake object should implement a dozen of interfaces and it's really ugly.
Upvotes: 2
Views: 5463
Reputation: 5415
Here's a table cell editor that pops up a dialog that contains a JList of checkboxes. It's a mashup of a variety of examples from here and elsewhere.
EDIT: added the Select All feature
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.table.*;
/*
* A table cell editor that pops up a JList of checkboxes.
*/
@SuppressWarnings("unchecked")
public class CheckListEditor extends DefaultCellEditor implements Runnable
{
private PopupDialog popup;
private JButton editorComp;
private String currentText = "";
public static void main(String[] args)
{
SwingUtilities.invokeLater(new CheckListEditor());
}
public void run()
{
String[] columnNames = { "Item", "Selections" };
Object[][] data = { { "Item 1", "A" },
{ "Item 2", "B" },
{ "Item 3", "C" } };
JTable table = new JTable(data, columnNames);
table.getColumnModel().getColumn(1).setPreferredWidth(300);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
CheckListEditor popupEditor = new CheckListEditor();
popupEditor.setList(Arrays.asList(new String[]{"A", "B", "C"}));
table.getColumnModel().getColumn(1).setCellEditor(popupEditor);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JFrame frame = new JFrame("Multi-Select Editor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(scrollPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public CheckListEditor()
{
super(new JTextField());
setClickCountToStart(2);
// Use a JButton as the editor component
editorComp = new JButton();
editorComp.setFont(editorComp.getFont().deriveFont(Font.PLAIN));
editorComp.setBackground(Color.WHITE);
editorComp.setBorderPainted(false);
editorComp.setContentAreaFilled(false);
editorComp.setHorizontalAlignment(SwingConstants.LEFT);
// Set up the dialog where we do the actual editing
popup = new PopupDialog();
}
@Override
public Object getCellEditorValue()
{
return currentText;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
popup.setValue(currentText);
Point p = editorComp.getLocationOnScreen();
popup.setLocation(p.x, p.y + editorComp.getSize().height);
popup.setVisible(true);
fireEditingStopped();
}
});
currentText = value.toString();
editorComp.setText(currentText);
return editorComp;
}
public <T> void setList(List<T> items)
{
popup.setList(items);
}
/*
* Dialog that contains the "editor" panel
*/
class PopupDialog extends JDialog
{
private final String delimiter = ",";
private JList jlist;
public PopupDialog()
{
super((Frame) null, "Select", true);
setUndecorated(true);
getRootPane().setWindowDecorationStyle(JRootPane.NONE);
jlist = new JList();
jlist.setCellRenderer(new CheckBoxListRenderer());
jlist.setPrototypeCellValue(new CheckListItem("12345678901234567890"));
jlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jlist.setVisibleRowCount(5);
jlist.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent event)
{
selectItem(event.getPoint());
}
});
JScrollPane scrollPane = new JScrollPane(jlist);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JButton selectAll = new JButton("Select All");
selectAll.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
selectAllItems();
}
});
JButton ok = new JButton("OK");
ok.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
closeDialog(true);
}
});
JButton cancel = new JButton("Cancel");
cancel.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
closeDialog(false);
}
});
JPanel buttons = new JPanel();
buttons.add(selectAll);
buttons.add(ok);
buttons.add(cancel);
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createLineBorder(Color.BLUE, 1));
panel.add(scrollPane, BorderLayout.CENTER);
panel.add(buttons, BorderLayout.SOUTH);
setContentPane(panel);
pack();
getRootPane().setDefaultButton(ok);
}
private void selectAllItems()
{
ListModel model = jlist.getModel();
for (int index = 0; index < model.getSize(); index++)
{
CheckListItem item = (CheckListItem) model.getElementAt(index);
item.setSelected(true);
}
jlist.repaint();
}
/*
* Save the changed text before hiding the popup
*/
public void closeDialog(boolean commit)
{
if (commit)
{
currentText = getSelectedItems();
}
jlist.requestFocusInWindow();
setVisible(false);
}
private void selectItem(Point point)
{
int index = jlist.locationToIndex(point);
if (index >= 0)
{
CheckListItem item = (CheckListItem) jlist.getModel().getElementAt(index);
item.setSelected(!item.isSelected());
jlist.repaint(jlist.getCellBounds(index, index));
}
}
private <T> void setList(List<T> items)
{
Vector<CheckListItem> listData = new Vector<CheckListItem>();
for (T item : items)
{
listData.add(new CheckListItem(item));
}
jlist.setListData(listData);
}
public String getSelectedItems()
{
String text = "";
ListModel model = jlist.getModel();
for (int i = 0; i < model.getSize(); i++)
{
CheckListItem item = (CheckListItem) model.getElementAt(i);
if (item.isSelected())
{
text += item.toString();
text += delimiter;
}
}
if (text.endsWith(delimiter))
{
text = text.substring(0, text.lastIndexOf(delimiter));
}
return text;
}
public void setValue(String value)
{
ListModel model = jlist.getModel();
for (int i = 0; i < model.getSize(); i++)
{
((CheckListItem) model.getElementAt(i)).setSelected(false);
}
String text = value == null ? "" : value.toString();
String[] tokens = text.split(delimiter);
for (String token : tokens)
{
for (int i = 0; i < model.getSize(); i++)
{
if (model.getElementAt(i).toString().equals(token))
{
((CheckListItem) model.getElementAt(i)).setSelected(true);
}
}
}
jlist.clearSelection();
jlist.ensureIndexIsVisible(0);
}
}
private class CheckBoxListRenderer extends JCheckBox implements ListCellRenderer
{
public Component getListCellRendererComponent(JList comp, Object value, int index,
boolean isSelected, boolean hasFocus)
{
setEnabled(comp.isEnabled());
setSelected(((CheckListItem) value).isSelected());
setFont(comp.getFont());
setText(value.toString());
if (isSelected)
{
setBackground(comp.getSelectionBackground());
setForeground(comp.getSelectionForeground());
}
else
{
setBackground(comp.getBackground());
setForeground(comp.getForeground());
}
return this;
}
}
private class CheckListItem
{
private Object item;
private boolean selected;
public CheckListItem(Object item)
{
this.item = item;
}
public boolean isSelected()
{
return selected;
}
public void setSelected(boolean isSelected)
{
this.selected = isSelected;
}
@Override
public String toString()
{
return item.toString();
}
}
}
Upvotes: 2
Reputation: 122
It is possible with a JComboBox, however, you need to implement a Renderer and ActionListener for the JComboBox and keep track of the selected items. Example:
private class MultiSelectionHandler<ComboBoxItemType> extends BasicComboBoxRenderer implements ActionListener{
private static final long serialVersionUID = 1L;
private ArrayList<Object> selected = new ArrayList<Object>();
private JComboBox<ComboBoxItemType> comboBox;
public MultiSelectionHandler(JComboBox<ComboBoxItemType> comboBox){
this.comboBox = comboBox;
comboBox.addActionListener(this);
comboBox.setRenderer(this);
selected.add(comboBox.getSelectedItem());
}
@Override
public void actionPerformed(ActionEvent e) {
// Get the now selected item
ComboBoxItemType selectedItem = comboBox.getItemAt(comboBox.getSelectedIndex());
if(selectedItem.equals("All")){
// The the "All"-item has been chosen
// Select all items (except the "All"-item)
int itemcount = comboBox.getItemCount();
for(int i=0; i<itemcount; i++){
Object item = comboBox.getItemAt(i);
if (!selected.contains(item) && !item.equals("All") ){
selected.add(item);
}
}
} else {
// Another option has been chosen
// Toggle the selection
if(selected.contains(selectedItem)) {
selected.remove(selectedItem);
} else if(!selected.contains(selectedItem)) {
selected.add(selectedItem);
}
}
}
@Override
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
// Set the background and foreground colors, use the selection colors if the item
// is in the selected list
if (selected.contains(value)) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
// Set the text of the item
setText((value == null) ? "" : value.toString());
return this;
}
}
(it seems to work at first glance, but probably is littered with bugs ;-) )
Then you can use this multi-selection-thingy like this:
// Create the items
String[] arr = {"One", "Two", "Three", "All"};
// Create the model and the box
DefaultComboBoxModel<String> model = new DefaultComboBoxModel<String>(arr);
JComboBox<String> box = new JComboBox<String>(model);
// Use the MultiSelectionHandler for rendering
new MultiSelectionHandler<String>(box);
Upvotes: 2
Reputation: 17971
You could try with JList
instead (see How to Use Lists) using SINGLE_SELECTION_INTERVAL
or MULTIPLE_SELECTION_INTERVAL
mode to achieve your target.
JList list = new JList(new DefaultListModel());
list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
JButton selectAll = new JButton("Select All");
selectAll.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
DefaultListModel dlm = (DefaultListModel)list.getModel();
list.setSelectionInterval(0, dlm.getSize() - 1);
}
});
Upvotes: 1