Swing/CheckBoxCellList のバックアップの現在との差分(No.2)
TITLE:JListのセルにJCheckBoxを使用する
Posted by aterai at 2011-03-28
JListのセルにJCheckBoxを使用する
JListのセルにJCheckBoxを使用して、チェックボックスの一覧を作成します。-
category: swing
folder: CheckBoxCellList
title: JListのセルにJCheckBoxを使用する
tags: [JList, JCheckBox, ListCellRenderer, MouseListener, JTree, Box]
author: aterai
pubdate: 2011-03-28T15:00:17+09:00
description: JListのセルにJCheckBoxを使用して、チェックボックスの一覧を作成します。
image:
hreflang:
href: https://java-swing-tips.blogspot.com/2013/10/scrollable-list-of-jcheckboxes.html lang: en
概要
JList
のセルにJCheckBox
を使用して、チェックボックスの一覧を作成します。
- &jnlp;
- &jar;
- &zip;
Screenshot
Advertisement
サンプルコード
サンプルコード
#spandel
class CheckBoxCellRenderer extends JCheckBox
#spanend
implements ListCellRenderer, MouseListener, MouseMotionListener {
#spanadd
class CheckBoxCellRenderer<E extends CheckBoxNode> extends JCheckBox
#spanend
implements ListCellRenderer<E>, MouseListener, MouseMotionListener {
private int rollOverRowIndex = -1;
#spanadd
#spanend
@Override public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
JList<? extends E> list, E value, int index,
boolean isSelected, boolean cellHasFocus) {
this.setOpaque(true);
if(isSelected) {
if (isSelected) {
this.setBackground(list.getSelectionBackground());
this.setForeground(list.getSelectionForeground());
}else{
} else {
this.setBackground(list.getBackground());
this.setForeground(list.getForeground());
}
if(value instanceof CheckBoxNode) {
this.setSelected(((CheckBoxNode)value).selected);
if(index==pressedRowIndex) {
this.getModel().setArmed(true);
this.getModel().setPressed(true);
}else{
this.getModel().setRollover(index==rollOverRowIndex);
this.getModel().setArmed(false);
this.getModel().setPressed(false);
}
}
this.setText(value.toString());
this.setSelected(value.selected);
this.getModel().setRollover(index == rollOverRowIndex);
this.setText(value.text);
return this;
}
private int rollOverRowIndex = -1;
private int pressedRowIndex = -3;
#spanadd
#spanend
@Override public void mouseExited(MouseEvent e) {
rollOverRowIndex = -1;
JList c = (JList)e.getSource();
c.repaint();
if (rollOverRowIndex >= 0) {
JList<?> l = (JList<?>) e.getComponent();
l.repaint(l.getCellBounds(rollOverRowIndex, rollOverRowIndex));
rollOverRowIndex = -1;
}
}
#spanadd
#spanend
@Override public void mouseClicked(MouseEvent e) {
if(e.getButton()==MouseEvent.BUTTON1) {
JList t = (JList)e.getComponent();
DefaultListModel m = (DefaultListModel)t.getModel();
if (e.getButton() == MouseEvent.BUTTON1) {
JList<?> l = (JList<?>) e.getComponent();
Point p = e.getPoint();
int index = t.locationToIndex(p);
CheckBoxNode n = (CheckBoxNode)m.get(index);
Component c = t.getCellRenderer().getListCellRendererComponent(
t, n, index, false, false);
Dimension d = c.getPreferredSize();
if(d.width>=p.x) {
int index = l.locationToIndex(p);
if (index >= 0) {
@SuppressWarnings("unchecked")
DefaultListModel<CheckBoxNode> m =
(DefaultListModel<CheckBoxNode>) l.getModel();
CheckBoxNode n = m.get(index);
m.set(index, new CheckBoxNode(n.text, !n.selected));
t.repaint();
t.repaint(t.getCellBounds(index, index));
l.repaint(l.getCellBounds(index, index));
}
}
}
@Override public void mouseEntered(MouseEvent e) {}
private int pressStartIndex = -1;
@Override public void mousePressed(MouseEvent e) {
if(e.getButton()==MouseEvent.BUTTON1) {
JList c = (JList)e.getSource();
int row = c.locationToIndex(e.getPoint());
pressStartIndex = row;
if(row != pressedRowIndex) {
pressedRowIndex = row;
c.repaint();
}
#spanadd
#spanend
@Override public void mouseMoved(MouseEvent e) {
JList<?> l = (JList<?>) e.getComponent();
int index = l.locationToIndex(e.getPoint());
if (index != rollOverRowIndex) {
rollOverRowIndex = index;
l.repaint();
}
}
@Override public void mouseReleased(MouseEvent e) {
pressedRowIndex = -1;
pressStartIndex = -1;
#spanadd
#spanend
@Override public void mouseEntered(MouseEvent e) {
/* not needed */
}
@Override public void mouseDragged(MouseEvent e) {
JList c = (JList)e.getSource();
int row = c.locationToIndex(e.getPoint());
if(row != rollOverRowIndex) {
rollOverRowIndex = -1;
}
if(row != pressedRowIndex) {
pressedRowIndex = -1;
}
if(row == pressStartIndex) {
pressedRowIndex = row;
}
c.repaint();
#spanadd
#spanend
@Override public void mousePressed(MouseEvent e) {
/* not needed */
}
@Override public void mouseMoved(MouseEvent e) {
JList c = (JList)e.getSource();
int row = c.locationToIndex(e.getPoint());
if(row != rollOverRowIndex) {
rollOverRowIndex = row;
c.repaint();
}
#spanadd
#spanend
@Override public void mouseReleased(MouseEvent e) {
/* not needed */
}
#spanadd
#spanend
@Override public void mouseDragged(MouseEvent e) {
/* not needed */
}
}
View in GitHub: Java, Kotlin解説
- 左: "JCheckBox Cell in JList"
- JCheckBoxを継承するListCellRendererを設定
- チェックボックスのロールオーバーなどは、JListにマウスリスナーを設定して表示
- JList#putClientProperty("List.isFileList", Boolean.TRUE);で、クリックが有効になる領域をチェックボックスの幅に制限
- 右: "JCheckBox in Box"
- Box.createVerticalBox()にJCheckBoxを追加
- JCheckBox#setAlignmentX(Component.LEFT_ALIGNMENT);で左揃えに設定
解説
-
Box
-
Box.createVerticalBox()
にJCheckBox
を追加 -
JCheckBox#setAlignmentX(Component.LEFT_ALIGNMENT);
で左揃えに設定
-
- - JTreeの葉ノードをJCheckBoxにするのセルレンダラーを使ったJTreeに、JTree#setRootVisible(false)を設定しても、ほぼ同様のチェックボックスの一覧を作成することができます。
-
JList
-
JCheckBox
を継承するListCellRenderer
を設定 - チェックボックスのロールオーバーなどは、
JList
にマウスリスナーを設定して描画 -
JList#processMouseEvent
、JList#processMouseMotionEvent
のオーバーライドと、JList#putClientProperty("List.isFileList", Boolean.TRUE);
でクリックが有効になる領域をチェックボックスの幅に制限
-
#spandel
import java.awt.*;
#spanend
#spandel
import java.awt.event.*;
#spanend
#spandel
import java.util.*;
#spanend
#spandel
import javax.swing.*;
#spanend
#spandel
import javax.swing.event.*;
#spanend
#spandel
import javax.swing.tree.*;
#spanend
#spandel
#spanend
#spandel
public class TreeCheckBoxListTest {
#spanend
public JComponent makeUI() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("JTree");
for(int i=0; i<16; i++) {
root.add(new DefaultMutableTreeNode(new CheckBoxNode("No."+i, i%2==0)));
#spanadd
JList list1 = new JList(model) {
#spanend
private CheckBoxCellRenderer renderer;
@Override public void updateUI() {
setForeground(null);
setBackground(null);
setSelectionForeground(null);
setSelectionBackground(null);
if (renderer != null) {
removeMouseListener(renderer);
removeMouseMotionListener(renderer);
}
JTree tree = new JTree(new DefaultTreeModel(root));
tree.setEditable(true);
tree.setRootVisible(false);
tree.setCellRenderer(new CheckBoxNodeRenderer());
tree.setCellEditor(new CheckBoxNodeEditor(tree));
return new JScrollPane(tree);
super.updateUI();
renderer = new CheckBoxCellRenderer();
setCellRenderer(renderer);
addMouseListener(renderer);
addMouseMotionListener(renderer);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
});
#spanadd
#spanend
// @see SwingUtilities2.pointOutsidePrefSize(...)
private boolean pointOutsidePrefSize(Point p) {
int index = locationToIndex(p);
DefaultListModel m = (DefaultListModel) getModel();
CheckBoxNode n = (CheckBoxNode) m.get(index);
Component c = getCellRenderer().getListCellRendererComponent(
this, n, index, false, false);
// c.doLayout();
Dimension d = c.getPreferredSize();
Rectangle rect = getCellBounds(index, index);
rect.width = d.width;
return index < 0 || !rect.contains(p);
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new TreeCheckBoxListTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
#spanadd
#spanend
@Override protected void processMouseEvent(MouseEvent e) {
if (!pointOutsidePrefSize(e.getPoint())) {
super.processMouseEvent(e);
}
}
#spandel
}
#spanend
#spandel
class CheckBoxNode {
#spanend
public final String text;
public final boolean selected;
public CheckBoxNode(String text, boolean selected) {
this.text = text;
this.selected = selected;
#spanadd
#spanend
@Override protected void processMouseMotionEvent(MouseEvent e) {
if (!pointOutsidePrefSize(e.getPoint())) {
super.processMouseMotionEvent(e);
} else {
e = new MouseEvent(
(Component) e.getSource(), MouseEvent.MOUSE_EXITED, e.getWhen(),
e.getModifiers(), e.getX(), e.getY(),
e.getXOnScreen(), e.getYOnScreen(),
e.getClickCount(), e.isPopupTrigger(), MouseEvent.NOBUTTON);
super.processMouseEvent(e);
}
}
@Override public String toString() {
return text;
}
#spandel
}
#spanend
#spanadd
};
#spanend
#spanadd
-
JTree
-
JCheckBox
を継承するTreeCellRenderer
を設定- JTreeの葉ノードをJCheckBoxにするで作成したセルレンダラーを使用
-
JTree#setRootVisible(false)
でルートノードを非表示に設定
-
#spanend
class CheckBoxNodeRenderer extends JCheckBox implements TreeCellRenderer {
private TreeCellRenderer renderer = new DefaultTreeCellRenderer();
@Override public Component getTreeCellRendererComponent(
JTree tree, Object value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
if(leaf && value != null && value instanceof DefaultMutableTreeNode) {
JTree tree, Object value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
if (leaf && value instanceof DefaultMutableTreeNode) {
this.setOpaque(false);
Object userObject = ((DefaultMutableTreeNode)value).getUserObject();
if(userObject!=null && userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode)userObject;
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
this.setText(node.text);
this.setSelected(node.selected);
}
return this;
}
return renderer.getTreeCellRendererComponent(
tree, value, selected, expanded, leaf, row, hasFocus);
tree, value, selected, expanded, leaf, row, hasFocus);
}
}
class CheckBoxNodeEditor extends JCheckBox implements TreeCellEditor {
private final JTree tree;
public CheckBoxNodeEditor(JTree tree) {
super();
this.tree = tree;
setOpaque(false);
setFocusable(false);
addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
stopCellEditing();
}
});
}
#spanadd
#spanend
@Override public Component getTreeCellEditorComponent(
JTree tree, Object value, boolean isSelected, boolean expanded,
boolean leaf, int row) {
if(leaf && value != null && value instanceof DefaultMutableTreeNode) {
Object userObject = ((DefaultMutableTreeNode)value).getUserObject();
if(userObject!=null && userObject instanceof CheckBoxNode) {
this.setSelected(((CheckBoxNode)userObject).selected);
JTree tree, Object value, boolean isSelected, boolean expanded,
boolean leaf, int row) {
if (leaf && value instanceof DefaultMutableTreeNode) {
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
this.setSelected(((CheckBoxNode) userObject).selected);
} else {
this.setSelected(false);
}
this.setText(value.toString());
}
return this;
}
#spanadd
#spanend
@Override public Object getCellEditorValue() {
return new CheckBoxNode(getText(), isSelected());
}
#spanadd
#spanend
@Override public boolean isCellEditable(EventObject e) {
return (e != null && e instanceof MouseEvent);
return (e instanceof MouseEvent);
}
//Copid from AbstractCellEditor
//protected EventListenerList listenerList = new EventListenerList();
//transient protected ChangeEvent changeEvent = null;
@Override public boolean shouldSelectCell(java.util.EventObject anEvent) {
return true;
}
@Override public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
@Override public void cancelCellEditing() {
fireEditingCanceled();
}
@Override public void addCellEditorListener(CellEditorListener l) {
listenerList.add(CellEditorListener.class, l);
}
@Override public void removeCellEditorListener(CellEditorListener l) {
listenerList.remove(CellEditorListener.class, l);
}
public CellEditorListener[] getCellEditorListeners() {
return listenerList.getListeners(CellEditorListener.class);
}
protected void fireEditingStopped() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for(int i = listeners.length-2; i>=0; i-=2) {
if(listeners[i]==CellEditorListener.class) {
// Lazily create the event:
if(changeEvent == null) changeEvent = new ChangeEvent(this);
((CellEditorListener)listeners[i+1]).editingStopped(changeEvent);
}
}
}
protected void fireEditingCanceled() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for(int i = listeners.length-2; i>=0; i-=2) {
if(listeners[i]==CellEditorListener.class) {
// Lazily create the event:
if(changeEvent == null) changeEvent = new ChangeEvent(this);
((CellEditorListener)listeners[i+1]).editingCanceled(changeEvent);
}
}
}
#spandel
}
#spanend
#spanadd
#spanend
// Copied from AbstractCellEditor
// protected EventListenerList listenerList = new EventListenerList();
// transient protected ChangeEvent changeEvent = null;
@Override public boolean shouldSelectCell(EventObject anEvent) {
// ...