Google Tag Manager

Showing posts with label TableCellRenderer. Show all posts
Showing posts with label TableCellRenderer. Show all posts

2024/08/31

Set JButton as cell renderer for JTableHeader

Code

class ButtonHeaderRenderer extends JButton implements TableCellRenderer {
  private int pushedColumn = -1;
  private int rolloverColumn = -1;

  @Override public void updateUI() {
    super.updateUI();
    setHorizontalTextPosition(LEFT);
  }

  @Override public Component getTableCellRendererComponent(
      JTable table, Object value,
      boolean isSelected, boolean hasFocus,
      int row, int column) {
    setText(Objects.toString(value, ""));
    int modelColumn = table.convertColumnIndexToModel(column);
    JTableHeader header = table.getTableHeader();
    if (header != null) {
      // setColor(header, hasFocus);
      boolean isPressed = modelColumn == pressedColumn;
      getModel().setPressed(isPressed);
      getModel().setArmed(isPressed);
      getModel().setRollover(modelColumn == rolloverColumn);
      setFont(header.getFont());
    }

    Icon sortIcon = null;
    if (table.getRowSorter() != null) {
      List<? extends RowSorter.SortKey> sortKeys =
          table.getRowSorter().getSortKeys();
      if (!sortKeys.isEmpty() &&
          sortKeys.get(0).getColumn() == modelColumn) {
        SortOrder sortOrder = sortKeys.get(0).getSortOrder();
        switch (sortOrder) {
          case ASCENDING:
            sortIcon = UIManager.getIcon("Table.ascendingSortIcon");
            break;
          case DESCENDING:
            sortIcon = UIManager.getIcon("Table.descendingSortIcon");
            break;
          // case UNSORTED:
          //   sortIcon = UIManager.getIcon("Table.naturalSortIcon");
          //   break;
          default:
            sortIcon = UIManager.getIcon("Table.naturalSortIcon");
        }
      }
    }
    setIcon(sortIcon);
    return this;
  }

  public void setPressedColumn(int column) {
    pushedColumn = column;
  }

  public void setRolloverColumn(int column) {
    rolloverColumn = column;
  }
}

class HeaderMouseListener extends MouseAdapter {
  @Override public void mousePressed(MouseEvent e) {
    JTableHeader header = (JTableHeader) e.getComponent();
    JTable table = header.getTable();
    TableCellRenderer renderer = header.getDefaultRenderer();
    int viewColumn = table.columnAtPoint(e.getPoint());
    if (viewColumn >= 0 && renderer instanceof ButtonHeaderRenderer) {
      int column = table.convertColumnIndexToModel(viewColumn);
      ((ButtonHeaderRenderer) renderer).setPressedColumn(column);
    }
  }

  @Override public void mouseReleased(MouseEvent e) {
    JTableHeader header = (JTableHeader) e.getComponent();
    TableCellRenderer renderer = header.getDefaultRenderer();
    if (renderer instanceof ButtonHeaderRenderer) {
      ((ButtonHeaderRenderer) renderer).setPressedColumn(-1);
    }
  }

  @Override public void mouseMoved(MouseEvent e) {
    JTableHeader header = (JTableHeader) e.getComponent();
    JTable table = header.getTable();
    TableCellRenderer renderer = header.getDefaultRenderer();
    int viewColumn = table.columnAtPoint(e.getPoint());
    if (viewColumn >= 0 && renderer instanceof ButtonHeaderRenderer) {
      int column = table.convertColumnIndexToModel(viewColumn);
      ((ButtonHeaderRenderer) renderer).setRolloverColumn(column);
    }
  }

  @Override public void mouseExited(MouseEvent e) {
    JTableHeader header = (JTableHeader) e.getComponent();
    TableCellRenderer renderer = header.getDefaultRenderer();
    if (renderer instanceof ButtonHeaderRenderer) {
      ((ButtonHeaderRenderer) renderer).setRolloverColumn(-1);
    }
  }
}

References

2024/01/31

Paint a JProgressBar with indeterminate progress status in a cell of a JTable

Code

