杰瑞科技汇

Java Swing日期控件如何选择与使用?

在 Java Swing 中,没有像 HTML5 <input type="date"> 那样功能单一、开箱即用的原生日期选择器控件,Swing 提供了非常灵活和强大的基础组件,我们可以通过组合它们来创建功能丰富的日期控件,Java 也提供了官方的 JXDatePicker,它属于 Swing 的一个扩展库。

Java Swing日期控件如何选择与使用?-图1
(图片来源网络,侵删)

下面我将从三个方面详细介绍 Java Swing 的日期控件:

  1. 手动组合基础组件(最灵活,但代码量稍多)
  2. 使用第三方库 JXDatePicker(最推荐,简单易用)
  3. 使用 Java 8+ 的 java.time API(现代、标准的日期时间处理)

手动组合基础组件 (JTextField + JButton + JDialog)

这是最经典、最灵活的方法,我们可以创建一个包含一个文本框和一个按钮的面板,点击按钮时,弹出一个模态对话框,对话框内部包含一个日历,用户选择日期后,日期会自动填充到文本框中,并关闭对话框。

创建一个自定义的 DatePicker 组件

我们将把这个逻辑封装到一个可重用的 JPanel 中。

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class CustomDatePicker extends JPanel {
    private final JTextField textField;
    private final JButton button;
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    public CustomDatePicker() {
        setLayout(new BorderLayout(5, 0));
        // 文本框
        textField = new JTextField(15);
        textField.setEditable(false); // 用户不能直接输入,只能通过按钮选择
        // 按钮
        button = new JButton("选择日期");
        button.addActionListener(e -> showDatePickerDialog());
        this.add(textField, BorderLayout.CENTER);
        this.add(button, BorderLayout.EAST);
    }
    private void showDatePickerDialog() {
        // 获取当前日期作为日历的初始值
        Calendar calendar = Calendar.getInstance();
        Date initialDate = calendar.getTime();
        // 创建日期选择器对话框
        JDialog dialog = new JDialog((Frame) SwingUtilities.getWindowAncestor(this), "选择日期", true);
        dialog.setLayout(new BorderLayout());
        // 使用 JSpinner 来选择日期
        // JSpinner 可以方便地处理日期的增加和减少
        SpinnerDateModel model = new SpinnerDateModel(initialDate, null, null, Calendar.DAY_OF_MONTH);
        JSpinner spinner = new JSpinner(model);
        spinner.setEditor(new JSpinner.DateEditor(spinner, "yyyy-MM-dd"));
        // 添加确定和取消按钮
        JPanel buttonPanel = new JPanel();
        JButton okButton = new JButton("确定");
        JButton cancelButton = new JButton("取消");
        okButton.addActionListener(e -> {
            Date selectedDate = (Date) spinner.getValue();
            textField.setText(dateFormat.format(selectedDate));
            dialog.dispose();
        });
        cancelButton.addActionListener(e -> dialog.dispose());
        buttonPanel.add(okButton);
        buttonPanel.add(cancelButton);
        dialog.add(spinner, BorderLayout.CENTER);
        dialog.add(buttonPanel, BorderLayout.SOUTH);
        dialog.pack();
        dialog.setLocationRelativeTo(this); // 居中显示
        dialog.setVisible(true);
    }
    // 获取用户选择的日期
    public Date getSelectedDate() {
        String dateStr = textField.getText();
        try {
            return dateFormat.parse(dateStr);
        } catch (Exception e) {
            return null; // 或者返回当前日期/空
        }
    }
    // 获取日期的字符串表示
    public String getSelectedDateAsString() {
        return textField.getText();
    }
}

如何使用这个自定义组件

import javax.swing.*;
import java.awt.*;
public class MainApplication {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("自定义日期选择器示例");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(400, 200);
            frame.setLayout(new FlowLayout());
            // 创建并添加我们的自定义日期选择器
            CustomDatePicker datePicker = new CustomDatePicker();
            frame.add(datePicker);
            // 添加一个按钮来获取选中的日期
            JButton getButton = new JButton("获取日期");
            getButton.addActionListener(e -> {
                Date selectedDate = datePicker.getSelectedDate();
                if (selectedDate != null) {
                    JOptionPane.showMessageDialog(frame, "您选择的日期是: " + selectedDate);
                } else {
                    JOptionPane.showMessageDialog(frame, "您还没有选择日期!");
                }
            });
            frame.add(getButton);
            frame.setLocationRelativeTo(null); // 居中屏幕
            frame.setVisible(true);
        });
    }
}

优点:

Java Swing日期控件如何选择与使用?-图2
(图片来源网络,侵删)
  • 完全控制UI的外观和行为。
  • 不需要引入任何外部库。
  • 学习Swing组件组合的好例子。

缺点:

  • 代码量较大,需要自己处理布局和事件逻辑。
  • 实现一个功能完善的日历视图(类似月历)会非常复杂。

使用第三方库 JXDatePicker (强烈推荐)

JXDatePicker 是 SwingX 项目的一部分,SwingX 是一个对 Swing 的扩展库,提供了许多现代、美观且功能强大的组件,包括一个非常好用的日期选择器。

添加依赖

