这是我改写的网上的DateChooser代码后的作品,使用效果如图所示。用法参考备注,以及Main函数中用法。
/** * * Copyright: Ares. * All Rights Reserved. * Company: Insigma HT/上海创图 * @author Ares <a href="mailto:[email protected]>send email</a> * @date 2013-11-17 16:53 * * Revision History * * Date Programmer Notes * --------- --------------------- -------------------------------------------- * 2013-11-17 Ares initial * 2014-09-16 Ares fix bug @n3k123 * * 1. you can change date format by parameter. * 2. you can change week label content by showTEXT. * 3. you can change dayOfWeek order by defaultStartDAY. */ package com.swing.test; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.Point; import java.awt.Polygon; import java.awt.Stroke; import java.awt.Toolkit; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.PopupFactory; import javax.swing.SwingUtilities; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; /** * @author Ares * @Describe(Date Chooser class) */ public class Chooser extends JPanel{ private static final long serialVersionUID = -5384012731547358720L; private Calendar calendar; private Calendar now = Calendar.getInstance(); private JPanel calendarPanel; private java.awt.Font font = new java.awt.Font("Times",java.awt.Font.PLAIN,12); private java.text.SimpleDateFormat sdf; private final LabelManager lm = new LabelManager(); private javax.swing.Popup pop; private TitlePanel titlePanel; private BodyPanel bodyPanel; private FooterPanel footerPanel; private JComponent showDate; private boolean isShow = false; private static final String DEFAULTFORMAT = "yyyy-MM-dd"; private static final String[] showTEXT = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; private static WeekLabel[] weekLabels = new WeekLabel[7]; private static int defaultStartDAY = 0;//0 is from Sun, 1 is from Mon, 2 is from Tue private static Color hoverColor = Color.BLUE; // hover color private Chooser(java.util.Date date, String format, int startDAY){ if(startDAY > -1 && startDAY < 7) defaultStartDAY = startDAY; int dayIndex = defaultStartDAY; for(int i=0; i<7; i++){ if(dayIndex > 6) dayIndex = 0; weekLabels[i] = new WeekLabel(dayIndex, showTEXT[dayIndex]); dayIndex ++ ; } sdf = new java.text.SimpleDateFormat(format); calendar = Calendar.getInstance(); calendar.setTime(date); initCalendarPanel(); } public static Chooser getInstance(java.util.Date date, String format){ return new Chooser(date, format, defaultStartDAY); } public static Chooser getInstance(java.util.Date date){ return getInstance(date, DEFAULTFORMAT); } public static Chooser getInstance(String format){ return getInstance(new java.util.Date(), format); } public static Chooser getInstance(){ return getInstance(new java.util.Date(), DEFAULTFORMAT); } private void initCalendarPanel(){ calendarPanel = new JPanel(new java.awt.BorderLayout()); calendarPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0xAA, 0xAA, 0xAA))); calendarPanel.add(titlePanel = new TitlePanel(), java.awt.BorderLayout.NORTH); calendarPanel.add(bodyPanel = new BodyPanel(), java.awt.BorderLayout.CENTER); calendarPanel.add(footerPanel = new FooterPanel(),java.awt.BorderLayout.SOUTH); this.addAncestorListener(new AncestorListener() { public void ancestorAdded(AncestorEvent event) { } public void ancestorRemoved(AncestorEvent event) {hidePanel();} //hide pop when move component. public void ancestorMoved(AncestorEvent event) { hidePanel(); } }); } public void register(final JComponent showComponent) { this.showDate = showComponent; showComponent.setRequestFocusEnabled(true); showComponent.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent me) { showComponent.requestFocusInWindow(); } }); this.add(showComponent, BorderLayout.CENTER); this.setPreferredSize(new Dimension(90, 25)); this.setBorder(BorderFactory.createLineBorder(Color.GRAY)); showComponent.addMouseListener(new MouseAdapter() { public void mouseEntered(MouseEvent me) { if (showComponent.isEnabled()) { showComponent.setCursor(new Cursor(Cursor.HAND_CURSOR)); } } public void mouseExited(MouseEvent me) { if (showComponent.isEnabled()) { showComponent.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); showComponent.setForeground(Color.BLACK); } } public void mousePressed(MouseEvent me) { if (showComponent.isEnabled()) { showComponent.setForeground(hoverColor); if (isShow) { hidePanel(); } else { showPanel(showComponent); } } } public void mouseReleased(MouseEvent me) { if (showComponent.isEnabled()) { showComponent.setForeground(Color.BLACK); } } }); showComponent.addFocusListener(new FocusListener() { public void focusLost(FocusEvent e) { hidePanel(); } public void focusGained(FocusEvent e) { } }); } //hide the main panel. private void hidePanel() { if (pop != null) { isShow = false; pop.hide(); pop = null; } } //show the main panel. private void showPanel(Component owner) { if (pop != null) pop.hide(); Point show = new Point(0, showDate.getHeight()); SwingUtilities.convertPointToScreen(show, showDate); Dimension size = Toolkit.getDefaultToolkit().getScreenSize(); int x = show.x; int y = show.y; if (x < 0) x = 0; if (x > size.width - 212) x = size.width - 212; if (y > size.height - 167) y -= 165; pop = PopupFactory.getSharedInstance().getPopup(owner, calendarPanel, x, y); pop.show(); isShow = true; } // change text or label's content. private void commit() { if (showDate instanceof JTextField) { ((JTextField) showDate).setText(sdf.format(calendar.getTime())); }else if (showDate instanceof JLabel) { ((JLabel) showDate).setText(sdf.format(calendar.getTime())); } hidePanel(); } // control panel private class TitlePanel extends JPanel { private static final long serialVersionUID = -2865282186037420798L; private JLabel preYear,preMonth,center,nextMonth,nextYear,centercontainer; public TitlePanel(){ super(new java.awt.BorderLayout()); this.setBackground(new java.awt.Color(190, 200, 200)); initTitlePanel(); } private void initTitlePanel(){ preYear = new JLabel("<<", JLabel.CENTER); preMonth = new JLabel("<", JLabel.CENTER); center = new JLabel("", JLabel.CENTER); centercontainer = new JLabel("", JLabel.CENTER); nextMonth = new JLabel(">", JLabel.CENTER); nextYear = new JLabel(">>", JLabel.CENTER); preYear.setToolTipText("Last Year"); preMonth.setToolTipText("Last Month"); nextMonth.setToolTipText("Next Month"); nextYear.setToolTipText("Next Year"); preYear.setBorder(javax.swing.BorderFactory.createEmptyBorder(2, 10, 0, 0)); preMonth.setBorder(javax.swing.BorderFactory.createEmptyBorder(2, 15, 0, 0)); nextMonth.setBorder(javax.swing.BorderFactory.createEmptyBorder(2, 0, 0, 15)); nextYear.setBorder(javax.swing.BorderFactory.createEmptyBorder(2, 0, 0, 10)); centercontainer.setLayout(new java.awt.BorderLayout()); centercontainer.add(preMonth,java.awt.BorderLayout.WEST); centercontainer.add(center,java.awt.BorderLayout.CENTER); centercontainer.add(nextMonth,java.awt.BorderLayout.EAST); this.add(preYear,java.awt.BorderLayout.WEST); this.add(centercontainer,java.awt.BorderLayout.CENTER); this.add(nextYear,java.awt.BorderLayout.EAST); this.setPreferredSize(new java.awt.Dimension(210, 25)); updateDate(); preYear.addMouseListener(new MyMouseAdapter(preYear, Calendar.YEAR, -1)); preMonth.addMouseListener(new MyMouseAdapter(preMonth, Calendar.MONTH, -1)); nextMonth.addMouseListener(new MyMouseAdapter(nextMonth, Calendar.MONTH, 1)); nextYear.addMouseListener(new MyMouseAdapter(nextYear, Calendar.YEAR, 1)); } private void updateDate() { center.setText(calendar.get(Calendar.YEAR)+"-"+(calendar.get(Calendar.MONTH) + 1)); } // listener for control label. class MyMouseAdapter extends java.awt.event.MouseAdapter{ JLabel label; private int type, value; public MyMouseAdapter(final JLabel label, final int type, final int value){ this.label = label; this.type = type; this.value = value; } public void mouseEntered(java.awt.event.MouseEvent me) { label.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); label.setForeground(hoverColor); } public void mouseExited(java.awt.event.MouseEvent me) { label.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); label.setForeground(java.awt.Color.BLACK); } public void mousePressed(java.awt.event.MouseEvent me) { calendar.add(type, value); label.setForeground(java.awt.Color.WHITE); refresh(); } public void mouseReleased(java.awt.event.MouseEvent me) { label.setForeground(java.awt.Color.BLACK); } } } // body panel, include week labels and day labels. private class BodyPanel extends JPanel { private static final long serialVersionUID = 5677718768457235447L; public BodyPanel(){ super(new GridLayout(7, 7)); this.setPreferredSize(new java.awt.Dimension(210, 140)); initMonthPanel(); } private void initMonthPanel(){ updateDate(); } public void updateDate() { this.removeAll(); lm.clear(); java.util.Date temp = calendar.getTime(); Calendar cal = Calendar.getInstance(); cal.setTime(temp); cal.set(Calendar.DAY_OF_MONTH, 1); int index = cal.get(Calendar.DAY_OF_WEEK); // 从当月1号前移,一直移动到面板显示的第一天的前一天;当-index + defaultStartDAY为正数时,为避免面板从当月1号之后开始显示,需要前移一周,确保当月显示完全 if(index > defaultStartDAY) cal.add(Calendar.DAY_OF_MONTH, -index + defaultStartDAY); else cal.add(Calendar.DAY_OF_MONTH, -index + defaultStartDAY - 7); for (WeekLabel weekLabel : weekLabels) { this.add(weekLabel); } for (int i = 0; i < 42; i++) { cal.add(Calendar.DAY_OF_MONTH, 1); lm.addLabel(new DayLabel(cal)); } for (DayLabel my : lm.getLabels()) { this.add(my); } } } private class FooterPanel extends JPanel { private static final long serialVersionUID = 8135037333899746736L; private JLabel dateLabel; public FooterPanel(){ super(new BorderLayout()); initFooterPanel(); } private void initFooterPanel(){ dateLabel = new JLabel("Today is : "+sdf.format(new java.util.Date())); dateLabel.addMouseListener(new MouseListener() { @Override public void mouseReleased(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) { calendar.setTime(new Date()); refresh(); commit(); } @Override public void mouseExited(MouseEvent e) { dateLabel.setForeground(Color.BLACK); } @Override public void mouseEntered(MouseEvent e) { dateLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); dateLabel.setForeground(hoverColor); } @Override public void mouseClicked(MouseEvent e) {} }); this.add(dateLabel); } public void updateDate(){}; } //refresh all panel private void refresh() { titlePanel.updateDate(); bodyPanel.updateDate(); footerPanel.updateDate(); SwingUtilities.updateComponentTreeUI(this); } private class WeekLabel extends JLabel { private static final long serialVersionUID = -8053965084432740110L; private String name; public WeekLabel(int index, String name){ super(name, JLabel.CENTER); this.name = name; } public String toString(){ return name; } } private class DayLabel extends JLabel implements java.util.Comparator<DayLabel>, java.awt.event.MouseListener, java.awt.event.MouseMotionListener { private static final long serialVersionUID = -6002103678554799020L; private boolean isSelected; private int year, month, day; public DayLabel(Calendar cal){ super(""+cal.get(Calendar.DAY_OF_MONTH), JLabel.CENTER); this.year = cal.get(Calendar.YEAR); this.month = cal.get(Calendar.MONTH); this.day = cal.get(Calendar.DAY_OF_MONTH); this.setFont(font); this.addMouseListener(this); this.addMouseMotionListener(this); if(month == calendar.get(Calendar.MONTH)) this.setForeground(java.awt.Color.BLACK); else this.setForeground(java.awt.Color.LIGHT_GRAY); } public boolean getIsSelected() { return isSelected; } public void setSelected(boolean b, boolean isDrag) { isSelected = b; if (b && !isDrag) { int temp = calendar.get(Calendar.MONTH); calendar.set(year, month, day); if (temp == month) { SwingUtilities.updateComponentTreeUI(bodyPanel); } else { refresh(); } this.repaint(); } } @Override protected void paintComponent(Graphics g) { //set curr select day's background if(day == calendar.get(Calendar.DAY_OF_MONTH) && month == calendar.get(Calendar.MONTH)){ g.setColor(new java.awt.Color(0xBB, 0xBF, 0xDA)); g.fillRect(0, 0, getWidth(), getHeight()); } //set current day's border if(year == now.get(Calendar.YEAR) && month == now.get(Calendar.MONTH) && day == now.get(Calendar.DAY_OF_MONTH)){ Graphics2D gd = (Graphics2D) g; gd.setColor(new java.awt.Color(0x55, 0x55, 0x88)); Polygon p = new Polygon(); p.addPoint(0, 0); p.addPoint(getWidth() - 1, 0); p.addPoint(getWidth() - 1, getHeight() - 1); p.addPoint(0, getHeight() - 1); gd.drawPolygon(p); } if (isSelected){ Stroke s = new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL, 1.0f, new float[] { 2.0f, 2.0f }, 1.0f); Graphics2D gd = (Graphics2D) g; gd.setStroke(s); gd.setColor(Color.BLACK); Polygon p = new Polygon(); p.addPoint(0, 0); p.addPoint(getWidth() - 1, 0); p.addPoint(getWidth() - 1, getHeight() - 1); p.addPoint(0, getHeight() - 1); gd.drawPolygon(p); } super.paintComponent(g); } public boolean contains(Point p) { return this.getBounds().contains(p); } private void update() { repaint(); } @Override public void mouseDragged(MouseEvent e) { } @Override public void mouseMoved(MouseEvent e) { } @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { isSelected = true; update(); } @Override public void mouseReleased(MouseEvent e) { Point p = SwingUtilities.convertPoint(this, e.getPoint(), bodyPanel); this.setForeground(Color.BLACK); lm.setSelect(p, false); commit(); } @Override // change color when mouse over. public void mouseEntered(MouseEvent e) { this.setForeground(hoverColor); this.repaint(); } @Override // change color when mouse exit. public void mouseExited(MouseEvent e) { if(month == calendar.get(Calendar.MONTH)) this.setForeground(java.awt.Color.BLACK); else this.setForeground(java.awt.Color.LIGHT_GRAY); this.repaint(); } @Override public int compare(DayLabel o1, DayLabel o2) { Calendar c1 = Calendar.getInstance(); c1.set(o1.year, o1.month, o1.day); Calendar c2 = Calendar.getInstance(); c2.set(o2.year, o2.month, o2.day); return c1.compareTo(c2); } } private class LabelManager { private List<DayLabel> list; public LabelManager(){ list = new ArrayList<Chooser.DayLabel>(); } public List<DayLabel> getLabels(){ return list; } public void addLabel(DayLabel label){ list.add(label); } public void clear() { list.clear(); } public void setSelect(Point p, boolean b) { //如果是拖动,则要优化一下,以提高效率 if (b) { //表示是否能返回,不用比较完所有的标签,能返回的标志就是把上一个标签和 //将要显示的标签找到了就可以了 boolean findPrevious = false, findNext = false; for (DayLabel lab : list) { if (lab.contains(p)) { findNext = true; if (lab.getIsSelected()) findPrevious = true; else lab.setSelected(true, b); } else if (lab.getIsSelected()) { findPrevious = true; lab.setSelected(false, b); } if (findPrevious && findNext) return; } }else { DayLabel temp = null; for (DayLabel m : list) { if (m.contains(p)) { temp = m; } else if (m.getIsSelected()) { m.setSelected(false, b); } } if (temp != null) temp.setSelected(true, b); } } } /** * @param args */ public static void main(String[] args) { JFrame jf = new JFrame("Date Picker Test"); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.setLayout(null); jf.setBounds(400, 200, 600, 400); Chooser ser = Chooser.getInstance(); javax.swing.JTextField text = new JTextField(); text.setBounds(10, 10, 200, 30); text.setText("2013-10-11"); ser.register(text); Chooser ser2 = Chooser.getInstance("yyyy年MM月dd日"); JLabel label = new JLabel("please click me."); label.setBounds(10, 50, 200, 30); ser2.register(label); jf.add(text); jf.add(label); jf.setVisible(true); } }