How to Make a List with Checkboxes in Java Swing

How do I make a list with checkboxes in Java Swing?

Create a custom ListCellRenderer and asign it to the JList.

This custom ListCellRenderer must return a JCheckbox in the implementantion of getListCellRendererComponent(...) method.

But this JCheckbox will not be editable, is a simple paint in the screen is up to you to choose when this JCheckbox must be 'ticked' or not,

For example, show it ticked when the row is selected (parameter isSelected), but this way the check status will no be mantained if the selection changes. Its better to show it checked consulting the data below the ListModel, but then is up to you to implement the method who changes the check status of the data, and notify the change to the JList to be repainted.

I Will post sample code later if you need it

ListCellRenderer

CheckBoxList in Java?

Found this: http://chianti.ucsd.edu/svn/csplugins/trunk/soc/jgao/IDMapping/src/csplugins/id/mapping/ui/CheckComboBox.java

It is an extension of JComboBox.

Sample Image

Here is a quick example I whipped up, but you get the picture:

import java.util.HashSet;
import java.util.Set;
import javax.swing.JFrame;

@SuppressWarnings("serial")
public class Test extends JFrame {

public Test() {
Set<Object> options = new HashSet<>();
options.add(new Option<Integer>("One", 1));
options.add(new Option<Integer>("Two", 2));
options.add(new Option<Integer>("Three", 3));
options.add(new Option<Integer>("Four", 4));
CheckComboBox c = new CheckComboBox(options);
this.add(c);
this.setVisible(true);
this.setLocationRelativeTo(null);
this.pack();
}

public static void main(String[] args) {
new Test();
}

private class Option<T> implements Comparable<T> {
private String label;
private T value;

public Option(String label, T value) {
this.label = label;
this.value = value;
}

@Override
public String toString() {
return this.label;
}

@Override
public int compareTo(T o) {
// TODO Auto-generated method stub
return 0;
}
}
}

Dynamic Arraylist of checkboxes in Java Swing

you need to call repaint and revalidate function to the container that holds your check boxes to redraw it with the new check boxes .

How to Add Listener to List of Checkboxes in JavaSwing

As suggested in a comment by @MadProgrammer and shown here, here and here, you can use JTable for the view and store Boolean values in the corresponding TableModel.

image

How to make a JList that each Item contains JCheckBox and JLabel with different events on click

If you want to do it properly - you will have to change JList UI implementation since the selection behavior is coming from there. That is a quite hard thing to do if you haven't ever worked with it.

Also, generally it is hard to do something like what you asked because JList component does not allow you to interact with the components provided in ListCellRenderer implementation directly - it simply uses them to "stamp" their graphical representation multiple times with different settings. That makes JList perform extremely well on large amounts of data, but locks you out of direct interaction with the renderer components.

But there is a workaround you could use for simple cases like yours - you can add a custom MouseListener to your list and "guess" where the user clicks. Luckily JList API provides you will all the methods necessary to do that:

