Google Tag Manager

Showing posts with label JCheckBox. Show all posts
Showing posts with label JCheckBox. Show all posts

2024/09/30

Set the maximum number of items that can be selected in a group in JCheckBox

Code

class GroupCheckBox extends JCheckBox {
  protected GroupCheckBox(String title) {
    super(title);
  }

  @Override public void updateUI() {
    super.updateUI();
    setModel(new ToggleButtonModel() {
      private static final int GROUP_SIZE = 3;

      @Override public void setSelected(boolean selected) {
        if (selected) {
          if (getSelectedObjects().length == GROUP_SIZE) {
            UIManager.getLookAndFeel()
                .provideErrorFeedback(GroupCheckBox.this);
          } else {
            super.setSelected(true);
          }
        } else {
          super.setSelected(false);
        }
      }

      @Override public Object[] getSelectedObjects() {
        Container parent = getParent();
        return Arrays.stream(parent.getComponents())
            .filter(AbstractButton.class::isInstance)
            .map(AbstractButton.class::cast)
            .filter(AbstractButton::isSelected)
            .toArray();
      }
    });
  }
}

References

2023/07/31

Add item check boxes to JList cells

Code

@Override public void setSelectionInterval(int anchor, int lead) {
  if (checkedIndex < 0 && isDragging()) {
    super.setSelectionInterval(anchor, lead);
  } else {
    EventQueue.invokeLater(() -> {
      if (checkedIndex >= 0 && lead == anchor && checkedIndex == anchor) {
        super.addSelectionInterval(checkedIndex, checkedIndex);
      } else {
        super.setSelectionInterval(anchor, lead);
      }
    });
  }
}

protected boolean isDragging() {
  Rectangle r = getRubberBand().getBounds();
  return r.width != 0 || r.height != 0;
}

@Override public void removeSelectionInterval(int index0, int index1) {
  if (checkedIndex < 0) {
    super.removeSelectionInterval(index0, index1);
  } else {
    EventQueue.invokeLater(() -> super.removeSelectionInterval(index0, index1));
  }
}

private static <E> Optional<AbstractButton> getItemCheckBox(
    JList<E> list, MouseEvent e, int index) {
  if (e.isShiftDown() || e.isControlDown() || e.isAltDown()) {
    return Optional.empty();
  }
  E proto = list.getPrototypeCellValue();
  ListCellRenderer<? super E> cr = list.getCellRenderer();
  Component c = cr.getListCellRendererComponent(
      list, proto, index, false, false);
  Rectangle r = list.getCellBounds(index, index);
  c.setBounds(r);
  Point pt = e.getPoint();
  pt.translate(-r.x, -r.y);
  return Optional
    .ofNullable(SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y))
    .filter(AbstractButton.class::isInstance)
    .map(AbstractButton.class::cast);
}

private final class ItemCheckBoxesListener extends MouseAdapter {
  private final Point srcPoint = new Point();

  @Override public void mouseDragged(MouseEvent e) {
    checkedIndex = -1;
    JList<?> l = (JList<?>) e.getComponent();
    l.setFocusable(true);
    Point destPoint = e.getPoint();
    Path2D rb = getRubberBand();
    rb.reset();
    rb.moveTo(srcPoint.x, srcPoint.y);
    rb.lineTo(destPoint.x, srcPoint.y);
    rb.lineTo(destPoint.x, destPoint.y);
    rb.lineTo(srcPoint.x, destPoint.y);
    rb.closePath();

    int[] indices = IntStream.range(0, l.getModel().getSize())
            .filter(i -> rb.intersects(l.getCellBounds(i, i))).toArray();
    l.setSelectedIndices(indices);
    l.repaint();
  }

  @Override public void mouseExited(MouseEvent e) {
    rollOverIndex = -1;
    e.getComponent().repaint();
  }

  @Override public void mouseMoved(MouseEvent e) {
    Point pt = e.getPoint();
    int idx = locationToIndex(pt);
    if (!getCellBounds(idx, idx).contains(pt)) {
      idx = -1;
    }
    Rectangle rect = new Rectangle();
    if (idx > 0) {
      rect.add(getCellBounds(idx, idx));
      if (rollOverIndex >= 0 && idx != rollOverIndex) {
        rect.add(getCellBounds(rollOverIndex, rollOverIndex));
      }
      rollOverIndex = idx;
    } else {
      if (rollOverIndex >= 0) {
        rect.add(getCellBounds(rollOverIndex, rollOverIndex));
      }
      rollOverIndex = -1;
    }
    ((JComponent) e.getComponent()).repaint(rect);
  }

  @Override public void mouseReleased(MouseEvent e) {
    getRubberBand().reset();
    Component c = e.getComponent();
    c.setFocusable(true);
    c.repaint();
  }