private final JTable table = new JTable(model) {
  @Override public void updateUI() {
    super.updateUI();
    removeColumn(getColumnModel().getColumn(3));
    JProgressBar progress = new JProgressBar();
    TableCellRenderer renderer = new DefaultTableCellRenderer();
    TableColumn tc = getColumnModel().getColumn(2);
    tc.setCellRenderer((tbl, value, isSelected, hasFocus, row, column) -> {
      Component c;
      if (value instanceof JProgressBar) {
        c = (JProgressBar) value;
      } else if (value instanceof Integer) {
        progress.setValue((int) value);
        c = progress;
      } else {
        c = renderer.getTableCellRendererComponent(
            tbl, Objects.toString(value), isSelected, hasFocus, row, column);
      }
      return c;
    });
  }
};

class IndeterminateProgressBarUI extends BasicProgressBarUI {
  @Override public void incrementAnimationIndex() {
    super.incrementAnimationIndex();
  }
}

class BackgroundTask extends SwingWorker<Integer, Object> {
  private final Random rnd = new Random();

  @Override protected Integer doInBackground() throws InterruptedException {
    int lengthOfTask = calculateTaskSize();
    int current = 0;
    int total = 0;
    while (current <= lengthOfTask && !isCancelled()) {
      publish(100 * current / lengthOfTask);
      total += doSomething();
      current++;
    }
    return total;
  }

  private int calculateTaskSize() throws InterruptedException {
    int total = 0;
    JProgressBar indeterminate = new JProgressBar() {
      @Override public void updateUI() {
        super.updateUI();
        setUI(new IndeterminateProgressBarUI());
      }
    };
    indeterminate.setIndeterminate(true);
    // Indeterminate loop:
    for (int i = 0; i < 200; i++) {
      int iv = rnd.nextInt(50) + 1;
      Thread.sleep(iv);
      ProgressBarUI ui = indeterminate.getUI()
      ((IndeterminateProgressBarUI) ui).incrementAnimationIndex();
      publish(indeterminate);
      total += iv;
    }
    return 1 + total / 100;
  }

  private int doSomething() throws InterruptedException {
    int iv = rnd.nextInt(50) + 1;
    Thread.sleep(iv);
    return iv;
  }
}

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/06/30

Round the corners of JTableHeader

Code

class RoundedHeaderRenderer extends DefaultTableCellRenderer {
  private final JLabel firstLabel = new JLabel() {
    @Override public void paintComponent(Graphics g) {
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setPaint(getBackground());
      float r = 8f;
      float x = 0f;
      float y = 0f;
      float w = getWidth();
      float h = getHeight();
      Path2D p = new Path2D.Float();
      p.moveTo(x, y + r);
      p.quadTo(x, y, x + r, y);
      p.lineTo(x + w, y);
      p.lineTo(x + w, y + h);
      p.lineTo(x + r, y + h);
      p.quadTo(x, y + h, x, y + h - r);
      p.closePath();
      g2.fill(p);
      g2.dispose();
      super.paintComponent(g);
    }
  };
  private final JLabel lastLabel = new JLabel() {
    @Override public void paintComponent(Graphics g) {
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setPaint(getBackground());
      float r = 8f;
      float x = 0f;
      float y = 0f;
      float w = getWidth();
      float h = getHeight();
      Path2D p = new Path2D.Float();
      p.moveTo(x, y);
      p.lineTo(x + w - r, y);
      p.quadTo(x + w, y, x + w, y + r);
      p.lineTo(x + w, y + h - r);
      p.quadTo(x + w, y + h, x + w - r, y + h);
      p.lineTo(x, y + h);
      p.closePath();
      g2.fill(p);
      g2.dispose();
      super.paintComponent(g);
    }
  };

  public RoundedHeaderRenderer() {
    super();
    firstLabel.setOpaque(false);
    lastLabel.setOpaque(false);
    setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    firstLabel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
    lastLabel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
  }

  @Override public Component getTableCellRendererComponent(
        JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    if (column == 0) {
      l = firstLabel;
    } else if (column == table.getColumnCount() - 1) {
      l = lastLabel;
    }
    l.setFont(table.getFont());
    l.setText(value.toString());
    l.setForeground(table.getTableHeader().getForeground());
    l.setBackground(table.getTableHeader().getBackground());
    l.setHorizontalAlignment(SwingConstants.CENTER);
    return l;
  }
}

References

2017/10/27

Set Sudoku style border lines created by MatteBorder as cell ruled lines of JTable

Code

