Swing/CalendarViewTable のバックアップ(No.4)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/CalendarViewTable へ行く。
- 1 (2018-01-29 (月) 15:00:50)
- 2 (2018-01-29 (月) 16:16:31)
- 3 (2018-01-30 (火) 13:10:45)
- 4 (2018-02-01 (木) 20:21:48)
- 5 (2018-02-02 (金) 17:40:26)
- 6 (2018-02-02 (金) 20:11:40)
- 7 (2018-02-05 (月) 16:07:58)
- 8 (2018-02-15 (木) 14:23:42)
- 9 (2018-03-02 (金) 17:44:10)
- 10 (2018-03-13 (火) 16:29:32)
- 11 (2020-03-17 (火) 18:32:28)
- 12 (2021-09-24 (金) 14:51:03)
- 13 (2024-03-01 (金) 19:11:43)
- 14 (2024-09-05 (木) 20:43:02)
- category: swing
folder: CalendarViewTable
title: JTableにLocaleを考慮したLocalDateを適用してカレンダーを表示する
tags: [JTable, LocalDate, Locale, Calendar]
author: aterai
pubdate: 2018-01-29T14:57:32+09:00
description: JTableに週の最初の曜日がLocaleに応じて変化するカレンダーを表示します。
image: https://drive.google.com/uc?export=view&id=1jXZtiYFaA5ABWsdaRBnPUKqS2_VBDkFqQA
hreflang:
href: https://java-swing-tips.blogspot.com/2018/01/apply-localdate-considering-locale-to.html lang: en
概要
JTable
に週の最初の曜日がLocale
に応じて変化するカレンダーを表示します。
Screenshot
Advertisement
サンプルコード
class CalendarViewTableModel<T extends LocalDate> extends DefaultTableModel {
private final LocalDate startDate;
private final WeekFields weekFields = WeekFields.of(Locale.getDefault());
public CalendarViewTableModel(T date) {
super();
LocalDate firstDayOfMonth = YearMonth.from(date).atDay(1);
int dowv = firstDayOfMonth.get(weekFields.dayOfWeek()) - 1;
startDate = firstDayOfMonth.minusDays(dowv);
}
@Override public Class<?> getColumnClass(int column) {
return LocalDate.class;
}
@Override public String getColumnName(int column) {
return weekFields.getFirstDayOfWeek().plus(column)
.getDisplayName(TextStyle.SHORT_STANDALONE, Locale.getDefault());
}
@Override public int getRowCount() {
return 6;
}
@Override public int getColumnCount() {
return 7;
}
@Override public Object getValueAt(int row, int column) {
return startDate.plusDays(row * getColumnCount() + column);
}
@Override public boolean isCellEditable(int row, int column) {
return false;
}
}
View in GitHub: Java, Kotlin解説
上記のサンプルでは、Java 8
からjava.time
パッケージに追加されたLocalDate
をJTable
のモデルとして使用し、月のカレンダーを表示しています。
- WeekFields#getFirstDayOfWeek()メソッドで
Locale
に応じた週の最初の曜日を取得して、JTable
の0
列目を設定- 例: フランスと
ISO-8601
標準では月曜日が週の最初の曜日になるjava -Duser.language=fr -jar example.jar
- 例: フランスと
- 土曜と日曜の位置も
6
列目と0
列目固定ではないので、以下のようにLocalDate.getDayOfWeek()
メソッドで曜日を確認してその背景色を変更する必要がある
private class CalendarTableRenderer extends DefaultTableCellRenderer {
@Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean selected, boolean focused,
int row, int column) {
super.getTableCellRendererComponent(table, value, selected, focused, row, column);
setHorizontalAlignment(SwingConstants.CENTER);
if (value instanceof LocalDate) {
LocalDate d = (LocalDate) value;
setText(String.valueOf(d.getDayOfMonth()));
if (YearMonth.from(d).equals(YearMonth.from(currentLocalDate))) {
setForeground(Color.BLACK);
} else {
setForeground(Color.GRAY);
}
DayOfWeek dow = d.getDayOfWeek();
if (d.isEqual(realLocalDate)) {
setBackground(new Color(220, 255, 220));
} else if (dow == DayOfWeek.SUNDAY) {
setBackground(new Color(255, 220, 220));
} else if (dow == DayOfWeek.SATURDAY) {
setBackground(new Color(220, 220, 255));
} else {
setBackground(Color.WHITE);
}
}
return this;
}
}
JTable
ではなく、JList
を使用すると週を跨いだ日付の範囲選択が可能
import java.awt.*;
import java.time.*;
import java.time.format.*;
import java.time.temporal.*;
import java.util.*;
import javax.swing.*;
public class CalendarViewListTest {
private final JLabel monthLabel = new JLabel("", SwingConstants.CENTER);
private final JList<LocalDate> monthList = new JList<>();
private final LocalDate realLocalDate = LocalDate.now();
private LocalDate currentLocalDate;
public JComponent makeUI() {
Dimension size = new Dimension(40, 20);
monthList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
monthList.setVisibleRowCount(6);
monthList.setFixedCellWidth(size.width);
monthList.setFixedCellHeight(size.height);
monthList.setCellRenderer(new CalendarTableRenderer<LocalDate>());
monthList.getSelectionModel().setSelectionMode(
ListSelectionModel.SINGLE_INTERVAL_SELECTION);
Locale l = Locale.getDefault();
DefaultListModel<DayOfWeek> weekModel = new DefaultListModel<>();
DayOfWeek firstDayOfWeek = WeekFields.of(l).getFirstDayOfWeek();
for (int i = 0; i < 7; i++) {
weekModel.add(i, firstDayOfWeek.plus(i));
}
JList<DayOfWeek> header = new JList<>(weekModel);
header.setLayoutOrientation(JList.HORIZONTAL_WRAP);
header.setVisibleRowCount(0);
header.setFixedCellWidth(size.width);
header.setFixedCellHeight(size.height);
header.setCellRenderer(new DefaultListCellRenderer() {
@Override public Component getListCellRendererComponent(
JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, false, false);
setHorizontalAlignment(SwingConstants.CENTER);
if (value instanceof DayOfWeek) {
DayOfWeek dow = (DayOfWeek) value;
String s = dow.getDisplayName(TextStyle.SHORT_STANDALONE, l);
setText(s.substring(0, Math.min(2, s.length())));
setBackground(new Color(220, 220, 220));
}
return this;
}
});
updateMonthView(realLocalDate);
JButton prev = new JButton("<");
prev.addActionListener(e -> updateMonthView(currentLocalDate.minusMonths(1)));
JButton next = new JButton(">");
next.addActionListener(e -> updateMonthView(currentLocalDate.plusMonths(1)));
JPanel monthPanel = new JPanel(new BorderLayout());
monthPanel.add(monthLabel);
monthPanel.add(prev, BorderLayout.WEST);
monthPanel.add(next, BorderLayout.EAST);
JScrollPane scroll = new JScrollPane(monthList);
scroll.setColumnHeaderView(header);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
Box box = Box.createVerticalBox();
box.add(monthPanel);
box.add(Box.createVerticalStrut(2));
box.add(scroll);
JPanel p = new JPanel();
p.add(box);
return p;
}
private void updateMonthView(LocalDate localDate) {
currentLocalDate = localDate;
monthLabel.setText(localDate.format(DateTimeFormatter.ofPattern("yyyy / MM")
.withLocale(Locale.getDefault())));
WeekFields weekFields = WeekFields.of(Locale.getDefault());
LocalDate firstDayOfMonth = localDate.with(TemporalAdjusters.firstDayOfMonth());
int dowv = firstDayOfMonth.get(weekFields.dayOfWeek()) - 1;
int vlen = 7 * 6;
LocalDate date = firstDayOfMonth.minusDays(dowv);
DefaultListModel<LocalDate> calendarModel = new DefaultListModel<>();
for (int i = 0; i < vlen; i++) {
calendarModel.add(i, date.plusDays(i));
}
monthList.setModel(calendarModel);
}
class CalendarTableRenderer<E extends LocalDate> implements ListCellRenderer<E> {
private final JLabel renderer = new JLabel("", SwingConstants.CENTER);
@Override public Component getListCellRendererComponent(
JList<? extends E> list, E value, int index,
boolean isSelected, boolean cellHasFocus) {
renderer.setOpaque(true);
if (value instanceof LocalDate) {
LocalDate d = (LocalDate) value;
renderer.setText(String.valueOf(d.getDayOfMonth()));
if (YearMonth.from(d).equals(YearMonth.from(currentLocalDate))) {
renderer.setForeground(Color.BLACK);
} else {
renderer.setForeground(Color.GRAY);
}
DayOfWeek dow = d.getDayOfWeek();
if (d.isEqual(realLocalDate)) {
renderer.setBackground(new Color(220, 255, 220));
} else if (dow == DayOfWeek.SUNDAY) {
renderer.setBackground(new Color(255, 220, 220));
} else if (dow == DayOfWeek.SATURDAY) {
renderer.setBackground(new Color(220, 220, 255));
} else {
renderer.setBackground(Color.WHITE);
}
if (isSelected) {
renderer.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.GRAY));
} else {
renderer.setBorder(BorderFactory.createEmptyBorder(0, 0, 1, 0));
}
}
return renderer;
}
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new CalendarViewListTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}