templatesList.addMouseListener ( new MouseAdapter ()
{
@Override
public void mousePressed ( final MouseEvent e )
{
final Point point = e.getPoint ();
final int index = templatesList.locationToIndex ( point );
if ( index != -1 )
{
// Next calculations assume that text is aligned to left, but are easy to adjust
final SimpleTemplate element = templatesList.getModel ().getElementAt ( index );
final Rectangle cellBounds = templatesList.getCellBounds ( index, index );
final JListRepositoryItem renderer = ( JListRepositoryItem ) templatesList.getCellRenderer ();
final int iconWidth = renderer.getIcon () !=null ? renderer.getIcon ().getIconWidth () : 16;
final Insets insets = renderer.getInsets ();
final int iconX = cellBounds.x + insets.left;

// Ensure that mouse press happened within top/bottom insets
if ( cellBounds.y + insets.top <= point.y && point.y <= cellBounds.y + cellBounds.height - insets.bottom )
{
// Check whether we hit the checkbox icon
if ( iconX <= point.x && point.x <= cellBounds.x + insets.left + iconWidth )
{
// We hit the checkbox icon
element.installed = !element.installed;
templatesList.repaint ( cellBounds );
}
else
{
// Check whether we hit text
final int iconTextGap = renderer.getIconTextGap ();
final int textX = cellBounds.x + insets.left + iconWidth + iconTextGap;
final FontMetrics fontMetrics = renderer.getFontMetrics ( renderer.getFont () );
final int textWidth = fontMetrics.stringWidth ( element.getName () );
if ( textX <= point.x && point.x <= textX + textWidth )
{
// We hit the text
templateName.setText ( element.getName () );
templateDescription.setText ( element.getDescription () );
}
else
{
// Reset values
templateName.setText ( "---" );
templateDescription.setText ( "---" );
}
}
}
else
{
// Reset values
templateName.setText ( "---" );
templateDescription.setText ( "---" );
}
}
else
{
// Reset values
templateName.setText ( "---" );
templateDescription.setText ( "---" );
}
}
} );

I've added text size calculation for demonstration purpose, but you can simplify the whole thing if you don't need that.

Here is a breakdown of any basic component like label, button or checkbox:

Component contents breakdown

This should make it easier to visualize and should help you understand which area you want to make "clickable" as this isn't really always a simple thing to decide. For instance my example is pretty precise - you can click only exactly on the check icon or the text, but on practice that will be terrible experience and you probably would want to expand it up to insets/leftover areas.

