---
category: swing
folder: CalendarHeatmapList
title: JListでウィークカレンダーを作成してヒートマップを表示する
tags: [JList, LocalDate, ListModel, Calendar, Icon]
author: aterai
pubdate: 2018-03-05T17:08:51+09:00
description: JListを垂直方向ニュースペーパー・スタイルレイアウトに設定してウィークカレンダーを作成し、これにヒートマップを表示します。
image: https://drive.google.com/uc?id=1nuJgXoB7AW6ndK0nG_xUtriaxwJAt5N53Q
---
* 概要 [#summary]
`JList`を垂直方向ニュースペーパー・スタイルレイアウトに設定してウィークカレンダーを作成し、これにヒートマップを表示します。

#download(https://drive.google.com/uc?id=1nuJgXoB7AW6ndK0nG_xUtriaxwJAt5N53Q)

* サンプルコード [#sourcecode]
#code(link){{
JList<Contribution> weekList = new JList<Contribution>() {
  @Override public void updateUI() {
    setCellRenderer(null);
    super.updateUI();
    setLayoutOrientation(JList.VERTICAL_WRAP);
    setVisibleRowCount(DayOfWeek.values().length); // ensure 7 rows in the list
    setFixedCellWidth(size.width);
    setFixedCellHeight(size.height);
    setCellRenderer(new ContributionListRenderer());
    getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
    setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
  }
};
//...
private class ContributionListRenderer implements ListCellRenderer<Contribution> {
  private final ListCellRenderer<? super Contribution> renderer
    = new DefaultListCellRenderer();
  @Override public Component getListCellRendererComponent(
      JList<? extends Contribution> list, Contribution value, int index,
      boolean isSelected, boolean cellHasFocus) {
    JLabel l = (JLabel) renderer.getListCellRendererComponent(
        list, null, index, isSelected, cellHasFocus);
    if (value.date.isAfter(currentLocalDate)) {
      l.setIcon(new ColorIcon(Color.WHITE));
      l.setToolTipText(null);
    } else {
      l.setIcon(new ColorIcon(activityColors.get(value.activity)));
      String actTxt = value.activity == 0 ? "No" : Objects.toString(value.activity);
      l.setToolTipText(actTxt + " contribution on " + value.date.toString());
    }
    return l;
  }
}
}}

* 解説 [#explanation]
上記のサンプルでは、セルが水平方向の次に垂直方向の順で並ぶ「ニュースペーパー・スタイル」レイアウトの`JList`を使用して、`GitHub`で表示されている`Contribution activity`風のヒートマップカレンダーを作成しています。

- `1`列で`1`週間になるよう、`JList.VERTICAL_WRAP`スタイルでの列数を`JList#setVisibleRowCount(7)`で指定
- `WeekFields#getFirstDayOfWeek()`メソッドで`Locale`に応じた週の最初の曜日を取得して、`JList`の`0`行目を設定
#code{{
public static final int WEEK_VIEW = 27;
//...
WeekFields weekFields = WeekFields.of(Locale.getDefault());
int dow = date.get(weekFields.dayOfWeek()) - 1;
startDate = date.minusWeeks(WEEK_VIEW - 1).minusDays(dow);
}}
- 表示される週は、約半年分の`27`週に設定
- ヒートマップは、テキストを空にして色アイコンを設定した`JLabel`を`ListCellRenderer#getListCellRendererComponent(...)`メソッドで返すことで表示
-- ツールチップテキストもこの``ListCellRenderer`の`JLabel`に設定

* 参考リンク [#reference]
- [[JListで月のカーソルキー移動や、週を跨いた日付を範囲選択が可能なカレンダーを作成する>Swing/CalendarViewList]]
-- こちらはセルが水平方向の次に垂直方向の順で並ぶ「ニュースペーパー・スタイル」レイアウトの`JList`で月カレンダーを表示

* コメント [#comment]
#comment
#comment