static class SudokuCellRenderer extends DefaultTableCellRenderer {
  private final Font font;
  private final Font bold;
  private final Border b0 = BorderFactory.createMatteBorder(
      0, 0, BORDERWIDTH1, BORDERWIDTH1, Color.GRAY);
  private final Border b1 = BorderFactory.createMatteBorder(
      0, 0, BORDERWIDTH2, BORDERWIDTH2, Color.BLACK);
  private final Border b2 = BorderFactory.createCompoundBorder(
      BorderFactory.createMatteBorder(0, 0, BORDERWIDTH2, 0, Color.BLACK),
      BorderFactory.createMatteBorder(0, 0, 0, BORDERWIDTH1, Color.GRAY));
  private final Border b3 = BorderFactory.createCompoundBorder(
      BorderFactory.createMatteBorder(0, 0, 0, BORDERWIDTH2, Color.BLACK),
      BorderFactory.createMatteBorder(0, 0, BORDERWIDTH1, 0, Color.GRAY));
  private final Integer[][] data;
  protected SudokuCellRenderer(Integer[][] src, Font font) {
    super();
    this.font = font;
    this.bold = font.deriveFont(Font.BOLD);
    Integer[][] dest = new Integer[src.length][src[0].length];
    for (int i = 0; i < src.length; i++) {
      System.arraycopy(src[i], 0, dest[i], 0, src[0].length);
    }
    this.data = dest;
  }
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected, boolean hasFocus,
      int row, int column) {
    boolean isEditable = data[row][column] == 0;
    super.getTableCellRendererComponent(
        table, value, isEditable && isSelected, hasFocus, row, column);
    if (isEditable && Objects.equals(value, 0)) {
      this.setText(" ");
    }
    setFont(isEditable ? font : bold);
    setHorizontalAlignment(CENTER);
    boolean rf = (row + 1) % 3 == 0;
    boolean cf = (column + 1) % 3 == 0;
    if (rf && cf) {
      setBorder(b1);
    } else if (rf) {
      setBorder(b2);
    } else if (cf) {
      setBorder(b3);
    } else {
      setBorder(b0);
    }
    return this;
  }
}

References

2017/06/29

Automatically adjust the height of JTable's row

Code

class TextAreaCellRenderer extends JTextArea implements TableCellRenderer {
  private final List<List<Integer>> cellHeights = new ArrayList<>();

  @Override public void updateUI() {
    super.updateUI();
    setLineWrap(true);
    setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
    setName("Table.cellRenderer");
  }
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected, boolean hasFocus,
      int row, int column) {
    setFont(table.getFont());
    setText(Objects.toString(value, ""));
    adjustRowHeight(table, row, column);
    return this;
  }

  /**
   * Calculate the new preferred height for a given row,
   * and sets the height on the table.
   * http://blog.botunge.dk/post/2009/10/09/JTable-multiline-cell-renderer.aspx
   */
  private void adjustRowHeight(JTable table, int row, int column) {
  // The trick to get this to work properly is to set the width of the column to
  // the textarea. The reason for this is that getPreferredSize(), without a width
  // tries to place all the text in one line.
  // By setting the size with the width of the column,
  // getPreferredSize() returnes the proper height which the row should have in
  // order to make room for the text.
  // int cWidth = table.getTableHeader().getColumnModel().getColumn(column).getWidth();
  // int cWidth = table.getCellRect(row, column, false).width; // IntercellSpacingを無視
  // setSize(new Dimension(cWidth, 1000));

    setBounds(table.getCellRect(row, column, false)); // setSizeではなくsetBoundsでも可
    // doLayout(); // 必要なさそう

    int preferredHeight = getPreferredSize().height;
    while (cellHeights.size() <= row) {
      cellHeights.add(new ArrayList<>(column));
    }
    List<Integer> list = cellHeights.get(row);
    while (list.size() <= column) {
      list.add(0);
    }
    list.set(column, preferredHeight);
    int max = list.stream().max(Integer::compare).get();
    if (table.getRowHeight(row) != max) {
      table.setRowHeight(row, max);
    }
  }
}

References

2016/09/28

Changing JTable header text alignment of specific columns

Code

JTable table2 = makeTable();
table2.getColumnModel().getColumn(0).setHeaderRenderer(
    new HorizontalAlignmentHeaderRenderer(SwingConstants.LEFT));
table2.getColumnModel().getColumn(1).setHeaderRenderer(
    new HorizontalAlignmentHeaderRenderer(SwingConstants.CENTER));
table2.getColumnModel().getColumn(2).setHeaderRenderer(
    new HorizontalAlignmentHeaderRenderer(SwingConstants.RIGHT));