如果你使用 Maven,在 pom.xml 中添加:

<dependency>
    <groupId>org.swinglabs</groupId>
    <artifactId>swingx</artifactId>
    <version>1.6.1</version> <!-- 使用最新的稳定版本 -->
</dependency>

如果你使用 Gradle,在 build.gradle 中添加:

implementation 'org.swinglabs:swingx:1.6.1'

使用 JXDatePicker

JXDatePicker 的使用非常简单,几乎和原生组件一样。

import org.jdesktop.swingx.JXDatePicker;
import javax.swing.*;
import java.awt.*;
import java.util.Date;
public class JXDatePickerExample {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("JXDatePicker 示例");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(400, 200);
            frame.setLayout(new FlowLayout());
            // 1. 直接创建 JXDatePicker
            JXDatePicker datePicker = new JXDatePicker();
            // 设置默认选中今天的日期
            datePicker.setDate(new Date());
            // 2. 可以设置日期格式
            datePicker.setFormats("yyyy年MM月dd日", "yyyy-MM-dd");
            // 3. 添加一个监听器,当日期改变时触发
            datePicker.addActionListener(e -> {
                Date selectedDate = datePicker.getDate();
                System.out.println("选择的日期是: " + selectedDate);
                JOptionPane.showMessageDialog(frame, "您选择的日期是: " + selectedDate);
            });
            frame.add(new JLabel("请选择日期:"));
            frame.add(datePicker);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

优点:

  • 开箱即用:功能非常完整,包括弹出式月历、日期格式化等。
  • 外观现代:比手动组合的组件看起来更专业。
  • 易于使用:API 设计直观,学习成本低。
  • 可扩展性强:可以轻松地与 JXMonthView 等其他 SwingX 组件配合。

缺点:

  • 需要引入第三方依赖。

结合 Java 8+ 的 java.time API (最佳实践)

无论你选择方案一还是方案二,处理日期数据时,强烈建议使用 Java 8 引入的 java.time,而不是过时的 java.util.Datejava.util.Calendarjava.time 更安全、更易用。

修改方案一的 CustomDatePicker 以使用 java.time

我们只需要修改 getSelectedDate() 方法,使其返回 LocalDate 类型。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
// ... 在 CustomDatePicker 类中 ...
private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
// ... showDatePickerDialog 方法中 ...
// JSpinner 的模型需要调整,或者直接使用 JCalendar 等更复杂的库。
// 为了简单起见,这里我们假设 JSpinner 仍然返回 Date 对象。
// 然后将其转换为 LocalDate。
okButton.addActionListener(e -> {
    Date selectedDate = (Date) spinner.getValue();
    // 将 java.util.Date 转换为 java.time.LocalDate
    Instant instant = selectedDate.toInstant();
    ZoneId zoneId = ZoneId.systemDefault(); // 获取系统默认时区
    LocalDate localDate = instant.atZone(zoneId).toLocalDate();
    textField.setText(dateFormatter.format(localDate));
    dialog.dispose();
});
// 新增方法,用于获取 java.time.LocalDate
public LocalDate getSelectedLocalDate() {
    String dateStr = textField.getText();
    try {
        return LocalDate.parse(dateStr, dateFormatter);
    } catch (DateTimeParseException e) {
        return null; // 或者返回 LocalDate.now()
    }
}

在主程序中,你就可以得到 LocalDate 对象,它提供了更丰富的方法,如 plusDays(), getDayOfWeek() 等。

// 在 MainApplication 的 ActionListener 中
LocalDate selectedLocalDate = datePicker.getSelectedLocalDate();
if (selectedLocalDate != null) {
    JOptionPane.showMessageDialog(frame, "您选择的日期是: " + selectedLocalDate + ", 是周" + selectedLocalDate.getDayOfWeek().getValue());
}

为什么推荐 java.time

  • 不可变:所有 java.time 类都是不可变的,线程安全,避免了 DateCalendar 的可变性问题。
  • API 清晰:方法命名清晰直观,如 plusDays, minusMonths
  • 时区处理:提供了 ZonedDateTimeZoneId 来完美处理时区问题。
  • 现代标准:是 Java 官方推荐的日期和时间API。

总结与选择建议

特性 手动组合 (JTextField + JButton) JXDatePicker (SwingX)
易用性 低,需要编写大量代码 高,开箱即用
功能完整性 低(基础),高(需大量开发) (自带月历、格式化等)
外观 依赖基础组件,需自行美化 现代、专业
依赖 需要 swingx
灵活性 极高,完全掌控 较高,可通过配置满足大部分需求
java.time 结合 容易,只需修改返回类型 容易,只需转换 Date 对象

如何选择?

  • 对于绝大多数项目强烈推荐使用 JXDatePicker,它能以最小的代码量提供最好的用户体验,是工业界的标准做法。
  • 对于学习或需要极致定制化:可以尝试手动组合组件,这有助于你深入理解 Swing 的工作原理,适合开发一些非常特殊、UI 要求极高的内部工具。
  • 无论哪种UI组件:在后台处理和存储日期数据时,请务必使用 Java 8+ 的 java.time API,这是现代 Java 开发的最佳实践。
分享:
扫描分享到社交APP
上一篇
下一篇