  @Override public void mousePressed(MouseEvent e) {
    JList<?> l = (JList<?>) e.getComponent();
    int index = l.locationToIndex(e.getPoint());
    if (l.getCellBounds(index, index).contains(e.getPoint())) {
      l.setFocusable(true);
      cellPressed(l, e, index);
    } else {
      l.setFocusable(false);
      l.clearSelection();
      l.getSelectionModel().setAnchorSelectionIndex(-1);
      l.getSelectionModel().setLeadSelectionIndex(-1);
    }
    srcPoint.setLocation(e.getPoint());
    l.repaint();
  }

  private void cellPressed(JList<?> l, MouseEvent e, int index) {
    if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() > 1) {
      ListItem item = getModel().getElementAt(index);
      JOptionPane.showMessageDialog(l.getRootPane(), item.title);
    } else {
      checkedIndex = -1;
      getItemCheckBox(l, e.getPoint(), index).ifPresent(rb -> {
        checkedIndex = index;
        if (l.isSelectedIndex(index)) {
          l.setFocusable(false);
          removeSelectionInterval(index, index);
        } else {
          setSelectionInterval(index, index);
        }
      });
    }
  }
}

References

2023/07/01

Click on the JCheckBox placed in the JTable cell to expand and collapss the row height

Code

int defaultHeight = 20;
JTable table = new JTable(model) {
  @Override public void updateUI() {
    super.updateUI();
    setAutoCreateRowSorter(true);
    setSurrendersFocusOnKeystroke(true);
    setRowHeight(defaultHeight);
    setDefaultRenderer(RowHeader.class, new RowHeaderRenderer());
    setDefaultEditor(RowHeader.class, new RowHeaderEditor());
    TableColumn column = getColumnModel().getColumn(1);
    column.setCellRenderer(new TextAreaCellRenderer());
    column.setPreferredWidth(160);
  }
};
table.getModel().addTableModelListener(e -> {
  int mc = e.getColumn();
  int mr = e.getFirstRow();
  int vc = table.convertColumnIndexToView(mc);
  int vr = table.convertRowIndexToView(mr);
  Object o = table.getValueAt(vr, vc);
  if (mc == 0 && o instanceof RowHeader) {
    RowHeader rh = (RowHeader) o;
    int vc1 = table.convertColumnIndexToView(1);
    TableCellRenderer r = table.getColumnModel().getColumn(vc1)
                               .getCellRenderer();
    Object v = table.getValueAt(vr, vc1);
    Component c = r.getTableCellRendererComponent(
        table, v, true, true, vr, vc1);
    int h = rh.isSelected() ? c.getPreferredSize().height
                            : defaultHeight;
    table.setRowHeight(vr, h);
  }
});

References

2021/07/31

Scale the check icon of JCheckBox

Code

class ScaledIcon implements Icon {
  private final Icon icon;
  private final int width;
  private final int height;

  protected ScaledIcon(Icon icon, int width, int height) {
    this.icon = icon;
    this.width = width;
    this.height = height;
  }

  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.translate(x, y);
    double sx = width / (double) icon.getIconWidth();
    double sy = height / (double) icon.getIconHeight();
    g2.scale(sx, sy);
    icon.paintIcon(c, g2, 0, 0);
    g2.dispose();
  }

  @Override public int getIconWidth() {
    return width;
  }

  @Override public int getIconHeight() {
    return height;
  }
}

class CheckBoxIcon implements Icon {
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    if (!(c instanceof AbstractButton)) {
      return;
    }
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.translate(x, y);
    g2.setPaint(Color.DARK_GRAY);
    float s = Math.min(getIconWidth(), getIconHeight()) * .05f;
    float w = getIconWidth() - s - s;
    float h = getIconHeight() - s - s;
    float gw = w / 8f;
    float gh = h / 8f;
    g2.setStroke(new BasicStroke(s));
    g2.draw(new Rectangle2D.Float(s, s, w, h));
    AbstractButton b = (AbstractButton) c;
    if (b.getModel().isSelected()) {
      g2.setStroke(new BasicStroke(3f * s));
      Path2D p = new Path2D.Float();
      p.moveTo(x + 2f * gw, y + .5f * h);
      p.lineTo(x + .4f * w, y + h - 2f * gh);
      p.lineTo(x + w - 2f * gw, y + 2f * gh);
      g2.draw(p);
    }
    g2.dispose();
  }

  @Override public int getIconWidth() {
    return 1000;
  }

  @Override public int getIconHeight() {
    return 1000;
  }
}