//...
class HorizontalAlignmentHeaderRenderer implements TableCellRenderer {
  private int horizontalAlignment = SwingConstants.LEFT;
  public HorizontalAlignmentHeaderRenderer(int horizontalAlignment) {
    this.horizontalAlignment = horizontalAlignment;
  }
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected,
      boolean hasFocus, int row, int column) {
    TableCellRenderer r = table.getTableHeader().getDefaultRenderer();
    JLabel l = (JLabel) r.getTableCellRendererComponent(
        table, value, isSelected, hasFocus, row, column);
    l.setHorizontalAlignment(horizontalAlignment);
    return l;
  }
}

References

2014/05/01

JProgressBar in JTable cell render a progress string

Code

class Task extends SwingWorker<Integer, ProgressValue> {
  private final int lengthOfTask;
  private final int randomSleep = new Random().nextInt(100) + 1;
  public Task(int lengthOfTask) {
    super();
    this.lengthOfTask = lengthOfTask;
  }

  @Override protected Integer doInBackground() {
    int current = 0;
    while (current < lengthOfTask && !isCancelled()) {
      current++;
      try {
        Thread.sleep(randomSleep);
      } catch (InterruptedException ie) {
        break;
      }
      publish(new ProgressValue(lengthOfTask, current));
    }
    return randomSleep * lengthOfTask;
  }
}

class ProgressValue {
  private final Integer progress;
  private final Integer lengthOfTask;
  public ProgressValue(Integer lengthOfTask, Integer progress) {
    this.progress = progress;
    this.lengthOfTask = lengthOfTask;
  }

  public Integer getProgress() {
    return progress;
  }

  public Integer getLengthOfTask() {
    return lengthOfTask;
  }
}

class ProgressRenderer extends DefaultTableCellRenderer {
  private final JProgressBar progress = new JProgressBar();
  private final JPanel renderer = new JPanel(new BorderLayout());
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected, boolean hasFocus,
      int row, int column) {
    Component c;
    renderer.removeAll();
    progress.setValue(0);
    if (value instanceof ProgressValue) {
      ProgressValue pv = (ProgressValue) value;
      Integer current = pv.getProgress();
      Integer lengthOfTask = pv.getLengthOfTask();
      if (current < 0) {
        c = super.getTableCellRendererComponent(
            table, "Canceled", isSelected, hasFocus, row, column);
      } else if (current < lengthOfTask) {
        progress.setValue(current * 100 / lengthOfTask);
        progress.setStringPainted(true);
        progress.setString(String.format("%d/%d", current, lengthOfTask));
        renderer.add(progress);
        c = renderer;
      } else {
        c = super.getTableCellRendererComponent(
                table, "Done", isSelected, hasFocus, row, column);
      }
    } else {
      c = super.getTableCellRendererComponent(
              table, "Waiting...", isSelected, hasFocus, row, column);
    }
    return c;
  }

  @Override public void updateUI() {
    super.updateUI();
    setOpaque(true);
    if (Objects.nonNull(renderer)) {
      SwingUtilities.updateComponentTreeUI(renderer);
    }
  }
}

References

2013/07/29

JTable highlighting and filtering with regular expression

Code

class HighlightTableCellRenderer
    extends JTextField implements TableCellRenderer {
  private static final Color BGC= new Color(220, 240, 255);
  private final transient Highlighter.HighlightPainter highlightPainter
    = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW);
  private String pattern = "";
  private String prev;

  public boolean setPattern(String str) {
    if (str == null || str.equals(pattern)) {
      return false;
    } else {
      prev = pattern;
      pattern = str;
      return true;
    }
  }

  public HighlightTableCellRenderer() {
    super();
    setOpaque(true);
    setBorder(BorderFactory.createEmptyBorder());
    setForeground(Color.BLACK);
    setBackground(Color.WHITE);
    setEditable(false);
  }

  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected,
      boolean hasFocus, int row, int column) {
    String txt = Objects.toString(value, "");
    Highlighter highlighter = getHighlighter();
    highlighter.removeAllHighlights();
    setText(txt);
    setBackground(isSelected ? BGC : Color.WHITE);
    if (pattern != null && !pattern.isEmpty() && !pattern.equals(prev)) {
      Matcher matcher = Pattern.compile(pattern).matcher(txt);
      int pos = 0;
      while (matcher.find(pos) && !matcher.group().isEmpty()) {
        int start = matcher.start();
        int end   = matcher.end();
        try {
          highlighter.addHighlight(start, end, highlightPainter);
        } catch (BadLocationException | PatternSyntaxException e) {
          e.printStackTrace();
        }
        pos = end;
      }
    }
    return this;
  }
}

