直接上代码,非常完整的代码,copy可以直接运行:
package component;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Paint;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* 时间选择器
*
* @author tang
* @since 2014/7/18
*
*/
@SuppressWarnings("serial")
public class DateChooser extends JPanel {
public static void main(String[] args) {
final JFrame frame = new JFrame("时间选择器");
frame.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 20));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
final JTextField textField = new JTextField(10);
frame.add(textField);
final JButton buttonLeft = new JButton("选择日期(弹出的对话框以此按钮左对齐)");
buttonLeft.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Dimension dialogSize = new Dimension(400, 250);
Point screen = buttonLeft.getLocationOnScreen();
Point point = new Point(screen.x, screen.y + buttonLeft.getPreferredSize().height + 5);
DateChooser dateChooser = new DateChooser();
String selectedDate = dateChooser.showDateDialog(frame, point, dialogSize);
if (dateChooser.isConfirm()) {
textField.setText(selectedDate);
}
}
});
frame.add(buttonLeft);
final JButton buttonRight = new JButton("选择日期(弹出的对话框以此按钮右对齐)");
buttonRight.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Dimension dialogSize = new Dimension(400, 250);
int x = dialogSize.width - buttonRight.getPreferredSize().width;
Point screen = buttonRight.getLocationOnScreen();
Point point = new Point(screen.x - x, screen.y + buttonRight.getPreferredSize().height + 5);
DateChooser dateChooser = new DateChooser();
String selectedDate = dateChooser.showDateDialog(frame, point, dialogSize);
if (dateChooser.isConfirm()) {
textField.setText(selectedDate);
}
}
});
frame.add(buttonRight);
frame.setVisible(true);
}
protected final int startYear;
protected final int lastYear;
protected final String[] weekStrings = { "日", "一", "二", "三", "四", "五", "六" };
protected Color selectedColor = new Color(250, 100, 100);
protected Color northColor = Color.decode("#f6f6f6"); // 控制条底色
protected Color labelColor = new Color(55, 80, 80); // 年/月标签文字色
protected Font labelFont = new Font("微软雅黑", Font.PLAIN, 14); // 年/月标签字体
protected Color weekLabelColor = new Color(150, 50, 150); // 星期标签文字色
protected Color weekendFontColor = new Color(100, 200, 100); // 周末文字色
protected Color dateFontColor = Color.BLACK; // 日期文字色
protected JDialog dialog;
protected JSpinner yearSpinner;
protected JSpinner monthSpinner;
protected JButton[][] dayButtons = new JButton[6][7];
protected ButtonGroup buttonGroup = new ButtonGroup();
protected DateFormat format;
protected Date date;
protected String selectedDay;
protected boolean isConfirm;
public DateChooser() {
this(new SimpleDateFormat("yyyy-MM-dd"));
}
public DateChooser(DateFormat format) {
this(format, new Date());
}
public DateChooser(DateFormat format, Date date) {
this(format, date, 1980, 2080);
}
public DateChooser(DateFormat format, Date date, int startYear, int lastYear) {
this.date = date;
this.format = format;
this.startYear = startYear;
this.lastYear = lastYear;
selectedDay = getCalendar().get(Calendar.DAY_OF_MONTH) + "";
setLayout(new BorderLayout());
setBackground(Color.WHITE);
JPanel northPanel = createNorthPanal();
northPanel.setPreferredSize(new Dimension(0, 40));
add(northPanel, BorderLayout.NORTH);
JPanel centerPanel = createCenterPanal();
add(centerPanel, BorderLayout.CENTER);
JPanel southPanel = createSouthPanel();
southPanel.setPreferredSize(new Dimension(0, 40));
add(southPanel, java.awt.BorderLayout.SOUTH);
}
private JPanel createNorthPanal() {
Calendar c = getCalendar();
int currentYear = c.get(Calendar.YEAR);
int currentMonth = c.get(Calendar.MONTH) + 1;
JPanel northPanel = new JPanel();
northPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 8));
northPanel.setBackground(northColor);
yearSpinner = new JSpinner(new SpinnerNumberModel(currentYear, startYear, lastYear, 1));
yearSpinner.setEditor(new JSpinner.NumberEditor(yearSpinner, "####"));
yearSpinner.setPreferredSize(new Dimension(60, 25));
yearSpinner.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
updateDate(Calendar.YEAR, (Integer) yearSpinner.getValue());
}
});
northPanel.add(yearSpinner);
JLabel yearLabel = new JLabel("年");
yearLabel.setForeground(labelColor);
yearLabel.setFont(labelFont);
northPanel.add(yearLabel);
northPanel.add(Box.createHorizontalStrut(15));
monthSpinner = new JSpinner(new SpinnerNumberModel(currentMonth, 1, 12, 1));
monthSpinner.setEditor(new JSpinner.NumberEditor(monthSpinner, "##"));
monthSpinner.setPreferredSize(new Dimension(60, 25));
monthSpinner.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
updateDate(Calendar.MONTH, (Integer) monthSpinner.getValue() - 1);
}
});
northPanel.add(monthSpinner);
JLabel monthLabel = new JLabel("月");
monthLabel.setForeground(labelColor);
monthLabel.setFont(labelFont);
northPanel.add(monthLabel);
return northPanel;
}
private JPanel createCenterPanal() {
JPanel centerPanel = new JPanel();
// 设置固定字体,以免调用环境改变影响界面美观
centerPanel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
centerPanel.setLayout(new GridLayout(7, 7));
centerPanel.setBackground(Color.WHITE);
for (int i = 0; i < 7; i++) {
RolloverBackgroundButton cell = new RolloverBackgroundButton(weekStrings[i]);
cell.clearDefaultAttribute();
cell.setHorizontalAlignment(JLabel.RIGHT);
cell.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
cell.setNormalForeground(weekLabelColor);
centerPanel.add(cell);
}
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 7; j++) {
final RolloverBackgroundButton numberButton = new RolloverBackgroundButton("");
numberButton.clearDefaultAttribute();
numberButton.setHorizontalAlignment(SwingConstants.RIGHT);
numberButton.setNormalForeground(dateFontColor);
numberButton.setSelectedForeground(selectedColor);
numberButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (numberButton.getText().length() == 0) {
return;
}
selectedDay = numberButton.getText();
updateDate(Calendar.DAY_OF_MONTH, Integer.parseInt(numberButton.getText()));
ComponentTool.clearButtonGroupSelected(buttonGroup);
numberButton.setSelected(true);
ComponentTool.updateButtonSelectedForeground(buttonGroup, selectedColor);
}
});
if (j == 0 || j == 6) {
numberButton.setNormalForeground(weekendFontColor);
} else {
numberButton.setNormalForeground(dateFontColor);
}
dayButtons[i][j] = numberButton;
centerPanel.add(numberButton);
buttonGroup.add(numberButton);
}
}
return centerPanel;
}
private JPanel createSouthPanel() {
JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 2));
southPanel.setOpaque(false);
JButton todayButton = new RolloverBackgroundButton("今天");
todayButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
today();
}
});
southPanel.add(todayButton);
JButton cancelButton = new RolloverBackgroundButton("取消");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cancel();
}
});
southPanel.add(cancelButton);
JButton confirmButton = new RolloverBackgroundButton("确定");
confirmButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
confirm();
}
});
southPanel.add(confirmButton);
return southPanel;
}
/**
* 显示日期选择对话框
*
* @param owner
* @return
*/
public String showDateDialog(Window owner) {
return showDateDialog(owner, null);
}
public String showDateDialog(Window owner, Point dialogPoint) {
return showDateDialog(owner, dialogPoint, new Dimension(400, 250));
}
/**
* 显示日期选择对话框
*
* @param owner
* @param dialogPoint
* @return
*/
public String showDateDialog(Window owner, Point dialogPoint, Dimension size) {
if (dialog == null) {
dialog = createDialog(owner, size);
}
dialog.setLocationRelativeTo(owner);
if (dialogPoint != null) {
dialog.setLocation(dialogPoint);
}
updateDayButtonsText();
dialog.setVisible(true);
return getDateText();
}
protected JDialog createDialog(Window owner, Dimension size) {
JDialog dialog = new JDialog(owner, "日期时间选择") {
public void setVisible(boolean b) {
if (b) {// 此处先if还是先super顺序很重要
isConfirm = false;
}
super.setVisible(b);
}
};
dialog.setModal(true);
dialog.setSize(size);
dialog.setContentPane(this);
dialog.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
cancel();
}
});
return dialog;
}
/**
* 用户点击取消
*/
protected void cancel() {
isConfirm = false;
dialog.setVisible(false);
}
/**
* 用户点击今天
*/
protected void today() {
date = new Date();
Calendar c = getCalendar();
yearSpinner.setValue(c.get(Calendar.YEAR));
monthSpinner.setValue(c.get(Calendar.MONTH) + 1);
selectedDay = c.get(Calendar.DAY_OF_MONTH) + "";
setDate(c.getTime());
updateDayButtonsText();
}
/**
* 用户点击确定
*/
protected void confirm() {
isConfirm = true;
dialog.setVisible(false);
}
protected void updateDate(int type, int value) {
Calendar c = getCalendar();
if (type == Calendar.MONTH) {// 处理选择的天数超出月份最大的天数情况
int day = c.get(Calendar.DAY_OF_MONTH);
c.set(Calendar.DAY_OF_MONTH, 1);
c.set(type, value);
int maxMonth_to = c.getActualMaximum(Calendar.DAY_OF_MONTH);
if (Integer.parseInt(selectedDay) <= maxMonth_to) {// 如果当前月份所选择的天数小于即将更新的月份的最大天数
c.set(Calendar.DAY_OF_MONTH, day);// 还原天数
} else {// 否则
selectedDay = "1";
}
} else {
c.set(type, value);
}
setDate(c.getTime());
if (type != Calendar.DAY_OF_MONTH) {
updateDayButtonsText();
}
}
protected void updateDayButtonsText() {
Calendar c = getCalendar();
c.set(Calendar.DAY_OF_MONTH, 1);
int maxDayNo = c.getActualMaximum(Calendar.DAY_OF_MONTH);
int dayNo = 2 - c.get(Calendar.DAY_OF_WEEK);
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 7; j++) {
String s = "";
if (dayNo >= 1 && dayNo <= maxDayNo) {
s = String.valueOf(dayNo);
}
dayButtons[i][j].setText(s);
if (s.equals(selectedDay)) {
ComponentTool.clearButtonGroupSelected(buttonGroup);
dayButtons[i][j].setSelected(true);
ComponentTool.updateButtonSelectedForeground(buttonGroup, selectedColor);
}
dayNo++;
}
}
}
public Dimension getDialogSize() {
return dialog.getSize();
}
protected Calendar getCalendar() {
Calendar result = Calendar.getInstance();
result.setTime(getDate());
return result;
}
/**
* 用户是否点击确定
*
* @return
*/
public boolean isConfirm() {
return isConfirm;
}
/**
* 获取选择的时间字符串
*
* @return
*/
public String getDateText() {
return format.format(getDate());
}
/**
* 设置默认的时间
*
* @param date
*/
public void setDate(Date date) {
this.date = date;
}
/**
* 获取选择的时间
*
* @return
*/
public Date getDate() {
return date;
}
//
public static class ComponentTool {
public static void updateButtonSelectedForeground(ButtonGroup buttonGroup, Color selectedColor) {
for (Enumeration<AbstractButton> enumBtn = buttonGroup.getElements(); enumBtn.hasMoreElements();) {
RolloverBackgroundButton button = (RolloverBackgroundButton) enumBtn.nextElement();
if (!button.isSelected()) {
button.setSelectedForeground(null);
} else {
button.setSelectedForeground(selectedColor);
}
button.repaint();
}
}
public static void clearButtonGroupSelected(ButtonGroup buttonGroup) {
for (Enumeration<AbstractButton> button = buttonGroup.getElements(); button.hasMoreElements();) {
button.nextElement().setSelected(false);
}
}
}
/**
* 鼠标悬浮和按下以及选中时能切换背景颜色/边框颜色/前景颜色的Button
*
* @author tang
* @since 2014/8/23
*
*/
public static class RolloverBackgroundButton extends JButton {
protected Color normalBackground;// 默认无状态时背景颜色,此属性父类中已定义(background)
protected Color pressedBackground;// 鼠标按下时背景颜色
protected Color rolloverBackground;// 鼠标悬浮时背景颜色
protected Color selectedBackground;// 选中时背景颜色
protected Color normalBorderColor;// 默认无状态时边框颜色
protected Color pressedBorderColor;// 鼠标按下时边框颜色
protected Color rolloverBorderColor;// 鼠标悬浮时边框颜色
protected Color selectedBorderColor;// 选中时边框颜色
protected Color normalForeground;// 默认时前景颜色
protected Color pressedForeground;// 鼠标按下时前景颜色
protected Color rolloverForeground;// 鼠标悬浮时前景颜色
protected Color selectedForeground;// 选中时前景颜色
{
initRolloverButton();
}
public RolloverBackgroundButton() {
}
public RolloverBackgroundButton(Icon icon) {
super(icon);
}
public RolloverBackgroundButton(String text, Icon icon) {
super(text, icon);
}
public RolloverBackgroundButton(String text) {
super(text);
}
public RolloverBackgroundButton(Action a) {
super(a);
}
private void initRolloverButton() {
setRolloverEnabled(true);
setBorderPainted(false);
setContentAreaFilled(false);
setFocusPainted(false);
setFont(new Font(Font.DIALOG, Font.PLAIN, 14));
setNormalBackground(new Color(216, 216, 216));
setPressedBackground(new Color(216, 216, 216, 100));
setNormalBorderColor(new Color(174, 174, 174));
setRolloverBorderColor(new Color(95, 205, 245));
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Paint oldPaint = g2d.getPaint();
if (isSelected() && selectedBackground != null) {// 选中时
g2d.setPaint(selectedBackground);
g2d.fillRect(0, 0, getWidth(), getHeight());// 背景
} else if (getModel().isPressed() && pressedBackground != null) {// 鼠标按下时
g2d.setPaint(pressedBackground);
g2d.fillRect(0, 0, getWidth(), getHeight());// 背景
} else if (getModel().isRollover() && rolloverBackground != null) {// 鼠标悬浮时
g2d.setPaint(rolloverBackground);
g2d.fillRect(0, 0, getWidth(), getHeight());// 背景
} else if (normalBackground != null) {// 默认无状态时
g2d.setPaint(normalBackground);
g2d.fillRect(0, 0, getWidth(), getHeight());// 背景
}
g2d.setPaint(oldPaint);
if (isSelected() && selectedForeground != null) {// 选中时
setForeground(selectedForeground);
} else if (getModel().isPressed() && pressedForeground != null) {// 鼠标按下时
setForeground(pressedForeground);
} else if (getModel().isRollover() && rolloverForeground != null) {// 鼠标悬浮时
setForeground(rolloverForeground);
} else if (normalForeground != null) {// 默认无状态时
setForeground(normalForeground);
}
super.paint(g2d);
if (isSelected() && selectedBorderColor != null) {// 选中时
g2d.setPaint(selectedBorderColor);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);// 边框
} else if (getModel().isPressed() && pressedBorderColor != null) {// 鼠标按下时
g2d.setPaint(pressedBorderColor);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);// 边框
} else if (getModel().isRollover() && rolloverBorderColor != null) {// 鼠标悬浮时
g2d.setPaint(rolloverBorderColor);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);// 边框
} else if (normalBorderColor != null) {// 默认无状态时
g2d.setPaint(normalBorderColor);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);// 边框
}
g2d.setPaint(oldPaint);
}
/**
* 清空设置的默认属性值:<br>
*
* setNormalBackground(null);<br>
* setPressedBackground(null); <br>
* setNormalBorderColor(null); <br>
* setRolloverBorderColor(null);
*
*/
public void clearDefaultAttribute() {
setNormalBackground(null);
setPressedBackground(null);
setNormalBorderColor(null);
setRolloverBorderColor(null);
}
public Color getNormalBackground() {
return normalBackground;
}
public void setNormalBackground(Color normalBackground) {
this.normalBackground = normalBackground;
}
public Color getPressedBackground() {
return pressedBackground;
}
public void setPressedBackground(Color pressedBackground) {
this.pressedBackground = pressedBackground;
}
public Color getRolloverBackground() {
return rolloverBackground;
}
public void setRolloverBackground(Color rolloverBackground) {
this.rolloverBackground = rolloverBackground;
}
public Color getNormalBorderColor() {
return normalBorderColor;
}
public void setNormalBorderColor(Color normalBorderColor) {
this.normalBorderColor = normalBorderColor;
}
public Color getPressedBorderColor() {
return pressedBorderColor;
}
public void setPressedBorderColor(Color pressedBorderColor) {
this.pressedBorderColor = pressedBorderColor;
}
public Color getRolloverBorderColor() {
return rolloverBorderColor;
}
public void setRolloverBorderColor(Color rolloverBorderColor) {
this.rolloverBorderColor = rolloverBorderColor;
}
public Color getPressedForeground() {
return pressedForeground;
}
public void setPressedForeground(Color pressedForeground) {
this.pressedForeground = pressedForeground;
}
public Color getRolloverForeground() {
return rolloverForeground;
}
public void setRolloverForeground(Color rolloverForeground) {
this.rolloverForeground = rolloverForeground;
}
public Color getNormalForeground() {
return normalForeground;
}
public void setNormalForeground(Color normalForeground) {
this.normalForeground = normalForeground;
}
public Color getSelectedBackground() {
return selectedBackground;
}
public void setSelectedBackground(Color selectedBackground) {
this.selectedBackground = selectedBackground;
}
public Color getSelectedBorderColor() {
return selectedBorderColor;
}
public void setSelectedBorderColor(Color selectedBorderColor) {
this.selectedBorderColor = selectedBorderColor;
}
public Color getSelectedForeground() {
return selectedForeground;
}
public void setSelectedForeground(Color selectedForeground) {
this.selectedForeground = selectedForeground;
}
}
}
运行效果图:
可以根据不同需要自行修改各种样式。