//...
JTable table = new JTable(model) {
  private final Insets iconIns = new Insets(4, 4, 4, 4);
  private final transient Icon checkIcon = new CheckBoxIcon();

  @Override public Component prepareRenderer(
        TableCellRenderer renderer, int row, int column) {
    Component c = super.prepareRenderer(renderer, row, column);
    if (c instanceof JCheckBox) {
      int s = getRowHeight(row) - iconIns.top - iconIns.bottom;
      JCheckBox cb = (JCheckBox) c;
      cb.setIcon(new ScaledIcon(checkIcon, s, s));
      cb.setBorderPainted(false);
    }
    return c;
  }

  @Override public Component prepareEditor(
        TableCellEditor editor, int row, int column) {
    Component c = super.prepareEditor(editor, row, column);
    if (c instanceof JCheckBox) {
      int s = getRowHeight(row) - iconIns.top - iconIns.bottom;
      JCheckBox cb = (JCheckBox) c;
      cb.setIcon(new ScaledIcon(checkIcon, s, s));
      cb.setBackground(getSelectionBackground());
    }
    return c;
  }
};
table.setRowHeight(40);
table.setSelectionBackground(Color.WHITE);

References

2018/11/29

Add editable JCheckBox to ComboBoxEditor of JComboBox

Code

class CheckComboBoxEditor implements ComboBoxEditor {
  private final EditorPanel editor = new EditorPanel(new ComboItem());
  @Override public void selectAll() {
    editor.selectAll();
  }

  @Override public Object getItem() {
    return editor.getItem();
  }

  @Override public void setItem(Object anObject) {
    EventQueue.invokeLater(() -> {
      Container c = SwingUtilities.getAncestorOfClass(
          JComboBox.class, getEditorComponent());
      if (c instanceof JComboBox) {
        JComboBox<?> combo = (JComboBox<?>) c;
        int idx = combo.getSelectedIndex();
        if (idx >= 0 && idx != editor.getEditingIndex()) {
          System.out.println("setItem: " + idx);
          editor.setEditingIndex(idx);
        }
      }
    });
    if (anObject instanceof ComboItem) {
      editor.setItem((ComboItem) anObject);
    } else {
      editor.setItem(new ComboItem());
    }
  }

  @Override public Component getEditorComponent() {
    return editor;
  }

  @Override public void addActionListener(ActionListener l) {
    editor.addActionListener(l);
  }

  @Override public void removeActionListener(ActionListener l) {
    editor.removeActionListener(l);
  }
}

final class EditorPanel extends JPanel {
  private final JCheckBox enabledCheck = new JCheckBox();
  private final JCheckBox editableCheck = new JCheckBox();
  private final JTextField textField = new JTextField("", 16);
  private final transient ComboItem data;
  private int editingIndex = -1;

  protected EditorPanel(ComboItem data) {
    super();
    this.data = data;
    setItem(data);

    enabledCheck.addActionListener(e -> {
      Container c = SwingUtilities.getAncestorOfClass(JComboBox.class, this);
      if (c instanceof JComboBox) {
        JComboBox<?> combo = (JComboBox<?>) c;
        ComboItem item = (ComboItem) combo.getItemAt(editingIndex);
        item.setEnabled(((JCheckBox) e.getSource()).isSelected());
        editableCheck.setEnabled(item.isEnabled());
        textField.setEnabled(item.isEnabled());
        combo.setSelectedIndex(editingIndex);
      }
    });
    enabledCheck.setOpaque(false);
    enabledCheck.setFocusable(false);

    editableCheck.addActionListener(e -> {
      Container c = SwingUtilities.getAncestorOfClass(JComboBox.class, this);
      if (c instanceof JComboBox) {
        JComboBox<?> combo = (JComboBox<?>) c;
        ComboItem item = (ComboItem) combo.getItemAt(editingIndex);
        item.setEditable(((JCheckBox) e.getSource()).isSelected());
        textField.setEditable(item.isEditable());
        combo.setSelectedIndex(editingIndex);
      }
    });
    editableCheck.setOpaque(false);
    editableCheck.setFocusable(false);

    textField.addActionListener(e -> {
      Container c = SwingUtilities.getAncestorOfClass(JComboBox.class, this);
      if (c instanceof JComboBox) {
        JComboBox<?> combo = (JComboBox<?>) c;
        ComboItem item = (ComboItem) combo.getItemAt(editingIndex);
        item.setText(((JTextField) e.getSource()).getText());
        combo.setSelectedIndex(editingIndex);
      }
    });
    textField.setBorder(BorderFactory.createEmptyBorder());
    textField.setOpaque(false);

    setOpaque(false);
    setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));

    add(enabledCheck);
    add(editableCheck);
    add(textField);
  }

  public int getEditingIndex() {
    return editingIndex;
  }

  public void setEditingIndex(int idx) {
    this.editingIndex = idx;
  }

  public ComboItem getItem() {
    data.setEnabled(enabledCheck.isSelected());
    data.setEditable(editableCheck.isSelected());
    data.setText(textField.getText());
    return data;
  }

  public void setItem(ComboItem item) {
    enabledCheck.setSelected(item.isEnabled());

    editableCheck.setSelected(item.isEditable());
    editableCheck.setEnabled(item.isEnabled());

    textField.setText(item.getText());
    textField.setEnabled(item.isEnabled());
    textField.setEditable(item.isEditable());
  }

  public void selectAll() {
    textField.requestFocusInWindow();
    textField.selectAll();
  }

  public void addActionListener(ActionListener l) {
    textField.addActionListener(l);
    enabledCheck.addActionListener(l);
    editableCheck.addActionListener(l);
  }

  public void removeActionListener(ActionListener l) {
    textField.removeActionListener(l);
    enabledCheck.removeActionListener(l);
    editableCheck.removeActionListener(l);
  }
}