References

2013/05/29

Column spanning TableCellRenderer

Code

class ColumnSpanningCellRenderer extends JPanel implements TableCellRenderer {
  private static final int TARGET_COLIDX = 0;
  private final JTextArea textArea = new JTextArea(2, 999999);
  private final JLabel label = new JLabel();
  private final JLabel iconLabel = new JLabel();
  private final JScrollPane scroll = new JScrollPane(textArea);

  protected ColumnSpanningCellRenderer() {
    super(new BorderLayout());

    scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
    scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    scroll.setBorder(BorderFactory.createEmptyBorder());
    scroll.setViewportBorder(BorderFactory.createEmptyBorder());
    scroll.setOpaque(false);
    scroll.getViewport().setOpaque(false);

    textArea.setBorder(BorderFactory.createEmptyBorder());
    textArea.setMargin(new Insets(0, 0, 0, 0));
    textArea.setForeground(Color.RED);
    textArea.setEditable(false);
    textArea.setFocusable(false);
    textArea.setOpaque(false);

    iconLabel.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4));
    iconLabel.setOpaque(false);

    Border b1 = BorderFactory.createEmptyBorder(2, 2, 2, 2);
    Border b2 = BorderFactory.createMatteBorder(0, 0, 1, 1, Color.GRAY);
    label.setBorder(BorderFactory.createCompoundBorder(b2, b1));

    setBackground(textArea.getBackground());
    setOpaque(true);
    add(label, BorderLayout.NORTH);
    add(scroll);
  }
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected,
      boolean hasFocus, int row, int column) {
    OptionPaneDescription d;
    if (value instanceof OptionPaneDescription) {
      d = (OptionPaneDescription) value;
      add(iconLabel, BorderLayout.WEST);
    } else {
      String title = Objects.toString(value, "");
      int mrow = table.convertRowIndexToModel(row);
      Object o = table.getModel().getValueAt(mrow, 0);
      if (o instanceof OptionPaneDescription) {
        OptionPaneDescription t = (OptionPaneDescription) o;
        d = new OptionPaneDescription(title, t.icon, t.text);
      } else {
        d = new OptionPaneDescription(title, null, "");
      }
      remove(iconLabel);
    }
    label.setText(d.title);
    textArea.setText(d.text);
    iconLabel.setIcon(d.icon);

    Rectangle cr = table.getCellRect(row, column, false);
    if (column != TARGET_COLIDX) {
      cr.x -= iconLabel.getPreferredSize().width;
    }
    scroll.getViewport().setViewPosition(cr.getLocation());

    if (isSelected) {
      setBackground(Color.ORANGE);
    } else {
      setBackground(Color.WHITE);
    }
    return this;
  }
}

class OptionPaneDescription {
  public final String title;
  public final Icon icon;
  public final String text;
  protected OptionPaneDescription(String title, Icon icon, String text) {
    this.title = title;
    this.icon  = icon;
    this.text  = text;
  }
}

References

2011/04/19

Transparent JTableHeader

Code

class TransparentHeader extends JLabel implements TableCellRenderer {
  private final Border b = BorderFactory.createCompoundBorder(
      BorderFactory.createMatteBorder(0, 0, 1, 0, Color.BLACK),
      BorderFactory.createEmptyBorder(2, 2, 1, 2));
  private final Color alphaZero = new Color(0x0, true);
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected, boolean hasFocus,
      int row, int column) {
    this.setText(Objects.toString(value, ""));
    this.setHorizontalAlignment(SwingConstants.CENTER);
    this.setOpaque(false);
    this.setBackground(alphaZero);
    this.setForeground(Color.BLACK);
    this.setBorder(b);
    return this;
  }
}

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/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

2010/01/12

make Explorer like JTable File List

Code

