java - JFormattedTextFields 中的两位数日期
问题描述
我有一个本质上是使用 DateFormatter 的 JFormattedTextField,它从用户控制的区域设置中获取其格式。下面的代码试图在没有大量专有代码的情况下重现这一点。(我为我在顶级 Swing 方面的粗鲁尝试道歉......)
我的问题是,如果用户选择了具有两位数年份的语言环境,则无法输入“错误”世纪的日期。例如,如果我运行下面的程序并将年份编辑为 2047 并单击确定,程序将打印 1947 年的日期。
原因似乎是JFormattedTextField 喜欢通过在文本表示中往返来“规范化”其数据。一种解决方法是使用测试往返的方法覆盖 commitEdit(),如果结果破坏了年份,则用硬编码的 YYYY-MM-DD 替换格式。不过,这似乎有点笨拙。有没有更好的方法,除了要求用户选择一个理智的语言环境或为这个特定字段硬连接格式?(我知道有多种方法可以选择哪个 100 年窗口是正确的,但这仍然将我限制在 100 年窗口)。
import javax.swing.*;
import javax.swing.text.DateFormatter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
var gbl = new GridBagLayout();
frame.setLayout(gbl);
final Container contentPane = frame.getContentPane();
Date date = new Date();
JFormattedTextField dateField = new JFormattedTextField(date);
dateField.setFormatterFactory(new JFormattedTextField.AbstractFormatterFactory() {
@Override
public JFormattedTextField.AbstractFormatter getFormatter(JFormattedTextField tf) {
return new DateFormatter(DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.GERMANY));
}
});
contentPane.add(dateField);
JButton button = new JButton("Ok");
contentPane.add(button);
button.addActionListener((ActionEvent e) -> {
try {
dateField.commitEdit();
} catch (ParseException ex) {
ex.printStackTrace();
}
System.out.println(dateField.getValue());
});
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(Main::createAndShowGUI);
}
}
解决方案
如果您需要四位数年份以确保具有正确的世纪并且您的语言环境在其SHORT
日期格式中使用两位数年份,我看到两个选项:
- 请改用
MEDIUM
日期格式。我怀疑在许多语言环境中,这将迫使用户进行更多的打字,他们可能不会对此感到满意。 - 修改语言环境的格式以要求 4 位数年份。根据观点,它可能被视为残酷或有趣的妥协,但它为我们提供了我们需要的东西。
我建议您在使用JFormattedTextField
. 要获取和修改用户区域设置的格式模式:
Locale userSelectedLocale = Locale.GERMAN;
String formatPattern = DateTimeFormatterBuilder
.getLocalizedDateTimePattern(FormatStyle.SHORT, FormatStyle.SHORT,
IsoChronology.INSTANCE, userSelectedLocale);
System.out.println("Localized format: " + formatPattern);
formatPattern = formatPattern.replaceFirst("y+", "yyyy");
System.out.println("Modified localized format: " + formatPattern);
到目前为止的输出是:
Localized format: dd.MM.yy, HH:mm Modified localized format: dd.MM.yyyy, HH:mm
要将其与 a 一起使用,JFormattedTextField
我们需要旧Format
类(的超类DateFormat
)的实例。要构建它:
Format formatForFormattedTextField
= DateTimeFormatter.ofPattern(formatPattern, userSelectedLocale)
.toFormat(LocalDateTime::from);
我指定格式化程序应该解析成LocalDateTime
对象。LocalDateTime
是没有时区或偏移量的日期和时间的 java.time 类。由于用户既没有输入时区也没有输入偏移量,这似乎是我们的目的正确的类。
对于如何使用Format
和JFormattedTextField
一起使用,您可以例如看到我的另一个答案,下面有一个链接。
链接
- 我对如何制作具有固定日期格式的 jtextfield 的回答?
- Oracle 教程:日期时间解释如何使用 java.time。
推荐阅读
- python - Python:无法导入已安装的模块 pdpbox
- c# - 如何将带有本地安装的 MongoDB 的 Asp.net 核心 Web api 部署到 Microsoft Azure?
- javascript - Vuetify v-combobox,勾选一个框后,删除文本
- python - 在批处理脚本中安装 Python + Django
- python - 如何使用 python 在没有 WASAPI 的情况下挂钩输出音频?
- python-3.x - return self.tk.call(self._w, 'cget', '-' + key) TypeError: can only concatenate str (not "int") to str
- django - 从数据库中的数据翻译
- laravel - 我想向某个团队添加和查看玩家,并根据 laravel 中的团队 id 查看他们
- r - 在 R 中绘制一系列具有不同参数的 pdf
- flutter - Hive 包不保存主对象下的对象