References

2016/10/25

Undo redo the selected state of the checkboxes

Code

private BigInteger status = new BigInteger("111000111", 2);
private static final int BIT_LENGTH = 50;
//...
for (int i = 0; i < BIT_LENGTH; i++) {
  BigInteger l = BigInteger.ONE.shiftLeft(i);
  JCheckBox c = new JCheckBox(Integer.toString(i + 1));
  c.addActionListener(e -> {
    JCheckBox cb = (JCheckBox) e.getSource();
    BigInteger newValue = cb.isSelected() ? status.or(l) : status.xor(l);
    undoSupport.postEdit(new StatusEdit(status, newValue));
    status = newValue;
    label.setText(print(status));
  });
  c.setSelected(!status.and(l).equals(BigInteger.ZERO));
  p.add(c);
}

References

2016/07/26

Select multiple JCheckBox in JComboBox

Code

class CheckedComboBox<E extends CheckableItem> extends JComboBox<E> {
  private boolean keepOpen;
  private transient ActionListener listener;

  protected CheckedComboBox() {
    super();
  }

  protected CheckedComboBox(ComboBoxModel<E> aModel) {
    super(aModel);
  }

  protected CheckedComboBox(E[] m) {
    super(m);
  }

  @Override public Dimension getPreferredSize() {
    return new Dimension(200, 20);
  }

  @Override public void updateUI() {
    setRenderer(null);
    removeActionListener(listener);
    super.updateUI();
    listener = e -> {
      if ((e.getModifiers() & AWTEvent.MOUSE_EVENT_MASK) != 0) {
        updateItem(getSelectedIndex());
        keepOpen = true;
      }
    };
    setRenderer(new CheckBoxCellRenderer<CheckableItem>());
    addActionListener(listener);
    getInputMap(JComponent.WHEN_FOCUSED).put(
        KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "checkbox-select");
    getActionMap().put("checkbox-select", new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        Accessible a = getAccessibleContext().getAccessibleChild(0);
        if (a instanceof BasicComboPopup) {
          BasicComboPopup pop = (BasicComboPopup) a;
          updateItem(pop.getList().getSelectedIndex());
        }
      }
    });
  }

  private void updateItem(int index) {
    if (isPopupVisible()) {
      E item = getItemAt(index);
      item.selected ^= true;
      setSelectedIndex(-1);
      setSelectedItem(item);
    }
  }

  @Override public void setPopupVisible(boolean v) {
    if (keepOpen) {
      keepOpen = false;
    } else {
      super.setPopupVisible(v);
    }
  }

  public static <E extends CheckableItem> String getCheckedItemString(
        ListModel<E> model) {
    return IntStream.range(0, model.getSize())
        .mapToObj(model::getElementAt)
        .filter(CheckableItem::isSelected)
        .map(Objects::toString)
        .sorted()
        .collect(Collectors.joining(", "));
  }
}

References

2016/05/30

Keep visible the JPopupMenu while clicking on CheckBox

Code

JMenuItem mi = new JMenuItem(" ");
mi.setLayout(new BorderLayout());
mi.add(new JCheckBox(title) {
  private transient MouseAdapter handler;

  @Override public void updateUI() {
    removeMouseListener(handler);
    removeMouseMotionListener(handler);
    super.updateUI();
    handler = new DispatchParentHandler();
    addMouseListener(handler);
    addMouseMotionListener(handler);
    setFocusable(false);
    setOpaque(false);
  }
});
popup.add(mi);