// @see SwingUtilities2.pointOutsidePrefSize(...)
private static Rectangle getCellRect2(JTable table, int row, int col) {
  TableCellRenderer tcr = table.getCellRenderer(row, col);
  Object value = table.getValueAt(row, col);
  Component cell = tcr.getTableCellRendererComponent(
      table, value, false, false, row, col);
  Dimension itemSize = cell.getPreferredSize();
  Rectangle cellBounds = table.getCellRect(row, col, false);
  cellBounds.width = itemSize.width;
  return cellBounds;
  // FontMetrics fm = table.getFontMetrics(table.getFont());
  // Object o = table.getValueAt(row, col);
  // int w = fm.stringWidth(o.toString()) + 16 + 2 + 2;
  // Rectangle rect = table.getCellRect(row, col, true);
  // rect.setSize(w, rect.height);
  // return rect;
}

References

2009/10/06

Multiple JButtons in a JTable cell

Code

class ButtonsPanel extends JPanel {
  public final List<JButton> buttons =
    Arrays.asList(new JButton("view"), new JButton("edit"));
  public ButtonsPanel() {
    super();
    setOpaque(true);
    for (JButton b: buttons) {
      b.setFocusable(false);
      b.setRolloverEnabled(false);
      add(b);
    }
  }
}

class ButtonsRenderer extends ButtonsPanel
                      implements TableCellRenderer {
  public ButtonsRenderer() {
    super();
    setName("Table.cellRenderer");
  }

  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected,
      boolean hasFocus, int row, int column) {
    Color bgc = isSelected ? table.getSelectionBackground()
                           : table.getBackground()
    setBackground(bgc);
    return this;
  }
}

