如何在 JCalendar 中设置自定义周开始?
How to set custom week-start in JCalendar?
我在 JCalendar 中设置自定义一周的第一天时遇到问题。
如果我更改语言环境,一周的第一天会发生变化。
但是,更改基础日历中的一周的第一天没有任何效果。
这是一个简短的演示代码:
public class TestJChooser extends JFrame {
/**
*
*/
public TestJChooser() {
setLayout(new BorderLayout(5,5));
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
Locale locale = Locale.forLanguageTag("de-DE");
Calendar calendar = Calendar.getInstance(locale);
calendar.setFirstDayOfWeek(Calendar.TUESDAY);
JCalendar jCal = new JCalendar(calendar);
jCal.setLocale(locale);
jCal.setPreferredSize(new Dimension(500, 400));
jCal.getDayChooser().setDayBordersVisible(true);
jCal.setTodayButtonVisible(true);
getContentPane().add(jCal,BorderLayout.CENTER);
pack();
setVisible(true);
}
/**
* @param args
*/
public static void main(String[] args) {
new TestJChooser();
}
}
更改
的值
calendar.setFirstDayOfWeek(Calendar.TUESDAY);
不更改 JCalendar 中一周的第一天,也不更改周末。
我找到了一种使用 swingx JXMonthView 实现所需功能的方法:
public class TestJXChooser extends JFrame {
/**
*
*/
public TestJXChooser() {
//set locale
Locale locale = Locale.forLanguageTag("de-DE");
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
UIManager.put(CalendarHeaderHandler.uiControllerID, SpinningCalendarHeaderHandler.class.getName());
UIManager.put(SpinningCalendarHeaderHandler.ARROWS_SURROUND_MONTH, Boolean.TRUE);
UIManager.put(SpinningCalendarHeaderHandler.FOCUSABLE_SPINNER_TEXT, Boolean.TRUE);
final JXMonthView monthView = new JXMonthView();
//needed for the month change and year change arrows
monthView.setZoomable(true);
monthView.setLocale(locale);
//set first day of week to Tuesday
monthView.setFirstDayOfWeek(Calendar.TUESDAY);
//set Tuesday color
monthView.setDayForeground(Calendar.TUESDAY, Color.MAGENTA);
getContentPane().add(monthView );
pack();
setVisible(true);
}
/**
* @param args
*/
public static void main(String[] args) {
new TestJXChooser();
}
}
我无法通过 com.toedter.calendar.JDateChooser.
实现它
为了使用 com.toedter.calendar.JDateChooser 实现我需要的功能,我必须扩展它。
先做一个演示:将星期日设置为一周的第一天(尽管它被语言环境设置为星期一)。测试class:
public class TestJXChooser extends JFrame {
/**
*
*/
public TestJXChooser(){
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
getContentPane().setLayout(new GridLayout(0, 1, 0, 0));
getContentPane().setLayout(new BorderLayout(5,5));
//set locale and calendar
Locale locale = Locale.forLanguageTag("de-DE");
Calendar cal = Calendar.getInstance(locale);
cal.setTime(new Date());
//set first day of week
int firstWeekDay = Calendar.SUNDAY;
cal.setFirstDayOfWeek(firstWeekDay);
//-- Toedter JCalendar
JCalendar jCalendar = new JCalendarExt(null, locale, true, true, false);
jCalendar.setCalendar(cal);
jCalendar.setPreferredSize(new Dimension(120, 160));
jCalendar.getDayChooser().setDayBordersVisible(true);
jCalendar.setTodayButtonVisible(true);
jCalendar.setWeekOfYearVisible(false);
getContentPane().add(jCalendar,BorderLayout.CENTER);
//-- Toedter JDateChooser
JCalendar jCalendar2 = new JCalendarExt(null, locale, true, true, false);
jCalendar2.setCalendar(cal);
JDateChooser dateChooser = new JDateChooser(jCalendar2, null , "dd.mm.yyyy",null);
dateChooser.setLocale(locale);
getContentPane().add(dateChooser,BorderLayout.SOUTH);
pack();
setVisible(true);
}
/**
* @param args
*/
public static void main(String[] args) {
new TestJXChooser();
}
}
结果如图所示
第二张图片演示了将一周的第一天设置为星期二。
扩展了两个 classes。 class 扩展 JCalendar:
/**
* Extended to gain control on week-first-day.
* It also enables the option to display in different color the
* last-day-of-week, rather than <code>JCalendar</code> default which is
* always display Sunday in a different color.
*
* @version
* $Log: JCalendarExt.java,v $
*
*
* @author Ofer Yuval
* 27 Nov 2015
*
*/
public class JCalendarExt extends JCalendar {
/**
*
* @param date
* @param locale
* @param monthSpinner
* @param weekOfYearVisible
* @param colorWeekend
* <br>When false, week-first-day will be painted in red, as in <code>JDayChooser</code>.
* <br>When true, week-last-day will be painted in red.
*/
public JCalendarExt(Date date, Locale locale, boolean monthSpinner, boolean weekOfYearVisible,
boolean colorWeekend) {
super(date, locale, monthSpinner, weekOfYearVisible);
remove(dayChooser);
//add the extended date chooser
dayChooser = new JDayChooserExt(weekOfYearVisible) ;
dayChooser.addPropertyChangeListener(this);
((JDayChooserExt) dayChooser).setColorWeekend(colorWeekend);
monthChooser.setDayChooser(dayChooser);
yearChooser.setDayChooser(dayChooser);
add(dayChooser, BorderLayout.CENTER);
}
@Override
public void setCalendar(Calendar c) {
getDayChooser().setCalendar(c);
super.setCalendar(c);
}
}
和 class 扩展 JDayChooser:
/**
*
* @version
* $Log: JDayChooserExt.java,v $
*
*
* @author Ofer Yuval
* 27 Nov 2015
*
*/
public class JDayChooserExt extends JDayChooser {
/**
* When false, week-first-day will be painted in red, as in <code>JDayChooser</code>.
* When true, week-last-day will be painted in red.
*/
private boolean isColorWeekend = false;
/**
* @param weekOfYearVisible
*/
public JDayChooserExt(boolean weekOfYearVisible) {
super(weekOfYearVisible);
}
/**
* Initializes the locale specific names for the days of the week.
*/
@Override
protected void init() {
JButton testButton = new JButton();
oldDayBackgroundColor = testButton.getBackground();
selectedColor = new Color(160, 160, 160);
drawDayNames();
drawDays();
}
/**
* Draws the day names of the day columns.
*/
private void drawDayNames() {
DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(locale);
dayNames = dateFormatSymbols.getShortWeekdays();
int Day = calendar.getFirstDayOfWeek();//firstDayOfWeek;
int coloredDay = (isColorWeekend ) ? Day -1 : Day;
if(coloredDay <= 0) {
coloredDay += 7;
}
for (int i = 0; i < 7; i++) {
if ((maxDayCharacters > 0) && (maxDayCharacters < 5)) {
if (dayNames[Day].length() >= maxDayCharacters) {
dayNames[Day] = dayNames[Day]
.substring(0, maxDayCharacters);
}
}
days[i].setText(dayNames[Day]);
if (Day == coloredDay) {
days[i].setForeground(sundayForeground);
} else {
days[i].setForeground(weekdayForeground);
}
if (Day < 7) {
Day++;
} else {
Day -= 6;
}
}
}
/**
* @param isColorWeekend the isColorWeekend to set
*/
public void setColorWeekend(boolean isColorWeekend) {
this.isColorWeekend = isColorWeekend;
}
// ///////////////////////////////////////////////////////////
// ////////////// DecoratorButton class //////////////////////
// ///////////////////////////////////////////////////////////
class DecoratorButton extends JButton {
private static final long serialVersionUID = -5306477668406547496L;
public DecoratorButton() {
setBackground(decorationBackgroundColor);
setContentAreaFilled(decorationBackgroundVisible);
setBorderPainted(decorationBordersVisible);
}
@Override
public void addMouseListener(MouseListener l) {
}
@Override
public boolean isFocusable() {
return false;
}
@Override
public void paint(Graphics g) {
if ("Windows".equals(UIManager.getLookAndFeel().getID())) {
// this is a hack to get the background painted
// when using Windows Look & Feel
if (decorationBackgroundVisible) {
g.setColor(decorationBackgroundColor);
} else {
g.setColor(days[7].getBackground());
}
g.fillRect(0, 0, getWidth(), getHeight());
if (isBorderPainted()) {
setContentAreaFilled(true);
} else {
setContentAreaFilled(false);
}
}
super.paint(g);
}
};
}
这里是使用反射的肮脏方式,你只需要重写JCalendar
:
private class MyJCalendar extends JCalendar {
MyJCalendar(Calendar c) {
super(c);
}
public void setFirstDayOfWeek(int firstdayofweek) {
try {
// Dirty hack to set first day of week :-)
Field f = JDayChooser.class.getDeclaredField("calendar");
f.setAccessible(true);
Calendar c = (Calendar) f.get(dayChooser);
c.setFirstDayOfWeek(firstdayofweek);
Method m = JDayChooser.class.getDeclaredMethod("drawDayNames");
m.setAccessible(true);
m.invoke(dayChooser, (Object[])null);
m = JDayChooser.class.getDeclaredMethod("drawDays");
m.setAccessible(true);
m.invoke(dayChooser, (Object[])null);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
我在 JCalendar 中设置自定义一周的第一天时遇到问题。 如果我更改语言环境,一周的第一天会发生变化。 但是,更改基础日历中的一周的第一天没有任何效果。
这是一个简短的演示代码:
public class TestJChooser extends JFrame {
/**
*
*/
public TestJChooser() {
setLayout(new BorderLayout(5,5));
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
Locale locale = Locale.forLanguageTag("de-DE");
Calendar calendar = Calendar.getInstance(locale);
calendar.setFirstDayOfWeek(Calendar.TUESDAY);
JCalendar jCal = new JCalendar(calendar);
jCal.setLocale(locale);
jCal.setPreferredSize(new Dimension(500, 400));
jCal.getDayChooser().setDayBordersVisible(true);
jCal.setTodayButtonVisible(true);
getContentPane().add(jCal,BorderLayout.CENTER);
pack();
setVisible(true);
}
/**
* @param args
*/
public static void main(String[] args) {
new TestJChooser();
}
}
更改
的值 calendar.setFirstDayOfWeek(Calendar.TUESDAY);
不更改 JCalendar 中一周的第一天,也不更改周末。
我找到了一种使用 swingx JXMonthView 实现所需功能的方法:
public class TestJXChooser extends JFrame {
/**
*
*/
public TestJXChooser() {
//set locale
Locale locale = Locale.forLanguageTag("de-DE");
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
UIManager.put(CalendarHeaderHandler.uiControllerID, SpinningCalendarHeaderHandler.class.getName());
UIManager.put(SpinningCalendarHeaderHandler.ARROWS_SURROUND_MONTH, Boolean.TRUE);
UIManager.put(SpinningCalendarHeaderHandler.FOCUSABLE_SPINNER_TEXT, Boolean.TRUE);
final JXMonthView monthView = new JXMonthView();
//needed for the month change and year change arrows
monthView.setZoomable(true);
monthView.setLocale(locale);
//set first day of week to Tuesday
monthView.setFirstDayOfWeek(Calendar.TUESDAY);
//set Tuesday color
monthView.setDayForeground(Calendar.TUESDAY, Color.MAGENTA);
getContentPane().add(monthView );
pack();
setVisible(true);
}
/**
* @param args
*/
public static void main(String[] args) {
new TestJXChooser();
}
}
为了使用 com.toedter.calendar.JDateChooser 实现我需要的功能,我必须扩展它。
先做一个演示:将星期日设置为一周的第一天(尽管它被语言环境设置为星期一)。测试class:
public class TestJXChooser extends JFrame {
/**
*
*/
public TestJXChooser(){
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
getContentPane().setLayout(new GridLayout(0, 1, 0, 0));
getContentPane().setLayout(new BorderLayout(5,5));
//set locale and calendar
Locale locale = Locale.forLanguageTag("de-DE");
Calendar cal = Calendar.getInstance(locale);
cal.setTime(new Date());
//set first day of week
int firstWeekDay = Calendar.SUNDAY;
cal.setFirstDayOfWeek(firstWeekDay);
//-- Toedter JCalendar
JCalendar jCalendar = new JCalendarExt(null, locale, true, true, false);
jCalendar.setCalendar(cal);
jCalendar.setPreferredSize(new Dimension(120, 160));
jCalendar.getDayChooser().setDayBordersVisible(true);
jCalendar.setTodayButtonVisible(true);
jCalendar.setWeekOfYearVisible(false);
getContentPane().add(jCalendar,BorderLayout.CENTER);
//-- Toedter JDateChooser
JCalendar jCalendar2 = new JCalendarExt(null, locale, true, true, false);
jCalendar2.setCalendar(cal);
JDateChooser dateChooser = new JDateChooser(jCalendar2, null , "dd.mm.yyyy",null);
dateChooser.setLocale(locale);
getContentPane().add(dateChooser,BorderLayout.SOUTH);
pack();
setVisible(true);
}
/**
* @param args
*/
public static void main(String[] args) {
new TestJXChooser();
}
}
结果如图所示
第二张图片演示了将一周的第一天设置为星期二。
扩展了两个 classes。 class 扩展 JCalendar:
/**
* Extended to gain control on week-first-day.
* It also enables the option to display in different color the
* last-day-of-week, rather than <code>JCalendar</code> default which is
* always display Sunday in a different color.
*
* @version
* $Log: JCalendarExt.java,v $
*
*
* @author Ofer Yuval
* 27 Nov 2015
*
*/
public class JCalendarExt extends JCalendar {
/**
*
* @param date
* @param locale
* @param monthSpinner
* @param weekOfYearVisible
* @param colorWeekend
* <br>When false, week-first-day will be painted in red, as in <code>JDayChooser</code>.
* <br>When true, week-last-day will be painted in red.
*/
public JCalendarExt(Date date, Locale locale, boolean monthSpinner, boolean weekOfYearVisible,
boolean colorWeekend) {
super(date, locale, monthSpinner, weekOfYearVisible);
remove(dayChooser);
//add the extended date chooser
dayChooser = new JDayChooserExt(weekOfYearVisible) ;
dayChooser.addPropertyChangeListener(this);
((JDayChooserExt) dayChooser).setColorWeekend(colorWeekend);
monthChooser.setDayChooser(dayChooser);
yearChooser.setDayChooser(dayChooser);
add(dayChooser, BorderLayout.CENTER);
}
@Override
public void setCalendar(Calendar c) {
getDayChooser().setCalendar(c);
super.setCalendar(c);
}
}
和 class 扩展 JDayChooser:
/**
*
* @version
* $Log: JDayChooserExt.java,v $
*
*
* @author Ofer Yuval
* 27 Nov 2015
*
*/
public class JDayChooserExt extends JDayChooser {
/**
* When false, week-first-day will be painted in red, as in <code>JDayChooser</code>.
* When true, week-last-day will be painted in red.
*/
private boolean isColorWeekend = false;
/**
* @param weekOfYearVisible
*/
public JDayChooserExt(boolean weekOfYearVisible) {
super(weekOfYearVisible);
}
/**
* Initializes the locale specific names for the days of the week.
*/
@Override
protected void init() {
JButton testButton = new JButton();
oldDayBackgroundColor = testButton.getBackground();
selectedColor = new Color(160, 160, 160);
drawDayNames();
drawDays();
}
/**
* Draws the day names of the day columns.
*/
private void drawDayNames() {
DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(locale);
dayNames = dateFormatSymbols.getShortWeekdays();
int Day = calendar.getFirstDayOfWeek();//firstDayOfWeek;
int coloredDay = (isColorWeekend ) ? Day -1 : Day;
if(coloredDay <= 0) {
coloredDay += 7;
}
for (int i = 0; i < 7; i++) {
if ((maxDayCharacters > 0) && (maxDayCharacters < 5)) {
if (dayNames[Day].length() >= maxDayCharacters) {
dayNames[Day] = dayNames[Day]
.substring(0, maxDayCharacters);
}
}
days[i].setText(dayNames[Day]);
if (Day == coloredDay) {
days[i].setForeground(sundayForeground);
} else {
days[i].setForeground(weekdayForeground);
}
if (Day < 7) {
Day++;
} else {
Day -= 6;
}
}
}
/**
* @param isColorWeekend the isColorWeekend to set
*/
public void setColorWeekend(boolean isColorWeekend) {
this.isColorWeekend = isColorWeekend;
}
// ///////////////////////////////////////////////////////////
// ////////////// DecoratorButton class //////////////////////
// ///////////////////////////////////////////////////////////
class DecoratorButton extends JButton {
private static final long serialVersionUID = -5306477668406547496L;
public DecoratorButton() {
setBackground(decorationBackgroundColor);
setContentAreaFilled(decorationBackgroundVisible);
setBorderPainted(decorationBordersVisible);
}
@Override
public void addMouseListener(MouseListener l) {
}
@Override
public boolean isFocusable() {
return false;
}
@Override
public void paint(Graphics g) {
if ("Windows".equals(UIManager.getLookAndFeel().getID())) {
// this is a hack to get the background painted
// when using Windows Look & Feel
if (decorationBackgroundVisible) {
g.setColor(decorationBackgroundColor);
} else {
g.setColor(days[7].getBackground());
}
g.fillRect(0, 0, getWidth(), getHeight());
if (isBorderPainted()) {
setContentAreaFilled(true);
} else {
setContentAreaFilled(false);
}
}
super.paint(g);
}
};
}
这里是使用反射的肮脏方式,你只需要重写JCalendar
:
private class MyJCalendar extends JCalendar {
MyJCalendar(Calendar c) {
super(c);
}
public void setFirstDayOfWeek(int firstdayofweek) {
try {
// Dirty hack to set first day of week :-)
Field f = JDayChooser.class.getDeclaredField("calendar");
f.setAccessible(true);
Calendar c = (Calendar) f.get(dayChooser);
c.setFirstDayOfWeek(firstdayofweek);
Method m = JDayChooser.class.getDeclaredMethod("drawDayNames");
m.setAccessible(true);
m.invoke(dayChooser, (Object[])null);
m = JDayChooser.class.getDeclaredMethod("drawDays");
m.setAccessible(true);
m.invoke(dayChooser, (Object[])null);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}