popup.add(new JCheckBoxMenuItem("keeping open #2") {
  @Override public void updateUI() {
    super.updateUI();
    setUI(new BasicCheckBoxMenuItemUI() {
      @Override protected void doClick(MenuSelectionManager msm) {
        // super.doClick(msm);
        System.out.println("MenuSelectionManager: doClick");
        menuItem.doClick(0);
      }
    });
  }
});
// https://bugs.openjdk.java.net/browse/JDK-8165234
// Provide a way to not close toggle menu items on mouse click on component level
// JDK 9
JMenuItem menuItem = new JMenuItem("JMenuItem");
menuItem.putClientProperty("CheckBoxMenuItem.doNotCloseOnMouseClick", true);

References

2015/01/29

Show/Hide PasswordField

Code

JPasswordField pf = new JPasswordField(24);
pf.setText("abcdefghijklmn");
pf.setAlignmentX(Component.RIGHT_ALIGNMENT);
AbstractDocument doc = (AbstractDocument) pf.getDocument();
doc.setDocumentFilter(new ASCIIOnlyDocumentFilter());

AbstractButton b = new JToggleButton(new AbstractAction() {
  @Override public void actionPerformed(ActionEvent e) {
    AbstractButton c = (AbstractButton) e.getSource();
    Character ec = c.isSelected() ? 0
        : (Character) UIManager.get("PasswordField.echoChar");
    pf.setEchoChar(ec);
  }
});
b.setFocusable(false);
b.setOpaque(false);
b.setContentAreaFilled(false);
b.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 4));
b.setAlignmentX(Component.RIGHT_ALIGNMENT);
b.setAlignmentY(Component.CENTER_ALIGNMENT);
b.setIcon(new ColorIcon(Color.GREEN));
b.setRolloverIcon(new ColorIcon(Color.BLUE));
b.setSelectedIcon(new ColorIcon(Color.RED));
b.setRolloverSelectedIcon(new ColorIcon(Color.ORANGE));

JPanel panel = new JPanel() {
  @Override public boolean isOptimizedDrawingEnabled() {
    return false;
  }
};
panel.setLayout(new OverlayLayout(panel));
panel.add(b);
panel.add(pf);

References

2013/10/15

Scrollable list of JCheckBoxes

Code

JList

class CheckBoxCellRenderer<E extends CheckBoxNode> extends JCheckBox
    implements ListCellRenderer<E>, MouseListener, MouseMotionListener {
  private int rollOverRowIndex = -1;

  @Override public Component getListCellRendererComponent(
        JList<? extends E> list, E value, int index,
        boolean isSelected, boolean cellHasFocus) {
    this.setOpaque(true);
    if (isSelected) {
      this.setBackground(list.getSelectionBackground());
      this.setForeground(list.getSelectionForeground());
    } else {
      this.setBackground(list.getBackground());
      this.setForeground(list.getForeground());
    }
    this.setSelected(value.selected);
    this.getModel().setRollover(index == rollOverRowIndex);
    this.setText(value.text);
    return this;
  }

  @Override public void mouseExited(MouseEvent e) {
    if (rollOverRowIndex >= 0) {
      JList<?> l = (JList<?>) e.getComponent();
      l.repaint(l.getCellBounds(rollOverRowIndex, rollOverRowIndex));
      rollOverRowIndex = -1;
    }
  }

  @Override public void mouseClicked(MouseEvent e) {
    if (e.getButton() == MouseEvent.BUTTON1) {
      JList<?> l = (JList<?>) e.getComponent();
      Point p = e.getPoint();
      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));
        l.repaint(l.getCellBounds(index, index));
      }
    }
  }

  @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 mouseEntered(MouseEvent e)  {
    /* not needed */
  }

  @Override public void mousePressed(MouseEvent e)  {
    /* not needed */
  }

  @Override public void mouseReleased(MouseEvent e) {
    /* not needed */
  }

  @Override public void mouseDragged(MouseEvent e)  {
    /* not needed */
  }
}

// ...
JList list1 = new JList(model) {
  private CheckBoxCellRenderer renderer;
  @Override public void updateUI() {
    setForeground(null);
    setBackground(null);
    setSelectionForeground(null);
    setSelectionBackground(null);
    if (renderer != null) {
      removeMouseListener(renderer);
      removeMouseMotionListener(renderer);
    }
    super.updateUI();
    renderer = new CheckBoxCellRenderer();
    setCellRenderer(renderer);
    addMouseListener(renderer);
    addMouseMotionListener(renderer);
  }

  // @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);
  }

  @Override protected void processMouseEvent(MouseEvent e) {
    if (!pointOutsidePrefSize(e.getPoint())) {
      super.processMouseEvent(e);
    }
  }

  @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);
    }
  }
};