class ButtonsEditor extends ButtonsPanel
                    implements TableCellEditor {
  public ButtonsEditor(final JTable table) {
    super();
    // ---->
    // DEBUG: view button click
    //   -> control key down + edit button(same cell) press
    //   -> remain selection color
    MouseListener ml = new MouseAdapter() {
      @Override public void mousePressed(MouseEvent e) {
        ButtonModel m = ((JButton) e.getSource()).getModel();
        if (m.isPressed() && table.isRowSelected(table.getEditingRow())
                          && e.isControlDown()) {
          setBackground(table.getBackground());
        }
      }
    };
    buttons.get(0).addMouseListener(ml);
    buttons.get(1).addMouseListener(ml);
    // <----

    buttons.get(0).addActionListener(new ActionListener() {
      @Override public void actionPerformed(ActionEvent e) {
        fireEditingStopped();
        JOptionPane.showMessageDialog(table, "Viewing");
      }
    });

    buttons.get(1).addActionListener(new ActionListener() {
      @Override public void actionPerformed(ActionEvent e) {
        int row = table.convertRowIndexToModel(table.getEditingRow());
        Object o = table.getModel().getValueAt(row, 0);
        fireEditingStopped();
        JOptionPane.showMessageDialog(table, "Editing: " + o);
      }
    });

    addMouseListener(new MouseAdapter() {
      @Override public void mousePressed(MouseEvent e) {
        fireEditingStopped();
      }
    });
  }

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

  @Override public Object getCellEditorValue() {
    return "";
  }

  // Copied from AbstractCellEditor
  // protected EventListenerList listenerList = new EventListenerList();
  transient protected ChangeEvent changeEvent = null;
  @Override public boolean isCellEditable(java.util.EventObject e) {
    return true;
  }
// ...

References

2009/02/27

HyperLink in JTable Cell

Code

class UriRenderer extends DefaultTableCellRenderer implements MouseListener, MouseMotionListener {
  private int viewRowIndex = -1;
  private int viewColumnIndex = -1;
  private boolean isRollover;

  @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    Component c = super.getTableCellRendererComponent(
        table, value, isSelected, false, row, column);
    if (c instanceof JLabel) {
      JLabel l = (JLabel) c;
      // @see https://ateraimemo.com/Swing/ClippedHtmlLabel.html
      // String str = SwingUtilities.layoutCompoundLabel(...);
      String str = Objects.toString(value, "");
      if (isRolloverCell(table, row, column)) {
        l.setText("<html><u><font color='blue'>" + str);
      } else if (hasFocus) {
        l.setText("<html><font color='blue'>" + str);
      } else {
        l.setText(str);
      }
    }
    return c;
  }

  protected boolean isRolloverCell(JTable table, int row, int column) {
    return !table.isEditing() && viewRowIndex == row && viewColumnIndex == column && isRollover;
  }

  private static boolean isUriColumn(JTable table, int column) {
    return column >= 0 && table.getColumnClass(column).equals(URI.class);
  }

  @Override public void mouseMoved(MouseEvent e) {
    JTable table = (JTable) e.getComponent();
    Point pt = e.getPoint();
    int prevRow = viewRowIndex;
    int prevCol = viewColumnIndex;
    viewRowIndex = table.rowAtPoint(pt);
    viewColumnIndex = table.columnAtPoint(pt);
    boolean isSameCell = viewRowIndex == prevRow && viewColumnIndex == prevCol;

    boolean prevRollover = isRollover;
    isRollover = isUriColumn(table, viewColumnIndex);
    boolean isNotRollover = isRollover == prevRollover && !isRollover; // && !prevRollover;

    if (isSameCell && isNotRollover) {
      return;
    }

    // >>>> HyperlinkCellRenderer.java
    // @see https://github.com/sjas/swingset3/blob/master/trunk/SwingSet3/src/com/sun/swingset3/demos/table/HyperlinkCellRenderer.java
    Rectangle repaintRect;
    if (isRollover) {
      Rectangle r = table.getCellRect(viewRowIndex, viewColumnIndex, false);
      repaintRect = prevRollover ? r.union(table.getCellRect(prevRow, prevCol, false)) : r;
    } else { // if (prevRollover) {
      repaintRect = table.getCellRect(prevRow, prevCol, false);
    }
    table.repaint(repaintRect);
    // <<<<
    // table.repaint();
  }

  @Override public void mouseExited(MouseEvent e) {
    JTable table = (JTable) e.getComponent();
    if (isUriColumn(table, viewColumnIndex)) {
      table.repaint(table.getCellRect(viewRowIndex, viewColumnIndex, false));
      viewRowIndex = -1;
      viewColumnIndex = -1;
      isRollover = false;
    }
  }

  @Override public void mouseClicked(MouseEvent e) {
    JTable table = (JTable) e.getComponent();
    Point pt = e.getPoint();
    int col = table.columnAtPoint(pt);
    if (isUriColumn(table, col)) {
      int crow = table.rowAtPoint(pt);
      URI uri = (URI) table.getValueAt(crow, col);
      try {
        if (Desktop.isDesktopSupported()) {
          Desktop.getDesktop().browse(uri);
        }
      } catch (IOException ex) {
        // Logger.getGlobal().severe(ex::getMessage);
        UIManager.getLookAndFeel().provideErrorFeedback(e.getComponent());
      }
    }
  }

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

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

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

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

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

2008/03/18

JProgressBar in JTable Cell

Code

class ProgressRenderer extends DefaultTableCellRenderer {
  private final JProgressBar b = new JProgressBar(0, 100);
  public ProgressRenderer() {
    super();
    setOpaque(true);
    b.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
  }
  public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {
    Integer i = (Integer) value;
    String text = "Done";
    if (i < 0) {
      text = "Canceled";
    } else if (i < 100) {
      b.setValue(i);
      return b;
    }
    super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column);
    return this;
  }
}
final Executor executor = Executors.newCachedThreadPool();
final int rowNumber = model.getRowCount();
SwingWorker<Integer, Integer> worker = new SwingWorker<Integer, Integer>() {
  private int sleepDummy = new Random().nextInt(100) + 1;
  private int lengthOfTask = 120;
  @Override
  protected Integer doInBackground() {
    int current = 0;
    while (current < lengthOfTask && !isCancelled()) {
      if (!table.isDisplayable()) {
        return -1;
      }
      current++;
      try {
        Thread.sleep(sleepDummy);
      } catch (InterruptedException ie) {
        publish(-1);
        break;
      }
      publish(100 * current / lengthOfTask);
    }
    return sleepDummy * lengthOfTask;
  }
  @Override
  protected void process(List<Integer> chunks) {
    for (Integer value : chunks) {
      model.setValueAt(value, rowNumber, 2);
    }
    // model.fireTableCellUpdated(rowNumber, 2);
  }
  @Override
  protected void done() {
    String text;
    int i = -1;
    if (isCancelled()) {
      text = "Canceled";
    } else {
      try {
        i = get();
        text = (i>=0)?"Done":"Disposed";
      } catch (Exception ignore) {
        ignore.printStackTrace();
        text = ignore.getMessage();
      }
    }
    System.out.println(rowNumber +":"+text+"("+i+"ms)");
  }
};
model.addTest(new Test("example", 0), worker);
executor.execute(worker); // JDK 1.6.0_18
// worker.execute();

References