java图形界面的时间控件

JDateChooser是一个模仿Windows日期和时间属性对话框的Java图形界面组件,包含月份、年份选择,日期网格和时间选择。用户可以方便地设置和获取日期及时间,并提供了显示对话框供用户选择日期的静态方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package kobe.util;

import javax.swing.*;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Date;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.event.*;

/**
 * 日期时间选择对话框,模仿Windows日期和时间属性对话框
 * @see #showDialog(java.awt.Component, String, java.util.Calendar)
 */
public class JDateChooser extends JPanel implements ChangeListener, ItemListener {

  private JComboBox month = new JComboBox(new String[]{"一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"});
  private JSpinner year = new JSpinner(new SpinnerNumberModel(1, 1, 9999, 1));
  private DateGrid dateGrid = new DateGrid();
  private JSpinner time = new JSpinner(new SpinnerDateModel());

  public JDateChooser(Calendar initialDate) {
    this.setBackground(Color.white);
    this.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
    this.setLayout(new GridLayout(1, 2, 5, 10));
    JPanel p1 = new JPanel();
    p1.setBackground(Color.white);
    p1.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("日期"), BorderFactory.createEmptyBorder(5, 5, 10, 5)));
    p1.setLayout(new BorderLayout(10, 10));
    JPanel p11 = new JPanel(new GridLayout(1, 2, 10, 10));
    p11.setBackground(Color.white);
    p11.add(month);
    month.addItemListener(this);
    month.setPreferredSize(new Dimension(0, 20));
    p11.add(year);
    year.setEditor(new JSpinner.NumberEditor(year, "0"));
    year.addChangeListener(this);
    year.setPreferredSize(new Dimension(0, 20));
    p1.add(p11, BorderLayout.NORTH);
    p1.add(dateGrid);
    this.add(p1);
    JPanel p2 = new JPanel(new BorderLayout(10, 10));
    p2.setBackground(Color.white);
    p2.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("时间"), BorderFactory.createEmptyBorder(0, 10, 10, 10)));
    time.setPreferredSize(new Dimension(0, 20));
    JSpinner.DateEditor editor = new JSpinner.DateEditor(time, "HH:mm:ss");
    editor.getTextField().setHorizontalAlignment(JTextField.RIGHT);
    time.setEditor(editor);
    JPanel p = new JPanel();
    p.setBackground(Color.white);
    time.setPreferredSize(new Dimension(100, 20));
    p.add(time);
    p2.add(p, BorderLayout.SOUTH);
    p2.add(new Clock(time));
    this.add(p2);
    setCalendar(initialDate);
    setPreferredSize(new Dimension(369, 200));
  }

  /**
   * 设置日期和时间
   * @param calendar 日期和时间
   */
  public void setCalendar(Calendar calendar) {
    if(calendar==null) calendar = new GregorianCalendar();
    month.setSelectedIndex(calendar.get(Calendar.MONTH));
    year.setValue(calendar.get(Calendar.YEAR));
    int year = (Integer)this.year.getValue();
    int month = this.month.getSelectedIndex()+1;
    dateGrid.set(year, month);
    dateGrid.setDay(calendar.get(Calendar.DAY_OF_MONTH));
    time.setValue(calendar.getTime());
  }

  /**
   * 获得日期和时间
   * @return 日期和时间
   */
  public Calendar getCalendar() {
    int year = (Integer)this.year.getValue();
    int month = this.month.getSelectedIndex();
    int day = dateGrid.getDay();
    Calendar c = Calendar.getInstance();
    Date date = (Date) time.getValue();
    c.setTime(date);
    c.set(year, month, day);
    return c;
  }

  /**
   * 显示对话框以选择日期,使用方法同JColorChooser.showDialog
   * @param c 父级组件
   * @param title 对话框标题
   * @param initialDate 初始化日期和时间
   * @return 选择的日期,null为取消选择
   */
  public static Calendar showDialog(Component c, String title, Calendar initialDate) {
    Window window = c==null?JOptionPane.getRootFrame():SwingUtilities.windowForComponent(c);
    JDialog dlg;
    if(window instanceof Frame) dlg = new JDialog((Frame)window, title, true);
    else dlg = new JDialog((Dialog)window, title, true);
    JDateChooser dc = new JDateChooser(initialDate);
    ActionHandler actionHandler = new ActionHandler(dc);
    JPanel p = new JPanel(new BorderLayout());
    p.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(6, 6, 0, 6), BorderFactory.createEtchedBorder()));
    p.add(dc);
    dlg.add(p);
    p = new JPanel(new FlowLayout(FlowLayout.RIGHT));
    dlg.add(p, BorderLayout.SOUTH);
    JButton btOk = new JButton("确定");
    btOk.addActionListener(actionHandler);
    dlg.getRootPane().setDefaultButton(btOk);
    p.add(btOk);
    JButton btCancel = new JButton("取消");
    btCancel.addActionListener(actionHandler);
    p.add(btCancel);
    dlg.pack();
    dlg.setLocationRelativeTo(window);
    dlg.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
    dlg.addWindowListener(actionHandler);
    dlg.setVisible(true);
    return actionHandler.getCalendar();
  }

  public void stateChanged(ChangeEvent e) {
    dateGrid.set((Integer)year.getValue(), month.getSelectedIndex()+1);
  }

  public void itemStateChanged(ItemEvent e) {
    dateGrid.set((Integer)year.getValue(), month.getSelectedIndex()+1);
  }

  private static class ActionHandler extends WindowAdapter implements ActionListener {

    private JDateChooser dc;

    public ActionHandler(JDateChooser dc) {
      this.dc = dc;
    }

    public void windowClosing(WindowEvent e) {
      actionPerformed(new ActionEvent(this, 0, "取消"));
    }

    public void actionPerformed(ActionEvent e) {
      JDialog dlg = (JDialog) SwingUtilities.windowForComponent(dc);
      dlg.dispose();
      if("取消".equals(e.getActionCommand())) {
        dc = null;
      }
    }

    public Calendar getCalendar() {
      return dc==null?null:dc.getCalendar();
    }
  }

  private static class DateGrid extends JPanel implements MouseListener {

    JLabel[][] lbs = new JLabel[7][7];

    int year = 1, month = 1, day = 1;

    public DateGrid() {
      super(new GridLayout(7, 7));
      this.setBackground(Color.white);
      Color blue = new Color(140, 150, 255);
      Color white = new Color(220, 220, 255);
      for(int i=0; i<7; i++) {
        for(int j=0; j<7; j++) {
          this.add(lbs[i][j] = new JLabel((String)null));
          lbs[i][j].setOpaque(true);
          lbs[i][j].setHorizontalAlignment(JLabel.CENTER);
          lbs[i][j].setBackground(Color.white);
          if(i>0) {
            lbs[i][j].addMouseListener(this);
          } else {
            lbs[0][j].setBackground(blue);
            lbs[0][j].setForeground(white);
          }
        }
      }
      lbs[0][0].setText("日");
      lbs[0][1].setText("一");
      lbs[0][2].setText("二");
      lbs[0][3].setText("三");
      lbs[0][4].setText("四");
      lbs[0][5].setText("五");
      lbs[0][6].setText("六");
      this.setBorder(BorderFactory.createLoweredBevelBorder());
    }

    public void setDay(int day) {
      if(day<1) day = 1;
      int days = maxDay(year, month);
      if(day>days) day = days;
      this.day = day;
      int d = 0;
      for(int i=1; i<7; i++) {
        for(int j=0; j<7; j++) {
          if(lbs[i][j].getText()!=null) {
            if(++d==day) {
              lbs[i][j].setBackground(Color.blue);
              lbs[i][j].setForeground(Color.white);
              continue;
            }
          }
          lbs[i][j].setBackground(Color.white);
          lbs[i][j].setForeground(Color.black);
        }
      }
      repaint();
    }

    public int getDay() {
      return day;
    }

    public void set(int year, int month) {
      if(year<1) year = 1;
      else if(year>9999) year = 9999;
      if(month<1) month = 1;
      else if(month>12) month = 12;
      //计算当月一号星期几 本可以用Calendar现成的功能,只是好玩,自己写了个算法
      int pastdays = (year-1)*365 + (year-1)/4 - (year-1)/100;
      pastdays += (month-1)*31;
      pastdays -= (month-1)/2;
      if(month>=9&&month%2==1) pastdays += 1;
      if(month>2) {
        pastdays -= 2;
        if((year%4==0)&&(year%400!=0)) pastdays += 1;
      }
      int dayInWeak = pastdays%7-1;
      if(dayInWeak==-1) dayInWeak = 6;
      //~
      for(int i=1; i<7; i++) {
        for(int j=0; j<7; j++) {
          lbs[i][j].setText(null);
        }
      }
      int days = maxDay(year, month);
      for(int i=1; i<=days; i++) {
        lbs[1+(dayInWeak+i-1)/7][(dayInWeak+i-1)%7].setText(String.valueOf(i));
      }
      this.year = year;
      this.month = month;
      setDay(day);
    }

    private int maxDay(int year, int month) {
      int days = (month%2==(month>7?0:1))?31:30;
      if(month==2) days = (year%4==0&&year%400!=0)?29:28;
      return days;
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
      Object o = e.getSource();
      JLabel lb = null;
      for(int i=1; i<7; i++) {
        for(int j=0; j<7; j++) {
          JLabel b = lbs[i][j];
          if(b==o&&b.getText()!=null) {
            lb = b;
            break;
          }
        }
      }
      if(lb==null) return;
      int d = 0;
      for(int i=1; i<7; i++) {
        for(int j=0; j<7; j++) {
          if(lbs[i][j].getText()!=null) {
            d++;
            if(lbs[i][j]==lb) {
              setDay(d);
              return;
            }
          }
        }
      }
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }
  }

  private static class Clock extends JComponent implements ChangeListener {

    Calendar c;
    int[] xs = new int[4];
    int[] ys = new int[4];
    static final Color handColor = new Color(24, 116, 109);

    public Clock(JSpinner time) {
      time.addChangeListener(this);
      stateChanged(new ChangeEvent(time));
    }

    public void stateChanged(ChangeEvent e) {
      JSpinner sp = (JSpinner) e.getSource();
      Date date = (Date) sp.getValue();
      if(c==null) c = Calendar.getInstance();
      c.setTime(date);
      repaint();
    }

    protected void paintComponent(Graphics g) {
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      float ox = getWidth()/2f;
      float oy = getHeight()/2f;
      final float R = 60f;
      Ellipse2D.Float oval = new Ellipse2D.Float();
      for(int i=0; i<360; i+=360/12/5) {
        float a = i/360f*(float)Math.PI*2;
        float dx = (float)Math.sin(a)*R;
        float dy = (float)Math.cos(a)*R;
        g2.setColor(i%(360/12)==0?Color.black:Color.lightGray);
        oval.setFrame(ox-dx-1f, oy-dy-1f, 2, 2);
        g2.fill(oval);
        if(i%(360/12)==0) {
          g2.setColor(Color.cyan);
          oval.setFrame(ox+dx-2f, oy+dy-1f, 2, 2);
          g2.fill(oval);
        }
      }
      int hour = c.get(Calendar.HOUR);
      int minute = c.get(Calendar.MINUTE);
      int second = c.get(Calendar.SECOND);
      float ha = (float)Math.PI * 2 / 12 *(hour + (float)minute/60);
      float ma = (float)Math.PI * 2/60 *(minute + (float)second/60);
      float sa = (float)Math.PI * 2/60 * second;
      g2.setColor(Color.lightGray);
      g2.translate(1, 1);
      drawHand(g2, ox, oy, ha, 40);
      g2.translate(1, 1);
      drawHand(g2, ox, oy, ma, 48);
      g2.translate(1, 1);
      drawHand(g2, ox, oy, sa, 50, false);
      g2.translate(-3, -3);
      g2.setColor(handColor);
      drawHand(g2, ox, oy, ha, 40);
      drawHand(g2, ox, oy, ma, 48);
      g2.setColor(Color.black);
      drawHand(g2, ox, oy, sa, 50, false);
    }

    private void drawHand(Graphics2D g2, float ox, float oy, float a, float len, boolean w) {
      xs[2] = (int) (ox + (float)Math.sin(a)*len);
      ys[2] = (int) (oy - (float)Math.cos(a)*len);
      xs[0] = (int) (ox + (float)Math.sin(a+Math.PI)*10);
      ys[0] = (int) (oy - (float)Math.cos(a+Math.PI)*10);
      if(w) {
        xs[1] = (int) (ox + (float)Math.sin(a+Math.PI/2)*3);
        ys[1] = (int) (oy - (float)Math.cos(a+Math.PI/2)*3);
        xs[3] = (int) (ox + (float)Math.sin(a+Math.PI*3/2)*3);
        ys[3] = (int) (oy - (float)Math.cos(a+Math.PI*3/2)*3);
        g2.fillPolygon(xs, ys, 4);
      } else {
        Line2D.Float line = new Line2D.Float(xs[0], ys[0], xs[2], ys[2]);
        g2.draw(line);
      }
    }

    private void drawHand(Graphics2D g2, float ox, float oy, float a, float len) {
      this.drawHand(g2, ox, oy, a, len, true);
    }
  }
}

 

import kobe.util.JDateChooser;

import javax.swing.*;
import java.util.Calendar;

public class Test {
  public static void main(String[] args) throws Exception {
    UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
    Calendar c = JDateChooser.showDialog(null, "请选择日期", null);
    if(c==null) JOptionPane.showMessageDialog(null, "你没有选择时间");
    else JOptionPane.showMessageDialog(null, "你选择的时间是" + c.getTime());
  }
}

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值