JTree

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 instanceof DefaultMutableTreeNode) {
      this.setOpaque(false);
      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);
  }
}

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();
      }
    });
  }

  @Override public Component getTreeCellEditorComponent(
    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;
  }

  @Override public Object getCellEditorValue() {
    return new CheckBoxNode(getText(), isSelected());
  }

  @Override public boolean isCellEditable(EventObject e) {
    return (e instanceof MouseEvent);
  }

  // Copied from AbstractCellEditor
  // protected EventListenerList listenerList = new EventListenerList();
  // transient protected ChangeEvent changeEvent = null;
  @Override public boolean shouldSelectCell(EventObject anEvent) {
    // ...

References

2012/02/06

JCheckBox Node JTree

Code

class CheckBoxNodeEditor extends TriStateCheckBox implements TreeCellEditor {
  private DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
  private final JPanel panel = new JPanel(new BorderLayout());
  private String str = null;
  public CheckBoxNodeEditor() {
    super();
    this.addActionListener(new ActionListener() {
      @Override public void actionPerformed(ActionEvent e) {
        // System.out.println("actionPerformed: stopCellEditing");
        stopCellEditing();
      }
    });
    panel.setFocusable(false);
    panel.setRequestFocusEnabled(false);
    panel.setOpaque(false);
    panel.add(this, BorderLayout.WEST);
    this.setOpaque(false);
  }

  @Override public Component getTreeCellEditorComponent(
      JTree tree, Object value, boolean isSelected,
      boolean expanded, boolean leaf, int row) {
    JLabel l = (JLabel) renderer.getTreeCellRendererComponent(
      tree, value, true, expanded, leaf, row, true);
    l.setFont(tree.getFont());
    if (value instanceof DefaultMutableTreeNode) {
      this.setEnabled(tree.isEnabled());
      this.setFont(tree.getFont());
      Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
      if (userObject instanceof CheckBoxNode) {
        CheckBoxNode node = (CheckBoxNode) userObject;
        if (node.status == Status.INDETERMINATE) {
          setIcon(new IndeterminateIcon());
        } else {
          setIcon(null);
        }
        l.setText(node.label);
        setSelected(node.status == Status.SELECTED);
        str = node.label;
      }
      // panel.add(this, BorderLayout.WEST);
      panel.add(l);
      return panel;
    }
    return l;
  }

  @Override public Object getCellEditorValue() {
    return new CheckBoxNode(str, isSelected() ? Status.SELECTED : Status.DESELECTED);
  }

  @Override public boolean isCellEditable(EventObject e) {
    if (e instanceof MouseEvent && e.getSource() instanceof JTree) {
      MouseEvent me = (MouseEvent) e;
      JTree tree = (JTree) e.getSource();
      TreePath path = tree.getPathForLocation(me.getX(), me.getY());
      Rectangle r = tree.getPathBounds(path);
      if (r == null) {
        return false;
      }
      Dimension d = getPreferredSize();
      r.setSize(new Dimension(d.width, r.height));
      if (r.contains(me.getPoint())) {
        return true;
      }
    }
    return false;
  }

  @Override public void updateUI() {
    super.updateUI();
    setName("Tree.cellEditor");
    if (panel != null) {
      //panel.removeAll(); // ??? Change to Nimbus LnF, JDK 1.6.0
      panel.updateUI();
      //panel.add(this, BorderLayout.WEST);
    }
    // ???#1: JDK 1.6.0 bug??? @see 1.7.0 DefaultTreeCellRenderer#updateUI()
    // if (System.getProperty("java.version").startsWith("1.6.0")) {
    //   renderer = new DefaultTreeCellRenderer();
    // }
  }
// ...

References

2011/08/29

FileSystemTree with JCheckBox

Code

class CheckBoxNodeEditor extends TriStateCheckBox implements TreeCellEditor {
  private final FileSystemView fileSystemView;
  private final JPanel panel = new JPanel(new BorderLayout());
  private DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
  private File file;

  public CheckBoxNodeEditor(FileSystemView fileSystemView) {
    super();
    this.fileSystemView = fileSystemView;
    this.addActionListener(new ActionListener() {
      @Override public void actionPerformed(ActionEvent e) {
        stopCellEditing();
      }
    });
    panel.setFocusable(false);
    panel.setRequestFocusEnabled(false);
    panel.setOpaque(false);
    panel.add(this, BorderLayout.WEST);
    this.setOpaque(false);
  }

  @Override public Component getTreeCellEditorComponent(
      JTree tree, Object value, boolean isSelected, boolean expanded,
      boolean leaf, int row) {
    JLabel l = (JLabel) renderer.getTreeCellRendererComponent(
      tree, value, true, expanded, leaf, row, true);
    l.setFont(tree.getFont());
    setOpaque(false);
    if (value instanceof DefaultMutableTreeNode) {
      this.setEnabled(tree.isEnabled());
      this.setFont(tree.getFont());
      Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
      if (userObject instanceof CheckBoxNode) {
        CheckBoxNode node = (CheckBoxNode) userObject;
        if (node.status == Status.INDETERMINATE) {
          setIcon(new IndeterminateIcon());
        } else {
          setIcon(null);
        }
        file = node.file;
        l.setIcon(fileSystemView.getSystemIcon(file));
        l.setText(fileSystemView.getSystemDisplayName(file));
        setSelected(node.status == Status.SELECTED);
      }
      // panel.add(this, BorderLayout.WEST);
      panel.add(l);
      return panel;
    }
    return l;
  }

  @Override public Object getCellEditorValue() {
    return new CheckBoxNode(file, isSelected() ? Status.SELECTED : Status.DESELECTED);
  }

  @Override public boolean isCellEditable(EventObject e) {
    if (e instanceof MouseEvent && e.getSource() instanceof JTree) {
      MouseEvent me = (MouseEvent) e;
      JTree tree = (JTree) e.getSource();
      TreePath path = tree.getPathForLocation(me.getX(), me.getY());
      Rectangle r = tree.getPathBounds(path);
      if (r == null) {
        return false;
      }
      Dimension d = getPreferredSize();
      r.setSize(new Dimension(d.width, r.height));
      if (r.contains(me.getX(), me.getY())) {
        // if (file == null && System.getProperty("java.version").startsWith("1.7.0")) {
        //   System.out.println("XXX: Java 7, only on first run\n" + getBounds());
        //   setBounds(new Rectangle(0, 0, d.width, r.height));
        // }
        return true;
      }
    }
    return false;
  }

  @Override public void updateUI() {
    super.updateUI();
    if (panel != null) {
      panel.updateUI();
    }
    // 1.6.0_24 bug??? @see 1.7.0 DefaultTreeCellRenderer#updateUI()
    renderer = new DefaultTreeCellRenderer();
  }
// ...

References

2011/03/10

CheckBoxes in JTable Cell

Code

class CheckBoxesPanel extends JPanel {
  private static final String OSNAME = System.getProperty("os.name");
  protected final String[] title = {"r", "w", "x"};
  public JCheckBox[] buttons;
  public CheckBoxesPanel() {
    super();
    setOpaque(false);
    setBackground(new Color(0x0, true));
    setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
    initButtons();
  }

  protected void initButtons() {
    buttons = new JCheckBox[title.length];
    for (int i = 0; i < buttons.length; i++) {
      JCheckBox b = new JCheckBox(title[i]);
      b.setOpaque(false);
      b.setFocusable(false);
      b.setRolloverEnabled(false);
      b.setBackground(new Color(0x0, true));
      buttons[i] = b;
      add(b);
      add(Box.createHorizontalStrut(5));
    }
  }

  protected void updateButtons(Object v) {
    if ("Windows 7".equals(OSNAME)) { //Windows aero?
      removeAll();
      initButtons();
    }
    Integer i = (Integer) (v == null ? 0 : v);
    buttons[0].setSelected((i & (1 << 2)) != 0);
    buttons[1].setSelected((i & (1 << 1)) != 0);
    buttons[2].setSelected((i & (1 << 0)) != 0);
  }
}

class CheckBoxesRenderer extends CheckBoxesPanel
                         implements TableCellRenderer, Serializable {
  public CheckBoxesRenderer() {
    super();
    setName("Table.cellRenderer");
  }

  @Override public Component getTableCellRendererComponent(JTable table,
      Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    updateButtons(value);
    return this;
  }

  public static class UIResource extends CheckBoxesRenderer implements UIResource {}
}

class CheckBoxesEditor extends CheckBoxesPanel
                       implements TableCellEditor, Serializable {
  public CheckBoxesEditor() {
    ActionListener al = new ActionListener() {
      @Override public void actionPerformed(ActionEvent e) {
        fireEditingStopped();
      }
    };
    ActionMap am = getActionMap();
    for (int i = 0; i < buttons.length; i++) {
      final JCheckBox b = buttons[i];
      b.addActionListener(al);
      am.put(title[i], new AbstractAction(title[i]) {
        @Override public void actionPerformed(ActionEvent e) {
          b.setSelected(!b.isSelected());
          fireEditingStopped();
        }
      });
    }
    InputMap im = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0), title[0]);
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), title[1]);
    im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, 0), title[2]);
  }

  @Override public Component getTableCellEditorComponent(JTable table,
        Object value, boolean isSelected, int row, int column) {
    updateButtons(value);
    return this;
  }

  @Override public Object getCellEditorValue() {
    int i = 0;
    if (buttons[0].isSelected()) i |= 1 << 2;
    if (buttons[1].isSelected()) i |= 1 << 1;
    if (buttons[2].isSelected()) i |= 1 << 0;
    return i;
  }

  // Copied from AbstractCellEditor
  protected EventListenerList listenerList = new EventListenerList();
  transient protected ChangeEvent changeEvent = null;
  // ...

