I have code for making a checkbox list. However, if I click anywhere on a row the checkbox selection changes. I want this to only happen when the checkbox itself is clicked. How do I correct this listener to be "accurate"?
Here is a SSCCE:
import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
public class CheckBoxList extends JList
{
public CheckBoxList()
{
super();
setModel(new DefaultListModel<>());
setCellRenderer(new CheckboxCellRenderer());
addMouseListener(new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent mouseEvent)
{
int index = locationToIndex(mouseEvent.getPoint());
if (index != -1)
{
Object object = getModel().getElementAt(index);
if (object instanceof JCheckBox)
{
JCheckBox checkbox = (JCheckBox) object;
checkbox.setSelected(!checkbox.isSelected());
repaint();
}
}
}
});
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
public static void main(String[] arguments)
{
JFrame frame = new JFrame();
DefaultListModel<String> listModel = new DefaultListModel<>();
listModel.addElement("Element 1");
listModel.addElement("Element 2");
JList<String> list = new JList<>();
list.setCellRenderer(new CheckboxListCellRenderer<>());
list.setModel(listModel);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(list);
frame.pack();
frame.setVisible(true);
}
}
class CheckboxCellRenderer extends DefaultListCellRenderer
{
private static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus)
{
if (value instanceof CheckBoxListEntry)
{
CheckBoxListEntry checkbox = (CheckBoxListEntry) value;
checkbox.setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
if (checkbox.isRed())
{
checkbox.setForeground(Color.red);
} else
{
checkbox.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
}
checkbox.setEnabled(isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
} else
{
return super.getListCellRendererComponent(list, value.getClass().getName(), index,
isSelected, cellHasFocus);
}
}
}
class CheckBoxListEntry extends JCheckBox
{
public CheckBoxListEntry(Object itemValue, boolean selected)
{
super(itemValue == null ? "" : "" + itemValue, selected);
}
public boolean isSelected()
{
return super.isSelected();
}
public void setSelected(boolean selected)
{
super.setSelected(selected);
}
boolean isRed()
{
return false;
}
}
Related
import java.awt.*;
import java.awt.event.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.table.*;
public class TableButtonCell extends JFrame {
private JPanel topPanel;
private JTable table;
public TableButtonCell() {
setTitle("JButton in JTable");
setSize(300,150);
topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
getContentPane().add(topPanel);
String [] columns = new String[] {"Text", "Button"};
String[][] data = new String[][]{
{"Line 1", ""},
{"Line 2", ""},
{"Line 3", ""}};
DefaultTableModel model = new DefaultTableModel(data,columns);
table = new JTable();
table.setModel(model);
table.getColumn("Button").setCellRenderer(new ButtonRenderer());
table.getColumn("Button").setCellEditor(new ButtonEditor());
JScrollPane scrollPane = new JScrollPane(table);
topPanel.add(scrollPane,BorderLayout.CENTER);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
class ButtonRenderer extends JButton implements TableCellRenderer {
public ButtonRenderer() {
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
setText((value == null) ? "Modify" : value.toString());
return this;
}
}
class ButtonEditor extends JButton implements TableCellEditor {
public ButtonEditor() {
JPopupMenu popup = new JPopupMenu();
JMenuItem item = new JMenuItem("Menu action 1");
item.addActionListener(this::menuAction);
item = new JMenuItem("Menu action 2");
item.addActionListener(this::menuAction);
setComponentPopupMenu(popup);
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
JOptionPane.showMessageDialog(null,"JButton clicked");
}
});
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
return this;
}
public Object getCellEditorValue() {
return null;
}
public void menuAction(ActionEvent ev) {
JOptionPane.showMessageDialog(null,"JButton clicked");
}
#Override
public boolean isCellEditable(EventObject anEvent) {
return true;
}
#Override
public boolean shouldSelectCell(EventObject anEvent) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean stopCellEditing() {
return true;
}
#Override
public void cancelCellEditing() {
}
#Override
public void addCellEditorListener(CellEditorListener l) {
}
#Override
public void removeCellEditorListener(CellEditorListener l) {
}
}
public static void main(String args[]) {
TableButtonCell f = new TableButtonCell();
f.setVisible(true);
}
}
The SSCE above creates a JTable with JButton as cell renderer/editor.
It's working fine & button action is triggered correclty
When trying to add a popup menu to the JButton, the menu is not shown when clicking mouse right button.
Looks like the table is consuming the Mouse right click event, so the JButton didn't receive & react to the event ?
Any clue ?
Thanks in advance for any guidance/help
Now it's working with the following code. Hope this may help some one else.
import java.awt.*;
import java.awt.event.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.table.*;
public class TableButtonCell extends JFrame {
private JPanel topPanel;
private JTable table;
public TableButtonCell() {
setTitle("JButton in JTable");
setSize(300,150);
topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
getContentPane().add(topPanel);
String [] columns = new String[] {"Text", "Button"};
String[][] data = new String[][]{
{"Line 1", "Button 1"},
{"Line 2", "Button 2"},
{"Line 3", "Button 3"},
{"Line 4", "Button 4"}};
DefaultTableModel model = new DefaultTableModel(data,columns);
table = new JTable();
table.setModel(model);
ButtonRendererEditor renderer = new ButtonRendererEditor(table, 1);
TableColumn tc = table.getColumn("Button");
tc.setCellRenderer(renderer);
tc.setCellEditor(renderer);
JScrollPane scrollPane = new JScrollPane(table);
topPanel.add(scrollPane,BorderLayout.CENTER);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
class ButtonRendererEditor extends JButton implements TableCellRenderer, TableCellEditor {
int column;
public ButtonRendererEditor(JTable table, int column) {
this.column = column;
JPopupMenu popup = new JPopupMenu();
JMenuItem item = new JMenuItem("Menu action 1");
item.addActionListener(this::menuAction);
popup.add(item);
item = new JMenuItem("Menu action 2");
item.addActionListener(this::menuAction);
popup.add(item);
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
JOptionPane.showMessageDialog(null,"JButton clicked");
}
});
table.addMouseListener( new MouseAdapter() {
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
if (!e.isPopupTrigger())
return;
JTable source = (JTable)e.getSource();
int col = source.columnAtPoint(e.getPoint());
if (col != column)
return;
popup.show(e.getComponent(), e.getX(), e.getY());
}
});
}
public void menuAction(ActionEvent ev) {
JOptionPane.showMessageDialog(null,"Menu item clicked");
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
setText((value == null) ? "" : value.toString());
return this;
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
setText((value == null) ? "" : value.toString());
return this;
}
public Object getCellEditorValue() {
return null;
}
#Override
public boolean isCellEditable(EventObject anEvent) {
return true;
}
#Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
#Override
public boolean stopCellEditing() {
return true;
}
#Override
public void cancelCellEditing() {
}
#Override
public void addCellEditorListener(CellEditorListener l) {
}
#Override
public void removeCellEditorListener(CellEditorListener l) {
}
}
public static void main(String args[]) {
TableButtonCell f = new TableButtonCell();
f.setVisible(true);
}
}
I have a JTable with 3 columns, the first column is a simple text, the other 2 columns are JComboBox. Column Name and Column Email both have a custom TableCellEditor and TableCellRenderer.
Sometimes when I click on a comboBox in a row that is not selected, the cell would not be drawn with the proper selected color (blue).
For illustration purposes, the TableCellRenderer draws pink cells, and TableCellEditor draws orange cells.
JTable returns false for isCellSelected(), more specifically returns false for isRowSelected(), at JTable editCellAt(). However when the renderer calls isCellSelected(), it returns true, so renderer is properly colored.
I can't figure out what's going wrong here.
My SSCCE:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractCellEditor;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumnModel;
import org.iii.snsi.streamcenter.main.Main;
public class EditorNotSelectedColorFrame {
public JComponent makeUI() {
JTable table = new JTable();
DefaultTableModel model = new DefaultTableModel(new String[]{"COL 1", "COL 2", "COL 3"}, 0);
table.setModel(model);
for (int i = 0; i < 5; i++) {
Object[] row = new Object[3];
row[0] = new MyListItem(new String[]{"item a", "item b", "item c"});
row[1] = new MyListItem(new String[]{"item d", "item e", "item f"});
row[2] = new MyListItem(new String[]{"item g", "item h", "item i"});
model.addRow(row);
}
MyTableCellEditor editor = new MyTableCellEditor(Color.orange, Color.BLACK);
MyTableCellRenderer renderer = new MyTableCellRenderer(Color.pink, Color.BLACK);
TableColumnModel columnModel = table.getColumnModel();
columnModel.getColumn(0).setCellEditor(editor);
columnModel.getColumn(1).setCellEditor(editor);
columnModel.getColumn(2).setCellEditor(editor);
columnModel.getColumn(0).setCellRenderer(renderer);
columnModel.getColumn(1).setCellRenderer(renderer);
columnModel.getColumn(2).setCellRenderer(renderer);
JPanel panel = new JPanel(new BorderLayout());
panel.add(new JScrollPane(table));
return panel;
}
public static void main(String... args) {
try {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Windows".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new EditorNotSelectedColorFrame().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
class MyListItem<T> {
private ArrayList<T> items = new ArrayList<>();
private Integer selectedIndex = -1;
public MyListItem(T[] items) {
selectedIndex = -1;
this.items.addAll(Arrays.asList(items));
}
public ArrayList<T> getItems() {
return items;
}
public void setSelectedIndex(Integer selectedIndex) {
this.selectedIndex = selectedIndex;
}
public Integer getSelectedIndex() {
return selectedIndex;
}
}
class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor {
private Color unselectedBackground;
private Color unselectedForeground;
private JMyComboBox comboBox;
private MyListItem myListItem;
public MyTableCellEditor(Color bg, Color fg) {
unselectedBackground = bg;
unselectedForeground = fg;
comboBox = new JMyComboBox(bg, fg);
comboBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stopCellEditing();
}
});
}
#Override
public Object getCellEditorValue() {
int idx = comboBox.getSelectedIndex();
if (idx > -1) {
myListItem.setSelectedIndex(comboBox.getSelectedIndex());
}
return myListItem;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
comboBox.removeAllItems();
if (value instanceof MyListItem) {
myListItem = (MyListItem) value;
for (Object item : myListItem.getItems()) {
comboBox.addItem(item.toString());
}
comboBox.setSelectedIndex(myListItem.getSelectedIndex());
} else {
myListItem = null;
}
if (isSelected) {
comboBox.setForeground(table.getSelectionForeground());
comboBox.setBackground(table.getSelectionBackground());
} else {
comboBox.setForeground(unselectedForeground);
comboBox.setBackground(unselectedBackground);
}
return comboBox;
}
}
class MyTableCellRenderer extends DefaultTableCellRenderer {
private Color unselectedBackground;
private Color unselectedForeground;
private JMyComboBox comboBox;
public MyTableCellRenderer(Color bg, Color fg) {
super();
unselectedBackground = bg;
unselectedForeground = fg;
comboBox = new JMyComboBox(bg, fg);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
comboBox.removeAllItems();
if (value instanceof MyListItem) {
MyListItem cellItem = (MyListItem) value;
for (Object item : cellItem.getItems()) {
comboBox.addItem(item.toString());
}
comboBox.setSelectedIndex(cellItem.getSelectedIndex());
}
if (isSelected) {
comboBox.setForeground(table.getSelectionForeground());
comboBox.setBackground(table.getSelectionBackground());
} else {
comboBox.setForeground(unselectedForeground);
comboBox.setBackground(unselectedBackground);
}
return comboBox;
}
}
class JMyComboBox extends JComboBox<String> {
private MyComboBoxEditor editor = new MyComboBoxEditor();
private MyComboBoxRenderer renderer = new MyComboBoxRenderer();
public JMyComboBox(Color bg, Color fg) {
super();
setEditable(true);
setEditor(editor);
setRenderer(renderer);
editor.setColors(bg, fg);
renderer.setColors(bg, fg);
}
#Override
public void setBackground(Color bg) {
super.setBackground(bg);
if (editor != null) {
editor.setColors(bg, getForeground());
}
}
#Override
public void setForeground(Color fg) {
super.setForeground(fg);
if (editor != null) {
editor.setColors(getBackground(), fg);
}
}
}
class MyComboBoxEditor extends BasicComboBoxEditor {
private JLabel label = new JLabel();
public MyComboBoxEditor() {
super();
label.setOpaque(true);
}
public void setColors(Color background, Color foreground) {
label.setBackground(background);
label.setForeground(foreground);
}
#Override
public void setItem(Object anObject) {
super.setItem(anObject);
label.setText(((JTextField) super.getEditorComponent()).getText());
}
#Override
public Component getEditorComponent() {
return label;
}
}
class MyComboBoxRenderer extends DefaultListCellRenderer {
private Color unselectedBackground;
private Color unselectedForeground;
public void setColors(Color background, Color foreground) {
this.unselectedBackground = background;
this.unselectedForeground = foreground;
}
#Override
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (!isSelected) {
if (unselectedBackground != null) {
setBackground(unselectedBackground);
}
if (unselectedForeground != null) {
setForeground(unselectedForeground);
}
}
return this;
}
}
I have the following Code that Buttons are within cells
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
/**
* #version 1.0 11/09/98
*/
public class JButtonTableExample extends JFrame {
public JButtonTableExample() {
super("JButtonTable Example");
DefaultTableModel dm = new DefaultTableModel();
dm.setDataVector(new Object[][] { { "button 1", "foo" },
{ "button 2", "bar" } }, new Object[] { "Button", "String" });
JTable table = new JTable(dm);
table.setFont(new Font("Comic Sans MA",0,20));
table.setRowHeight(35);
table.getColumn("Button").setCellRenderer(new ButtonRenderer());
table.getColumn("Button").setCellEditor(
new ButtonEditor(new JCheckBox()));
JScrollPane scroll = new JScrollPane(table);
getContentPane().add(scroll);
setSize(400, 100);
setVisible(true);
}
public static void main(String[] args) {
JButtonTableExample frame = new JButtonTableExample();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
/**
* #version 1.0 11/09/98
*/
class ButtonRenderer extends JButton implements TableCellRenderer {
public ButtonRenderer() {
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(UIManager.getColor("Button.background"));
}
setText((value == null) ? "" : value.toString());
return this;
}
}
/**
* #version 1.0 11/09/98
*/
class ButtonEditor extends DefaultCellEditor {
protected JButton button;
private String label;
private boolean isPushed;
public ButtonEditor(JCheckBox checkBox) {
super(checkBox);
button = new JButton();
button.setFont(new Font("Comic Sans MS",0,25));
buttonButtonEditor
button.setOpaque(true);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (isSelected) {
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setForeground(table.getForeground());
button.setBackground(table.getBackground());
}
label = (value == null) ? "" : value.toString();
button.setText(label);
isPushed = true;
return button;
}
public Object getCellEditorValue() {
if (isPushed) {
//
//
JOptionPane.showMessageDialog(button, label + ": Ouch!");
// System.out.println(label + ": Ouch!");
}
isPushed = false;
return new String(label);
}
public boolean stopCellEditing() {
isPushed = false;
return super.stopCellEditing();
}
protected void fireEditingStopped() {
super.fireEditingStopped();
}
}
I tried to change the font of the buttons by adding the following line of code to the ButtonEditor class
button.setFont(new Font("Comic Sans MS",0,25));
But it doesn't Work!!
What should I do to change the font of those buttons
Edit your ButtonRenderer class as follows:
class ButtonRenderer extends JButton implements TableCellRenderer {
public ButtonRenderer() {
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(UIManager.getColor("Button.background"));
}
setText((value == null) ? "" : value.toString());
setFont(new Font("Times New Roman", 0, 10)); //Add this line
return this;
}
}
Font was always being reset to the table's model, so you were needing to add that line to force the model to respect the change.
And your output should be:
I need to provide some disabled items in a combobox. All works fine except preventing of combobox from closing after click on a disabled item.
Here is my code:
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import javax.swing.plaf.basic.ComboPopup;
public class DisabledCombo {
public static void main(String[] args) {
final DisabledSupportComboModel model = new DisabledSupportComboModel();
model.addElement(new Item("First element"));
model.addElement(new Item("Second element"));
model.addElement(new Item("Disabled", false));
model.addElement(new Item("Fourth element"));
final JComboBox<Item> itemCombo = new JComboBox<DisabledCombo.Item>(model);
itemCombo.setRenderer(new DisabledSupportComboRenderer());
final ComboPopup popup = (ComboPopup) itemCombo.getUI().getAccessibleChild(itemCombo, 0);
final JList<?> l = popup.getList();
final MouseListener[] listeners = l.getMouseListeners();
for (final MouseListener ml : listeners) {
l.removeMouseListener(ml);
System.out.println("remove listener: " + ml);
}
System.out.println("Number of listeners: " + l.getMouseListeners().length);
l.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
System.out.println("Release");
final int idx = l.locationToIndex(e.getPoint());
if (idx >= 0 && l.getModel().getElementAt(idx) instanceof Item) {
final Item itm = (Item) l.getModel().getElementAt(idx);
if (!itm.isEnabled()) {
e.consume();
}
}
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Click");
final int idx = l.locationToIndex(e.getPoint());
if (idx >= 0 && l.getModel().getElementAt(idx) instanceof Item) {
final Item itm = (Item) l.getModel().getElementAt(idx);
if (!itm.isEnabled()) {
e.consume();
}
}
}
});
for (final MouseListener ml : listeners) {
l.addMouseListener(ml);
}
final JFrame frm = new JFrame("Combo test");
frm.add(itemCombo);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class Item {
private final Object value;
private final boolean enabled;
public Item(Object aValue) {
value = aValue;
enabled = true;
}
public Item(Object aValue, boolean isEnabled) {
value = aValue;
enabled = isEnabled;
}
public Object getValue() {
return value;
}
public boolean isEnabled() {
return enabled;
}
/**
* {#inheritDoc}
*/
#Override
public String toString() {
return null == value? null : value.toString();
}
}
private static class DisabledSupportComboModel extends DefaultComboBoxModel<Item> {
/**
* {#inheritDoc}
*/
#Override
public void setSelectedItem(Object anObject) {
if (anObject instanceof Item) {
if (((Item) anObject).isEnabled()) {
super.setSelectedItem(anObject);
}
} else {
super.setSelectedItem(anObject);
}
}
}
private static class DisabledSupportComboRenderer extends BasicComboBoxRenderer {
/**
* {#inheritDoc}
*/
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof Item) {
if (((Item) value).isEnabled()) {
setForeground(isSelected? list.getSelectionForeground() : list.getForeground());
setBackground(isSelected? list.getSelectionBackground() : list.getBackground());
} else {
setForeground(UIManager.getColor("Label.disabledForeground"));
setBackground(list.getBackground());
}
} else {
setForeground(isSelected? list.getSelectionForeground() : list.getForeground());
setBackground(isSelected? list.getSelectionBackground() : list.getBackground());
}
return this;
}
}
}
My problem is, that I get mouseReleased event, but no mouseClicked event. The only way to get mouseClicked event is to register AWTEventListener for mouse events using the Toolkit class. But it's realy ugly here. The approach to show the popup again using the setPopupVisible(true) is also difficult here due to eventually scroll pane in popup (the real combobox can have about 30 entries, so I need to save the scroll bar value to restore the drop down list at the same position). Can somebody advise me, how can I prevent the combo popup from closing?
Here's my attempt:
Override JComboBox#setPopupVisible(boolean) instead of using JList#addMouseListener(...)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DisabledCombo2 {
public static JComponent makeUI() {
DisabledSupportComboModel model = new DisabledSupportComboModel();
model.addElement(new Item("First element"));
model.addElement(new Item("Second element"));
model.addElement(new Item("Disabled", false));
model.addElement(new Item("Fourth element"));
JComboBox<Item> itemCombo = new JComboBox<Item>(model) {
//#see http://java-swing-tips.blogspot.jp/2010/03/non-selectable-jcombobox-items.html
private boolean isDisableIndex;
#Override public void setPopupVisible(boolean v) {
if (!v && isDisableIndex) {
//Do nothing(prevent the combo popup from closing)
isDisableIndex = false;
} else {
super.setPopupVisible(v);
}
}
#Override public void setSelectedObject(Object o) {
if (o instanceof Item && !((Item) o).isEnabled()) {
isDisableIndex = true;
} else {
super.setSelectedObject(o);
}
}
#Override public void setSelectedIndex(int index) {
Object o = getItemAt(index);
if (o instanceof Item && !((Item) o).isEnabled()) {
isDisableIndex = true;
} else {
super.setSelectedIndex(index);
}
}
};
itemCombo.setRenderer(new DisabledSupportComboRenderer());
return itemCombo;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame("Combo test2");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(makeUI());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class Item {
private final Object value;
private final boolean enabled;
public Item(Object aValue) {
value = aValue;
enabled = true;
}
public Item(Object aValue, boolean isEnabled) {
value = aValue;
enabled = isEnabled;
}
public Object getValue() {
return value;
}
public boolean isEnabled() {
return enabled;
}
#Override public String toString() {
return null == value ? null : value.toString();
}
}
class DisabledSupportComboModel extends DefaultComboBoxModel<Item> {
#Override public void setSelectedItem(Object anObject) {
if (anObject instanceof Item) {
if (((Item) anObject).isEnabled()) {
super.setSelectedItem(anObject);
}
} else {
super.setSelectedItem(anObject);
}
}
}
class DisabledSupportComboRenderer extends DefaultListCellRenderer {
#Override public Component getListCellRendererComponent(
JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof Item) {
if (((Item) value).isEnabled()) {
setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
} else {
setForeground(UIManager.getColor("Label.disabledForeground"));
setBackground(list.getBackground());
}
} else {
setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
}
return this;
}
}
I found some simple solution to always keep popup open, until user clicks outside the popup. It may be useful with some custom JComboBox'es, like the one I have in my project, but is a little hacky.
public class MyComboBox extends JComboBox
{
boolean select_action_performed = false; //check when user select item
public MyComboBox(){
setRenderer(new MyComboBoxRenderer()); //our spesial render
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
//Do stuff when user select item
select_action_performed = true; //set the flag
}
});
}
class MyComboBoxRenderer extends BasicComboBoxRenderer {
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
if (index == -1){ //if popup hidden
if (select_action_performed) {
showPopup(); //show it again
select_action_performed = false; //and remove the flag
}
return r;
}
}
}
}
I'm very new to programming, and I can't add JCheckbox to the JList. There is no error but nothing is displayed.
JFrame f=new JFrame();
String[] labels={"a","b","c","d","e"};
JCheckBox[] ch=new JCheckBox[labels.length];
JList list=new JList();
for (int i = 0; i < labels.length; i++) {
ch[i]=new JCheckBox("CheckBox"+i);
list.add(ch[i]);
}
JScrollPane pane=new JScrollPane(list);
f.add(pane);
f.setVisible(true);
As an alternative to the JTable solution that trashgod posted, you can also create the appearance of JCheckBoxes in a JList by:
Use a custom renderer for your JList that will show each item as a JCheckBox
Use a custom object in your JList that maintains it's boolean "checked" state
Add a MouseListener to the JList that will set/unset the checked state of each item.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class JCheckBoxListDemo implements Runnable
{
private JList jlist;
public static void main(String args[])
{
SwingUtilities.invokeLater(new JCheckBoxListDemo());
}
public void run()
{
Object[] items = new CheckListItem[] {
new CheckListItem("Apple"),
new CheckListItem("Banana"),
new CheckListItem("Carrot"),
new CheckListItem("Date"),
new CheckListItem("Eggplant"),
new CheckListItem("Fig"),
new CheckListItem("Guava"),
};
jlist = new JList(items);
jlist.setCellRenderer(new CheckBoxListRenderer());
jlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jlist.setVisibleRowCount(5);
jlist.addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent event)
{
selectItem(event.getPoint());
}
});
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0);
Object mapKey = keyStroke.toString();
jlist.getInputMap().put(keyStroke, mapKey);
jlist.getActionMap().put(mapKey, new AbstractAction()
{
public void actionPerformed(ActionEvent event)
{
toggleSelectedItem();
}
});
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(jlist));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
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 void toggleSelectedItem()
{
int index = jlist.getSelectedIndex();
if (index >= 0)
{
CheckListItem item = (CheckListItem)jlist.getModel().getElementAt(index);
item.setSelected(!item.isSelected());
jlist.repaint(jlist.getCellBounds(index, index));
}
}
private class CheckListItem
{
private Object item;
private boolean selected;
public CheckListItem(Object item)
{
this.item = item;
}
#SuppressWarnings("unused")
public Object getItem()
{
return item;
}
public boolean isSelected()
{
return selected;
}
public void setSelected(boolean isSelected)
{
this.selected = isSelected;
}
#Override
public String toString()
{
return item.toString();
}
}
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;
}
}
}
A JList renderer can draw a checkbox, but JList does not support a cell editor. Instead, consider a one-column JTable. The default renderer & editor for a column of type Boolean.class is a JCheckBox, for example.
Here is what you might be looking for:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class CheckBo
{
public static void main(String[] args)
{
JFrame f=new JFrame();
String[]labels={"a","b","c","d","e"};
JCheckBox[]ch=new JCheckBox[labels.length];
final DefaultListModel model = new DefaultListModel();
JList list=new JList(model);
list.setCellRenderer(new CheckListRenderer());
for (int i = 0; i < labels.length; i++) {
//ch[i]=new JCheckBox("CheckBox"+i);
model.addElement(new CheckListItem("CheckBox"+i));
}
JScrollPane pane=new JScrollPane(list);
list.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent event)
{
JList list = (JList) event.getSource();
// Get index of item clicked
int index = list.locationToIndex(event.getPoint());
CheckListItem item = (CheckListItem)
list.getModel().getElementAt(index);
// Toggle selected state
item.setSelected(! item.isSelected());
// Repaint cell
list.repaint(list.getCellBounds(index, index));
}
});
f.add(pane);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
static class CheckListItem
{
private String label;
private boolean isSelected = false;
public CheckListItem(String label)
{
this.label = label;
}
public boolean isSelected()
{
return isSelected;
}
public void setSelected(boolean isSelected)
{
this.isSelected = isSelected;
}
public String toString()
{
return label;
}
}
static class CheckListRenderer extends JCheckBox implements ListCellRenderer
{
public Component getListCellRendererComponent(JList list, Object value, int index,boolean isSelected, boolean hasFocus)
{
setEnabled(list.isEnabled());
setSelected(((CheckListItem)value).isSelected());
setFont(list.getFont());
setBackground(list.getBackground());
setForeground(list.getForeground());
setText(value.toString());
return this;
}
}
}
Source for above code is this