• category: swing folder: DiagonallySplitCellCalendar title: JTableのセルを斜めに分割する tags: [JTable, JLayer, JLabel] author: aterai pubdate: 2020-06-01T03:09:34+09:00 description: JTableのセルレンダラーにJLayerで直線を描画して斜め分断セルを表示します。 image: https://drive.google.com/uc?id=19GKh0Ts86Zd4J0mjJTp1pmNkOnrcURBy

概要

JTableのセルレンダラーにJLayerで直線を描画して斜め分断セルを表示します。

サンプルコード

private class CalendarTableRenderer extends DefaultTableCellRenderer {
  private final JPanel p = new JPanel();

  @Override public Component getTableCellRendererComponent(
        JTable table, Object value, boolean selected, boolean focused,
        int row, int column) {
    JLabel c = (JLabel) super.getTableCellRendererComponent(
        table, value, selected, focused, row, column);
    if (value instanceof LocalDate) {
      LocalDate d = (LocalDate) value;
      c.setText(Objects.toString(d.getDayOfMonth()));
      c.setVerticalAlignment(SwingConstants.TOP);
      c.setHorizontalAlignment(SwingConstants.LEFT);
      updateCellWeekColor(d, c, c);

      LocalDate nextWeekDay = d.plusDays(7);
      boolean isLastRow = row == table.getModel().getRowCount() - 1;
      if (isLastRow &&
          YearMonth.from(nextWeekDay).equals(YearMonth.from(getCurrentLocalDate()))) {
        JLabel sub = new JLabel(Objects.toString(nextWeekDay.getDayOfMonth()));
        sub.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
        sub.setOpaque(false);
        sub.setVerticalAlignment(SwingConstants.BOTTOM);
        sub.setHorizontalAlignment(SwingConstants.RIGHT);

        p.removeAll();
        p.setLayout(new BorderLayout());
        p.add(sub, BorderLayout.SOUTH);
        p.add(c, BorderLayout.NORTH);
        p.setBorder(c.getBorder());
        c.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));

        updateCellWeekColor(d, sub, p);
        return new JLayer<>(p, new DiagonallySplitCellLayerUI());
      }
    }
    return c;
  }
  // ...
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、月カレンダーで6週目になる日を前の5週目の同じ曜日のセルを斜め分割してまとめて表示しています。

  • DefaultTableModel#getRowCount()が常に5を返すようオーバーライドして、月カレンダーが5週分のみ表示するよう設定
  • 5週目(row==4)を表示するセルレンダラーで対象日の7日後が今月の場合、BorderLayoutを設定したJPanelを作成し対象日用のJLabelBorderLayout.NORTH7日後の日付を表示するための別JLabelBorderLayout.SOUTHに追加
  • このJLabelに斜め線を表示するJLayerを作成してセルレンダラーとして使用
class DiagonallySplitCellLayerUI extends LayerUI<JPanel> {
  @Override public void paint(Graphics g, JComponent c) {
    super.paint(g, c);
    if (c instanceof JLayer) {
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setPaint(UIManager.getColor("Table.gridColor"));
      g2.drawLine(c.getWidth(), 0, 0, c.getHeight());
      g2.dispose();
    }
  }
}

参考リンク

コメント