References

2010/08/02

Transparent, Translucent JTable

Code

JScrollPane scroll = new JScrollPane(table) {
  private final TexturePaint texture = makeImageTexture();
  @Override protected JViewport createViewport() {
    return new JViewport() {
      @Override protected void paintComponent(Graphics g) {
        if (texture != null) {
          Graphics2D g2 = (Graphics2D) g;
          g2.setPaint(texture);
          g2.fillRect(0, 0, getWidth(), getHeight());
        }
        super.paintComponent(g);
      }
    };
  }
};
Color alphaZero = new Color(0x0, true);
table.setOpaque(false);
table.setBackground(alphaZero);
scroll.getViewport().setOpaque(false);
scroll.getViewport().setBackground(alphaZero);

References

2010/07/20

create a JCheckBox rollover effect in a JTable

Code

class RolloverBooleanRenderer extends JCheckBox implements TableCellRenderer, UIResource {
  private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
  private final HighlightListener highlighter;

  public RolloverBooleanRenderer(HighlightListener highlighter) {
    super();
    this.highlighter = highlighter;
    setHorizontalAlignment(SwingConstants.CENTER);
    setBorderPainted(true);
    setRolloverEnabled(true);
    setOpaque(true);
  }

  @Override public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {
    if (highlighter.isHighlightableCell(row, column)) {
      getModel().setRollover(true);
    } else {
      getModel().setRollover(false);
    }
    if (isSelected) {
      setForeground(table.getSelectionForeground());
      super.setBackground(table.getSelectionBackground());
    } else {
      setForeground(table.getForeground());
      setBackground(table.getBackground());
    }
    setSelected((value != null && ((Boolean) value).booleanValue()));
    if (hasFocus) {
      setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
    } else {
      setBorder(noFocusBorder);
    }
    return this;
  }
}

