输入法
实际上,以上所有讨论都涉及操作或显示数据。然而,必须以某种方式输入数据。对于最终用户,最常用的是键盘。但是,如果键盘不支持某种语言输入所需的字符,您该怎么办呢?
输入法(Input method)是允许数据输入的软件组件的一个技术术语。Java 平台既允许使用主机 OS 输入法也允许使用基于 Java 语言的输入法。如果您需要实现输入法,您可以使用输入法框架(Input Method Framework)。您可以在 JDK 文档中 Internationalization 一节中的 Input Method Framework (可以从参考资料中访问该文档)中找到输入法客户机 API(Input Method Client API)及输入法引擎 SPI(Input Method Engine SPI)的规范、参考和教程
Unicode 与 Java 字符
Java 字符与 char 数据类型
Java 程序员的一个最知名的抱怨是“我只看到程序输出是问号(或方块),我的数据是怎么被破坏的呢?”通常,作为 Java 开发人员,您应该理解实际发生了什么以及这一表面问题后面的原因,而这种知识在处理国际化问题时尤为重要。
Java 语言规范(Java Language Specification)将 char 定义为原始的、数值型和整型的类型。此外,char 是唯一的无符号(unsigned)数字类型,它允许一些有趣的(或讨厌的,这取决于您的观点)窍门。char 在另一方面也十分特殊,因为将它们送到诸如显示器或打印机的输出设备时,会将其值从字符映射或字体映射成字形。然而,从根本上来说,char 是数值类型,支持所有整数运算。因此 Unicode支持 注释道:可以使用字母或 Unicode 转义符设置 char。因为 char 是数值型,所以您也可以使用八进制、十进制或十六进制表示法甚至反转位来赋值。
假设出现上述情况并假定没有程序错误,上面问题的答案是:字符映射或字体不支持该字符,显示问号或方块来作为替代。该 char 本身的值仍然有效。但是,这样您就不能可视地验证数据;您不得不核对数值。下面的示例显示了这一行为。
这幅图像显示了日本象形文字中的“Go”或 5,以 Unicode 表示为‘\u4E94’。该字符导致在下面的 charExample 程序中显示成问号和方块:
import javax.swing.*;
public class charExample
{
public static void main( String[] args )
{
boolean bFirst = true;
char aChar[] = {
'A', // character
65, // decimal
0x41, // hex
0101, // octal
'\u0041' // Unicode escape
};
char myChar = 256;
for( int i = 0; i < aChar.length; i++ )
{
System.out.print( aChar[i]++ + " " );
if( i == (aChar.length - 1) )
{
System.out.println( "\n---------" );
if( bFirst )
{
i = -1;
bFirst = !bFirst;
}
}
} // end for
// the result of adding two chars is an int
System.out.println( "aChar[0] + aChar[1] equals: " +
(aChar[0] + aChar[1]) );
System.out.println( "myChar at 256: " + myChar );
System.out.println( "myChar at 20116 or \\u4E94: " +
( myChar = 20116 ) );
// show integer value of the char
System.out.println( "myChar numeric value: " +
(int)myChar );
JFrame jf = new JFrame();
JOptionPane.showMessageDialog( jf,
"myChar at 20116 or \\u4E94: " +
( myChar = 20116 ) +
"\nmyChar numeric value: " +
(int)myChar,
"charExample", JOptionPane.ERROR_MESSAGE);
jf.dispose();
System.exit(0);
} // end main
} // End class charExample
首先,程序用字母“A”的各种表示法初始化一个 char 数组,并将一个 char 变量设置成 256(‘\u0100’)。程序在一个循环中打印两次数组的值。打印之后递增每个元素的值(char 是数值型,记得吗?)。接下来,将头两个元素加到一起,然后打印其结果(int)。然后,打印 char 变量,首先用其初始值,然后用值 20116 或‘\u4E94’,它是 5 的日本象形文字“Go”。如预期的那样在使用代码页 cp1252 的 Windows NT 上,会在显示器上将这两个值打印成问号。根据您的系统使用的代码页,显示可能略微有些不同。要核查其值,接下来将变量作为 int 打印。最后,JOptionPane 显示其值,对于不受支持的 char‘\u4E94’,它显示一个方块。
下面是 charExample 的输出:
A A A A A
---------
B B B B B
---------
aChar[0] + aChar[1] equals: 134
myChar at 256: ?
myChar at 20116 or \u4E94: ?
myChar numeric value: 20116
JOptionPane 显示:
字体、字体特性及 Lucida 字体
Java 平台既识别逻辑字体也识别物理字体。
逻辑字体是那些被映射到主机系统字体的字体。比如人们熟悉的 Serif、Sans-serif、Monospaced、Dialog 以及 DialogInput 字体。还有四种逻辑字体样式:普通、粗体、斜体及粗斜体。使用一个位于 JRE/lib 目录下的font.properties 文件来实现主机字体到逻辑字体的映射。尽管细节因系统而异,但是缺省 font.properties 文件通常设置成英语环境,虽然JDK 也有一个本地化日语版本可用。还提供了另外的font.properties 文件;JDK 1.3.1 Windows 版包含阿拉伯语、希伯来语、日语、韩国语、俄语、泰国语字体文件以及中文的几种版本的字体文件。就象命名约定一样,搜索适当的 font.properties 同用于 ResourceBundle 的方法类似(但不全相同)。如果特定于语言的 font.properties 文件同您的系统的语言环境相匹配,并且安装了期望的字体(通常随 OS 的那一版本一起提供),那么就会对该语言进行自动映射。否则,就使用缺省的(通常是英语)文件映射。
如果您安装了适当的字体并且在调用 Java 应用程序时传入了相应的语言及国家或地区代码,那么也会进行自动映射。如果期望的 font.properties 文件存在,那么这种行为对开发非常有用。也可以将最初的缺省 font.properties 文件拷贝到别的地方,然后将特定文件重命名为“font.properties”,通过这样来将该语言/字体有效地设置成缺省情况。虽然对于开发人员来说很容易,但这显然不是最终用户非得做的事情。
如果您必须亲自定制或创建一个新的font.properties 文件,那就完全是另一回事,而且更难。可以在JDK 文档 Internationalization 一节中的 Font Properties 中找到处理 font.properties 文件的指示信息。
物理字体是我们始终在使用的正常字体。基于ASCII 和 ISO 8859-1 的字体不会有问题。然而,一旦超出这一范围,主机平台显然必须理解它们,并且必须对它们进行 Unicode 编码以使之能够用于您的 Java程序。找到这些字体不象以前那么难了。例如,Windows MS MinchoTrueType 字体(主要是日语)是 Unicode 编码的,可以以标准方式立即投入使用。当在系统上装入了适当的物理字体时,您可以让用户选择他们想要的字体并保存他们的首选项,或者将该字体设置成整个软件包的标准字体,而不用进入 font.properties 文件。
Java 2 SDK 还提供三种物理字体系列:Lucida Sans、Lucida Bright 和 Lucida Sans Typewriter。每一系列都含有四种字体 ― 分别用于普通、斜体、粗体以及粗斜体样式 ― 总计 12 种字体。虽然关于这些字体的确切功能的信息极为稀少,但 Lucida Sans 字体处理大多数欧洲和中东语言。不包括亚洲语言。由于该字体随 JDK 一起提供,因此教程中的所有图形应用程序示例都使用Lucida Sans 字体。更多信息,请参阅 JDK 文档 Internationalization 一节中的 Physical Fonts (可以从参考资料访问)。
提供本地化的资源
创建语言环境
提供任何类型的本地化资源时,您应该做的第一件事情是创建一个适当的语言环境(参阅语言环境)。虽然有一个包含平台/浏览器变体的构造器,但通常您将使用
Locale l = new Locale(String language, String country); |
其中,language 是由 ISO-639 定义的小写、两字母代码,country 是一个由 ISO-3166 定义的大写、两字母代码。
下面是用于特定于德国的德语语言环境:
Locale l = new Locale( "de", "DE"); |
Locale 有一个返回受支持的语言环境数组的 static getAvailableLocales() 方法。实际上,所有与语言环境相关的 Java 2 Platform API 都有一个 getAvailableLocales() 方法,您可以期望它返回一致的值。其它有用的方法是 static getDefault(),它返回缺省的语言环境,以及 getDisplayName() 和 getDisplayName(Locale inLocale) 方法,它们分别用缺省或所请求的语言环境语言来返回适于显示的名称。您也可以获取国家或地区以及语言的代码和名称。这些方法允许没有特定语言知识的程序员为最终用户提供读、选择以及返回本地化的语言环境信息的能力。
使用资源束
ResourceBundle 包含键/值结合。键总是 String,而值总是 PropertyResourceBundle 中的 String,但可以是 ListResourceBundle 中的任何对象或定制子类。如果没有找到请求的资源,那么 ResourceBundle 访问方法会抛出一个MissingResourceException。
参阅本地化的资源以获得更多常规信息。本教程将集中于 PropertyResourceBundle,因为它们适合于大多数情形,并且易于生成和修改而无须编写任何新代码。
ResourceBundle.getBundle(StringbaseName) 和 ResourceBundle.getBundle(StringbaseName, Locale locale) 提供一种内置的搜索机制,当这些束的结构恰当时,这种机制工作得非常好。正常的搜索从 base_language_country_variant 到 base_language_country,再到base_language,最后到 base。注:如果请求一个特定的、非缺省的语言环境,并且同资源一起存在一个缺省的语言环境束,那么搜索将会停在那儿而不是继续搜索到基础束。我们的示例程序(参阅 PropertyResourceBundle代码示例)支持英语、法语、德语和俄语并使用 PropertyResourceBundle。支持的 .properties 文件被命名为:
· ByTheNumbersrb.properties
· ByTheNumbersrb_de.properties
· ByTheNumbersrb_en.properties
· ByTheNumbersrb_fr.properties
· ByTheNumbersrb_ru.properties
所有文件都含有全部所需资源。英语用作缺省值,ByTheNumbersrb.properties和 ByTheNumbersrb_en.properties 是相同的。这种做法略微有些偏离传统认知,即:对于基础缺省语言,不需要专门命名的 .properties 文件,因此我们不需要ByTheNumbersrb_en.properties。然而,当一段特定信息使用非缺省语言环境时,这种设置却是必需的,我们的示例程序就是这种情形。假定一个英语语言环境将被用来在一台法语为缺省语言环境机器上显示某项。如果 _fr 束中存在相同的键,_en 搜索失败时,将会选择该值。这完全不是所请求的或所期待的那样。如果在程序的任意一次给定运行中只使用一种语言环境,那么专门命名的副本就不是必需的。但无论如何,在任何情况下这种做法都不需要新的代码并且起作用。
如果我们需要更特定的语言环境支持,例如奥地利语、瑞士语和德语(分别是 _de_AT、_de_CH 和 _de_DE),那么只将国家或地区细节置于以适当的国家或地区命名的特性文件(例如,myprops_de_CH.properties)中,而将更一般的元素置于 _de 束级别,这样做会很有意义。在那种情形下,需要其它元素时,将总能找到 _de 束。
您也应该为束实现几种命名约定。我们的示例使用这种通用格式:Object.getClass().getName() + "rb"。主要规则是:对于 .properties 文件,不要只使用类名称作为其基础名称。忽视该规则在有些平台上照样能行,但在其它一些平台上您会大吃一惊。记入文档的准则是:如果类和具有相同名称的 .properties 文件同时存在,那么被选中和装入的将是类。就是这样。这一行为的一个好结果是:使用适当命名的束,您可以在 ListResourceBundle 和PropertyResourceBundle 之间转换,而不用更改代码;只要将期望的类型移到类路径即可。
您可能会发现让不同的信息类型具有多个 ResourceBundle 更加合适。它们可以为许多不同的程序提供资源。特定的前缀或后缀约定对于避免类名冲突仍然有用。
使用 PropertyResourceBundle
PropertyResourceBundle 的语义同其父束 ResourceBundle 的语义相同。不同之处在于数据存储的位置。PropertyResourceBundle 由符合 Properties 约定的 .properties 文件支持。下面是创建文件所要知道的内容:
· 文件被格式化为 ISO8859-1 编码的基本文本,因此您可以使用任何编辑器来创建和编辑文件。
· 以 # 开头的行是注释。
· 每个资源以 key=value 的形式被设置成键/值对。
· 文件扩展名必须是.properties。名称必须遵守下列格式,其中 language 由 ISO-639 定义,country 由 ISO-3166 定义(参阅创建语言环境):
1. baseName.properties
2. baseName_language.properties
3. baseName_language_country.properties
4. baseName_language_country_variant.properties
下面是ByTheNumbersrb_en.properties 的一个示例项:
1=One: |
下面是ByTheNumbersrb_ru.properties 的一个示例项:
1=\u041E\u0434\u0438\u043D: |
上面两个示例中的冒号实际上是值的一部分而不是所需的项。注:一旦我们超越了 ISO 8859-1 而进入其它 Unicode 范围,我们必须使用 Java Unicode 转义。您可以使用 JDKnative2ascii 工具来从不同编码进行转换。
Property ResourceBundle 代码示例
显示在右侧的 ByTheNumbers 示例使用俄语语言环境 ― ru_RU。
ByTheNumbers.java(参阅 ByTheNumbers.java:PropertyResourceBundle 示例)以几种不同的语言显示数字 0 到 10 的名称。进入时,将缺省的语言环境同支持的语言环境(英语、法语、德语和俄语)相比较。如果缺省语言环境与其中的某一种不匹配,那么就将英语选做缺省,将基础 ResourceBundle 用于资源;否则,使用缺省语言环境 ResourceBundle。通过使用缺省语言环境获得支持的语言的语言环境显示名称(Locale Display Name),并将其装入 JComboBox。用户可以键入适当名称的号码然后按 OK。程序验证这些输入项并显示祝贺消息或重试消息。我们提供一个按钮以随机顺序显示号码名称。用户可以从 JComboBox 选择任何语言,并且字段初始将以数值顺序显示选中的语言。程序使用 Lucida Sans 字体,因此可以正确地显示所有受支持的语言。遗憾的是,我们的翻译还没有返回我们对标题翻译的请求,因此“title=Key in numbers to match the words:”键/值对仅仅出现在基础名称文件中,它给了我们一个机会,让我们明白不位于层次结构较低位置的键可以在祖先文件中找到。
要运行该程序,使用下列任意一条命令:
l java ByTheNumbers // 如果支持缺省语言环境,就使用它,否则,就使用英语。
l java -Duser.language=de -Duser.region=DE ByTheNumbers // 德语
l java -Duser.language=en -Duser.region=US ByTheNumbers // 英语
l java -Duser.language=fr -Duser.region=FR ByTheNumbers // 法语
l java -Duser.language=ru -Duser.region=RU ByTheNumbers // 俄语
下面显示了五个 .properties 文件中的两个:
ByTheNumbersrb.properties (与 ByTheNumbersrb_en.properties相同)
# Default properties in English 0=Zero: 1=One: 2=Two: 3=Three: 4=Four: 5=Five: 6=Six: 7=Seven: 8=Eight: 9=Nine: 10=Ten: random=Random title=Key in numbers to match the words: |
ByTheNumbersrb_ru.properties
# Default properties in Russian 0=\u041D\u0443\u043B\u044C: 1=\u041E\u0434\u0438\u043D: 2=\u0414\u0432\u0430: 3=\u0422\u0440\u0438: 4=\u0427\u0435\u0442\u044B\u0440\u0435: 5=\u041F\u044F\u0442\u044C: 6=\u0428\u0435\u0441\u0442\u044C: 7=\u0441\u0435\u043C\u044C: 8=\u0412\u043E\u0441\u0435\u043C\u044C: 9=\u0414\u0435\u0432\u044F\u0442\u044C: 10=\u0414\u0435\u0441\u044F\u0442\u044C: random=\u041D\u0430\u0443\u0433\u0430\u0434 |
Property ResourceBundle 代码示例:I18N 详细信息
让我们看一看同 I18N 有关的代码部分。首先,建立支持的语言环境和 ResourceBundle 基础名称。
Locale[] alSupported = { Locale.US, Locale.FRANCE, Locale.GERMANY, new Locale( "ru", "RU" ) }; ...
String sRBName = getClass().getName() + "rb"; |
接下来,使用与 OK 按钮的字体相同的样式和大小创建 Lucida Sans 字体,然后获得缺省语言环境语言所支持的语言的显示名称(Display Names)。此外,对缺省语言环境进行比较以确定是否支持它。如果不支持,英语数字将是首先被显示的集合。
Font fJB = jbOK.getFont(); fLucida = new Font("Lucida Sans", fJB.getStyle(), fJB.getSize() );
...
asDNames = new String[ alSupported.length ]; Locale lDefault = Locale.getDefault(); for( i = 0; i < alSupported.length; i++ ) { asDNames[i] = alSupported[i].getDisplayName();
if( iSelIndex == 0 && lDefault.equals( alSupported[i] ) ) { iSelIndex = i; } } // end for |
接下来,在一个循环中创建 JLabel 和 JTextField 并将它们装入数组。设置每个 JLabel 的 Font 和 Name。一旦构建了数组,就调用 loadFromResourceBundle() 来设置每个 JLabel 的文本值。接下来设置本地化jbRandom 按钮和标题文本。请注意,这两个组件的属性只设置了一次,这是典型程序中所有组件的正常情况,在那里,语言环境在给定的运行期间不会改变。
jlTemp.setFont( fLucida ); jlTemp.setName( i + "" ); // set Name ... loadFromResourceBundle(); // get localized labels ... jbRandom.setFont( fLucida ); jbRandom.setText( rb.getString( "random" ) ); ... jlTemp = new JLabel( rb.getString( "title" ) ); jlTemp.setFont( fLucida ); |
下面是 loadFromResourceBundle() 方法,它使用选中的语言环境访问适当的 ResourceBundle。使用 JLabel.Name 属性作为 getString(String key) 的键来设置 JLabel 的文本。如果没有找到特别的资源,就显示一个错误对话框。从JComboBox 选择语言时,也会调用这一方法。
public void loadFromResourceBundle() { try { // get the PropertyResourceBundle rb = ResourceBundle.getBundle( sRBName, alSupported[iSelIndex] ); // get data associated with keys for( int i = 0; i < sfiSIZE; i++ ) { aiOrder[i] = i; ajl[i].setText( rb.getString( ajl[i].getName() ) ); } bRandomize = false; } // end try catch( MissingResourceException mre ) { JOptionPane.showMessageDialog( this, "ResourceBundle problem;\n" + "Specific error: " + mre.getMessage(), "", JOptionPane.ERROR_MESSAGE); } } // end loadFromResourceBundle |
同样,有关完整的程序清单及所有.properties 文件的内容,请参阅 ByTheNumbers.java:PropertyResourceBundle 示例。
使用日期、数字和货币
日期、数字和货币
对于任何那些从未出过国,或从未接触过日期、数字和货币的“外国”用法的人来说,格式化和解析日期、数字和货币显得很简单。毕竟,所有人都能理解 lundi 1 avril 2002 或至少 4.1.02 的月和日部分,对吗?虽然我们极少有人能实际以 150,75 购买 32 1500,7 项东西,但我们能够很容易地理解以欧元表示的价格有多少项。或者可能不是这样。这些示例看起来可能不典型,但他们确实发生了,并且表示了为什么非本国人在理解本国的日期、数字和货币格式方面经常会有问题。
结果是,全世界使用的日期有各种各样的顺序和符号。数字和货币也是如此。此外,货币符号可能不止一个字符,它可能出现在值的前面或后面,和值之间有或没有空格。在大多数编程语言中,您几乎总是靠自己来处理这些情形。但 Java API 却能够处理每个受支持语言环境的所有的不同格式。而且,通过使用 DateFormatSymbols 和 DecimalFormatSymbols 类,您可以获得诸如这样的信息:本地化的长短月日名称、十进制与货币分隔符以及货币与百分比符号。
API 文档鼓励您为 I18N 应用程序使用抽象父类 DateFormat 和 NumberFormat 的 getInstance() 和 getXXXInstance() 方法。从 1.3(和 1.4)参考实现起,分别返回 SimpleDateFormat 和 DecimalFormat 的实例。两个类都有缺省的模式与符号用于格式化和解析,并且还允许定制。
下面几页中的示例程序都使用缺省模式来帮助您理解它们是怎样工作的。您将看到:由于 API 设计的缘故,三个示例中的代码都非常相似。从最终用户的观点,它们也非常相似:以本机语言环境提供一个输入域。当用户按下 OK 按钮时,就在表示用户选择的语言环境和标准解析的“原始”值的单独域中显示值。这三个示例都将处理由 JDKAPI 支持的所有语言环境。Lucida Sans 字体用于所有显示。“Toggle Display Names”按钮将语言环境名称的显示从用户的本机语言切换为特定语言环境的本机语言。当字体中没有用于本地化显示名称的第一个字符的字形时,“ - font can't display.”就被附加到下拉框中的语言环境名称上。程序仍然会工作,但在那种情况下,您可能会看到输出的某些部分是您熟悉的方框或问号。
使用下面的命令调用程序:
java AppName |
由于支持所有 API 语言环境,您也可以使用下列命令调用它们
java -Duser.language=lc -Duser.region=cc AppName |
其 lc 是 API 支持的语言环境的 ISO-639 语言代码,cc 是 API 支持的语言环境的 ISO-3166 国家或地区代码,以使输入格式化成该语言环境的样式。
注:由于要访问整个语言环境显示名称集,这些应用程序将比正常情况要花费更长的时间来启动。
日期格式化示例
这个 JIBDateGUI 示例使用德语作为缺省语言环境 ― de_DE。
JIBDateGUI(参阅 JIBDateGUI.java:DateFormat 示例)允许用户以其本地的格式输入日期。输入时确定本地语言环境,并且该语言环境显示在 OK 按钮的旁边。当用户按下 OK 时,则解析输入数字并以选中的语言环境显示该数字。还以 ISO 格式对该值进行单独解析和显示。可能使用参数“full”、“long”、“medium”或“short”调用程序。如果没有发送参数或者发送了这四个参数之外的其它参数,那么就使用“short”。这些值对应于DateFormat.FULL、DateFormat.LONG、DateFormat.MEDIUM 和 DateFormat.SHORT,并且被用来以选中的样式创建 DateFormats。
程序通过定义缺省和选中的 DateFormats 和 locales 开始。java.sql.Date 被初始化成显示标准 ISO 日期值的当前日期(注:没有为该示例对日期进行标准化),然后定义 Lucida 字体、缺省语言环境、支持的语言环境的数组以及本机和本地化的语言环境显示名称。
DateFormat dfLocal, dfSelected;
java.sql.Date jsqlDate = new java.sql.Date( System.currentTimeMillis() );
Font fLucida; ... Locale lDefault = Locale.getDefault(); Locale[] alSupported;
String[] asDNames, asLDNames; |
在构造器中,创建了 Lucida Sans 字体并将其赋给显示域。捕获请求的样式并创建缺省 DateFormat。接下来,同时以缺省和本地化格式收集所有可用的显示名称。由 Font.canDisplay() 检查每个本地化显示名称的第一个字符;如果返回 false,那么“ - font can'tdisplay.”就被附加到该名称后面。如果 Java API 支持缺省语言环境,那么相应的显示名称就会被选中;否则就选中第零行。此外,使用 java.sql.Date 的值设置和格式化输入域。DateFormat.setLenient(false) 被应用到缺省 DateFormat 并且获取缺省显示名称以供显示。
Font fJCB = jbToggle.getFont(); fLucida = new Font("Lucida Sans", fJCB.getStyle(), fJCB.getSize() );
iFormat = argiFormat; dfLocal = DateFormat.getDateInstance( iFormat );
alSupported = Locale.getAvailableLocales(); asDNames = new String[ alSupported.length ]; asLDNames = new String[ alSupported.length ]; for( int i = 0; i < alSupported.length; i++ ) { asDNames[i] = alSupported[i].getDisplayName();
s1 = alSupported[i].getDisplayName( alSupported[i] ); if( fLucida.canDisplay( s1.charAt( 0 ) ) ) { asLDNames[i] = s1; } else { asLDNames[i] = s1 + " - font can't display."; }
if( iSelIndex == 0 && lDefault.equals( alSupported[i] ) ) { iSelIndex = i; } } // end for ... jtI.setText( dfLocal.format( jsqlDate ) ); ... dfLocal.setLenient( false ); ... JLabel jlTemp = new JLabel("Default = " + lDefault.getDisplayName() ); jlTemp.setFont( fLucida ); |
在 ActionListener(actionPerformed() 方法)中为显示名称 JComboBox(jcb)处理所有其它 I18N 功能:根据选择项,创建新的 DateFormat 并清空显示域。如果在下一节中出现了任何错误,对话框将显示 ParseException 消息。代码试图从输入解析 java.util.Date 并使用缺省 DateFormat 对其重新进行格式化以供输出。接下来,格式化选中的 DateFormat 的显示。最后,解析该值并用它来创建 java.sql.Date,java.sql.Date 被用来显示 ISO 值。
if( oSource == jcb ) { dfSelected = DateFormat.getDateInstance( iFormat, alSupported[ jcb.getSelectedIndex() ] ); } // end if jcb, continue on
jtD.setText( "" ); jtP.setText( "" );
try { java.util.Date d = dfLocal.parse( jtI.getText() ); jtI.setText( dfLocal.format( d ) ); jtI.setCaretPosition(0); jtD.setText( dfSelected.format( d ) ); jtD.setCaretPosition(0); d = dfSelected.parse( jtD.getText() ); // get new java.sql.Date jsqlDate = new java.sql.Date( d.getTime() );
jtP.setText( jsqlDate.toString() ); } catch( ParseException pe ) { JOptionPane.showMessageDialog( this, pe.getMessage(), "", JOptionPane.ERROR_MESSAGE); } |
同样,JIBDateGUI.java:DateFormat 示例上列出了完整的程序。