You'll also need to remove your ListSelectionListener as it will be conflicting with the MouseListener. Here is the full code:

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class CustomJListExample extends JFrame
{

private static final Dimension SIDE_PANEL_DIMENSION = new Dimension ( 190, 190 );
private static final Dimension CONTAINER_PANEL_DIMENSION = new Dimension ( 400, 200 );
private static final Dimension TEMPLATES_LIST_DIMENSION = new Dimension ( 180, 180 );
private static final Border SIMPLE_BORDER = new JTextField ().getBorder ();

private JList<SimpleTemplate> templatesList = new JList<> ();
private JLabel templateName = new JLabel ();
private JLabel templateDescription = new JLabel ();

public CustomJListExample ()
{
JPanel rightPanel = prepareRightSide ();
JPanel leftPanel = prepareLeftSide ();

JPanel containerPanel = new JPanel ();
containerPanel.setPreferredSize ( CONTAINER_PANEL_DIMENSION );

containerPanel.add ( leftPanel );
containerPanel.add ( rightPanel );
add ( containerPanel );
pack ();
}

private JPanel prepareRightSide ()
{
JPanel rightPanel = new JPanel ();
rightPanel.setBorder ( SIMPLE_BORDER );
rightPanel.setBackground ( Color.GRAY );
rightPanel.setPreferredSize ( SIDE_PANEL_DIMENSION );

templateName.setText ( "---" );
templateDescription.setText ( "---" );

rightPanel.add ( templateName );
rightPanel.add ( templateDescription );

return rightPanel;
}

private JPanel prepareLeftSide ()
{
JPanel leftPanel = new JPanel ();
leftPanel.setBorder ( SIMPLE_BORDER );
leftPanel.setBackground ( Color.GRAY );
leftPanel.setPreferredSize ( SIDE_PANEL_DIMENSION );

DefaultListModel<SimpleTemplate> templatesListModel = new DefaultListModel<> ();
templatesListModel.addElement ( new SimpleTemplate ( "Template 1", "Description template 1", false ) );
templatesListModel.addElement ( new SimpleTemplate ( "Template 2", "Description template 2", true ) );
templatesListModel.addElement ( new SimpleTemplate ( "Template 3", "Description template 3", false ) );

templatesList.setCellRenderer ( new JListRepositoryItem () );
templatesList.setPreferredSize ( TEMPLATES_LIST_DIMENSION );
templatesList.setModel ( templatesListModel );
templatesList.repaint ();

templatesList.addMouseListener ( new MouseAdapter ()
{
@Override
public void mousePressed ( final MouseEvent e )
{
final Point point = e.getPoint ();
final int index = templatesList.locationToIndex ( point );
if ( index != -1 )
{
// Next calculations assume that text is aligned to left, but are easy to adjust
final SimpleTemplate element = templatesList.getModel ().getElementAt ( index );
final Rectangle cellBounds = templatesList.getCellBounds ( index, index );
final JListRepositoryItem renderer = ( JListRepositoryItem ) templatesList.getCellRenderer ();
final int iconWidth = renderer.getIcon () !=null ? renderer.getIcon ().getIconWidth () : 16;
final Insets insets = renderer.getInsets ();
final int iconX = cellBounds.x + insets.left;

// Ensure that mouse press happened within top/bottom insets
if ( cellBounds.y + insets.top <= point.y && point.y <= cellBounds.y + cellBounds.height - insets.bottom )
{
// Check whether we hit the checkbox icon
if ( iconX <= point.x && point.x <= cellBounds.x + insets.left + iconWidth )
{
// We hit the checkbox icon
element.installed = !element.installed;
templatesList.repaint ( cellBounds );
}
else
{
// Check whether we hit text
final int iconTextGap = renderer.getIconTextGap ();
final int textX = cellBounds.x + insets.left + iconWidth + iconTextGap;
final FontMetrics fontMetrics = renderer.getFontMetrics ( renderer.getFont () );
final int textWidth = fontMetrics.stringWidth ( element.getName () );
if ( textX <= point.x && point.x <= textX + textWidth )
{
// We hit the text
templateName.setText ( element.getName () );
templateDescription.setText ( element.getDescription () );
}
else
{
// Reset values
templateName.setText ( "---" );
templateDescription.setText ( "---" );
}
}
}
else
{
// Reset values
templateName.setText ( "---" );
templateDescription.setText ( "---" );
}
}
else
{
// Reset values
templateName.setText ( "---" );
templateDescription.setText ( "---" );
}
}
} );

leftPanel.add ( templatesList );

return leftPanel;
}

class JListRepositoryItem extends JCheckBox implements ListCellRenderer<SimpleTemplate>
{
@Override
public Component getListCellRendererComponent ( JList list, SimpleTemplate value, int index,
boolean isSelected, boolean cellHasFocus )
{
setComponentOrientation ( list.getComponentOrientation () );
setFont ( list.getFont () );
setBackground ( list.getBackground () );
setForeground ( list.getForeground () );

setSelected ( value.isInstalled () );
setEnabled ( list.isEnabled () );
setText ( value.getName () );

return this;
}
}

class SimpleTemplate
{
private String name;
private String description;
private boolean installed;

public SimpleTemplate ( String name, String description, boolean installed )
{
this.name = name;
this.description = description;
this.installed = installed;
}

public String getName ()
{
return name;
}

public String getDescription ()
{
return description;
}

public boolean isInstalled ()
{
return installed;
}
}

public static void main ( String[] args )
{
SwingUtilities.invokeLater ( () -> new CustomJListExample ().setVisible ( true ) );
}
}

Although I do want to emphasize again that this is a "hack" that works outside of the JList internal logic, so you cannot rely on the JList selection as it will be changed by the internal lsiteners from the JList UI. But it doesn't seem that you really need the JList selection in the first place, so this might work just fine for you.

In case you would be willing to adjust JList UI - you will need to perform similar calculations, but also provide a custom ListUI implementation which may be hard if you are using native OS Look and Feel.

How to add checkboxes in list in java

This is the full exception message:

IllegalArgumentException: invalid verticalScrollBarPolicy

caused when JScrollPane is instantiated. The JScrollPane policies are the wrong way around:

JScrollPane sp = new JScrollPane(l,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);


Related Topics



Leave a reply



Submit