References

2009/02/16

JTableHeader CheckBox

Code

enum Status { SELECTED, DESELECTED, INDETERMINATE }

class HeaderRenderer extends JCheckBox implements TableCellRenderer {
  private final JLabel label = new JLabel("Check All");
  private final int targetColumnIndex;

  public HeaderRenderer(JTableHeader header, int index) {
    super((String) null);
    this.targetColumnIndex = index;
    setOpaque(false);
    setFont(header.getFont());
    header.addMouseListener(new MouseAdapter() {
      @Override public void mouseClicked(MouseEvent e) {
        JTableHeader header = (JTableHeader) e.getComponent();
        JTable table = header.getTable();
        TableColumnModel columnModel = table.getColumnModel();
        int vci = columnModel.getColumnIndexAtX(e.getX());
        int mci = table.convertColumnIndexToModel(vci);
        if (mci == targetColumnIndex) {
          TableColumn column = columnModel.getColumn(vci);
          boolean b = column.getHeaderValue() == Status.DESELECTED;
          TableModel m = table.getModel();
          for (int i = 0; i < m.getRowCount(); i++) {
            m.setValueAt(b, i, mci);
          }
          column.setHeaderValue(b ? Status.SELECTED : Status.DESELECTED);
          // header.repaint();
        }
      }
    });
  }

  @Override public Component getTableCellRendererComponent(
        JTable tbl, Object val, boolean isS, boolean hasF, int row, int col) {
    TableCellRenderer r = tbl.getTableHeader().getDefaultRenderer();
    JLabel l = (JLabel) r.getTableCellRendererComponent(tbl, val, isS, hasF, row, col);
    if (targetColumnIndex == tbl.convertColumnIndexToModel(col)) {
      if (val instanceof Status) {
        switch ((Status) val) {
        case SELECTED:
          setSelected(true);
          setEnabled(true);
          break;
        case DESELECTED:
          setSelected(false);
          setEnabled(true);
          break;
        case INDETERMINATE:
          setSelected(true);
          setEnabled(false);
          break;
        default:
          throw new AssertionError("Unknown Status");
        }
      } else {
        setSelected(true);
        setEnabled(false);
      }
      label.setIcon(new ComponentIcon(this));
      l.setIcon(new ComponentIcon(label));
      l.setText(null);
    }
    return l;
  }
}

class ComponentIcon implements Icon {
  private final JComponent cmp;

  public ComponentIcon(JComponent cmp) {
    this.cmp = cmp;
  }

  @Override public int getIconWidth() {
    return cmp.getPreferredSize().width;
  }

  @Override public int getIconHeight() {
    return cmp.getPreferredSize().height;
  }

  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    SwingUtilities.paintComponent(
        g, cmp, c.getParent(), x, y, getIconWidth(), getIconHeight());
  }
}

References