6 在JavaFX中实现Swing应用程序
在本章中,您将了解一个Swing应用程序,并学习如何在JavaFX中实现它。
为了本章的目的,请熟悉图6-1中显示的Converter应用程序。该应用程序用于在公制和美制单位之间转换距离测量。
分析在Swing中开发的转换器应用程序
有关在Java编程语言中实现此示例的更多信息,请参阅Swing教程中的如何使用面板和使用模型部分。特别是,图形用户界面(GUI)在关于面板的教程中进行了讨论。
要了解转换器应用程序的代码,请下载其NetBeans项目或在示例索引中提供的源文件。
Swing组件使用模型。如果您查看项目的内容,您会注意到ConverterRangeModel和FollowerRangeModel类定义了转换器应用程序的模型。
转换器应用程序包含以下文件:
-
ConversionPanel.java— 包含一个自定义的JPanel子类来容纳组件 -
Converter.java— 包含主应用程序类 -
ConverterRangeModel.java— 定义顶部滑块的模型 -
FollowerRangeModel.java— 定义底部滑块的模型 -
Units.java— 创建Unit对象
请注意,每个文本字段与其滑块之间的同步是通过监听值的变化的事件处理程序来实现的。
在JavaFX中规划转换器应用程序
Converter应用程序包含两个类似的面板,其中包含文本字段、滑块和组合框等组件。这些面板有标题。javafx.scene.control包中的TitlePane类非常适合Converter应用程序的GUI。
接下来,您将实现ConversionPanel类,并将两个该类的实例添加到Converter应用程序的图形场景中。
首先,请注意单个ConversionPanel对象中的组件应该按照以下方式进行同步。每当您在滑块上移动旋钮时,您必须更新文本字段中的值,反之亦然:每当您更改文本字段中的值时,您必须调整滑块上的旋钮位置。
一旦您从组合框中选择另一个值,您必须更新文本字段的值,从而更新滑块上的旋钮位置。
其次,请注意两个ConversionPanel对象应该进行同步。一旦一个面板发生更改,另一个面板上的相应组件必须更新。
建议您使用DoubleProperty对象(称为meters)在面板之间实现同步,并通过创建和注册两个InvalidationListener对象(fromMeters和toMeters)监听文本字段和组合框的属性更改。每当一个面板上的文本字段的属性更改时,将调用附加的InvalidationListener对象的invalidated方法,该方法会更新meters属性。因为meters属性发生了变化,所以会调用附加到meters属性的InvalidationListener对象的invalidated方法,该方法会更新另一个面板上的相应文本字段。
类似地,每当一个面板上的组合框的属性更改时,将调用附加的InvalidationListener对象的invalidated方法,该方法会更新该面板上的文本字段。
为了在滑块的值和meters对象的值之间提供同步,使用双向绑定。
有关JavaFX属性和绑定的更多信息,请参阅使用JavaFX属性和绑定。
在JavaFX中创建转换器应用程序
在NetBeans IDE中创建一个新的JavaFX项目,并将其命名为Converter。从Swing应用程序中复制Unit.java文件到Converter项目中。在该项目中添加一个新的Java类,并将其命名为ConversionPanel.java。
在JavaFX中创建GUI的标准模式
在开始创建JavaFX中的Converter应用程序的GUI之前,先看一下Swing应用程序中GUI创建的标准模式,如示例6-1所示。
示例6-1
public class Converter {
private void initAndShowGUI() {
...
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
initAndShowGUI();
}
});
}
}
要将此模式映射到JavaFX中,您需要扩展javafx.application.Application类,重写start方法,并调用main方法,如示例6-2所示。
示例6-2
import javafx.application.Application;
import javafx.stage.Stage;
public class Converter extends Application {
@Override
public void start(Stage t) {
...
}
public static void main(String[] args) {
launch(args);
}
}
在NetBeans IDE中创建一个新的JavaFX项目时,这个模式会自动为您生成。然而,如果您使用文本编辑器,了解JavaFX中GUI创建的基本方法是很重要的。
容器和布局
在Swing中,容器和布局管理器是不同的实体。您创建一个容器,比如一个JPanel或JComponent对象,并为该容器设置一个布局管理器。您可以指定一个特定的布局管理器,并在代码中写.add(),或者不指定任何布局管理器。
在JavaFX中,容器本身负责布局其子节点。您创建一个特定的布局面板,比如Vbox、FlowPane或TitledPane对象,然后使用.getChildren().add()方法将内容添加到其子节点列表中。
JavaFX中有几个布局容器类,称为面板,其中一些在Swing中有对应的类,比如JavaFX中的FlowPane类和Swing中的FlowLayout类。
更多信息,请参阅在JavaFX中使用布局。
UI控件
JavaFX SDK提供了一组标准的UI控件。其中一些UI控件在Swing中也有对应的控件,比如JavaFX中的Button类和Swing中的JButton,JavaFX中的Slider和Swing中的JSlider,以及JavaFX中的TextField和Swing中的JTextField。
要在JavaFX中实现Converter应用程序,可以使用TextField、Slider和ComboBox类提供的标准UI控件。
更多信息,请参见使用JavaFX UI控件。
用户操作和绑定的机制
在Swing中,您可以在任何组件上注册监听器,监听组件属性的变化,比如大小、位置或可见性的变化;或者监听事件,比如组件是否获得或失去了键盘焦点;或者鼠标是否在组件上点击、按下或释放。
在JavaFX中,每个对象都有一组属性,您可以为这些属性注册监听器。当属性的值发生变化时,监听器会被调用。
请注意,一个对象可以注册为另一个对象属性的监听器。因此,您可以使用绑定机制来同步两个对象的某些属性。
创建ConversionPanel类
ConversionPanel类用于容纳组件:文本字段、滑块和组合框。在创建Converter应用程序的图形场景时,将两个ConversionPanel类的实例添加到图形场景中。按照示例6-3中所示的方式添加TitledPane类的导入语句并扩展ConversionPanel类。
创建DoubleProperty和NumberFormat对象
按照示例6-5中所示的方式添加DoubleProperty和NumberFormat类的导入语句,并创建一个名为meters的DoubleProperty对象。meters对象用于确保两个ConversionPanel对象之间的同步。
布局组件
使用VBox类来布局文本字段和滑块。使用HBox类来布局这两个组件和一个组合框。按照示例6-6中所示的方式添加ObservableList类的导入语句并实现ConversionPanel类的构造函数。
示例6-6
import javafx.collections.ObservableList;
public ConversionPanel(String title, ObservableList<Unit> units,
DoubleProperty meters) {
setText(title);
setCollapsible(false);
numberFormat = NumberFormat.getNumberInstance();
numberFormat.setMaximumFractionDigits(2);
textField = new TextField();
slider = new Slider(0, MAX, 0);
comboBox = new ComboBox(units);
comboBox.setConverter(new StringConverter<Unit>() {
@Override
public String toString(Unit t) {
return t.description;
}
@Override
public Unit fromString(String string) {
throw new UnsupportedOperationException("Not supported yet.");
}
})
VBox vbox = new VBox(textField, slider);
HBox hbox = new HBox(vbox, comboBox);
setContent(hbox);
this.meters = meters;
comboBox.getSelectionModel().select(0);
}
代码的最后一行选择了ComboBox对象中的一个值。
创建InvalidationListener对象
为了监听文本字段和组合框的属性变化,创建InvalidationListener对象fromMeters和toMeters,如示例6-7所示。
示例6-7
import javafx.beans.InvalidationListener;
private InvalidationListener fromMeters = t -> {
if (!textField.isFocused()) {
textField.setText(numberFormat.format(meters.get() / getMultiplier()));
}
};
private InvalidationListener toMeters = t -> {
if (!textField.isFocused()) {
return;
try {
meters.set(numberFormat.parse(textField.getText()).doubleValue() *
getMultiplier());
} catch (ParseException | Error | RuntimeException ignored) {
}
};
向控件添加更改监听器并确保同步
为了在文本字段和组合框之间提供同步,可以像示例6-8中所示添加更改监听器。
示例6-8
meters.addListener(fromMeters); comboBox.valueProperty().addListener(fromMeters); textField.textProperty().addListener(toMeters); fromMeters.invalidated(null);
可以像示例6-9中所示,创建滑块值和meters对象值之间的双向绑定。
当在文本字段中输入新值时,将调用toMeters监听器的invalidated方法,该方法会更新meters对象的值。
创建转换器类
打开由NetBeans IDE自动生成的Converter.java文件,并删除除main方法之外的所有代码。然后,按下Ctrl(或Cmd)+Shift+I来修正导入语句。
定义实例变量
添加ObservableList、DoubleProperty和SimpleDoubleProperty类的导入语句,并按照示例6-10中所示创建metricDistances、usaDistances和meters变量。
创建转换器类的构造函数
在Converter类的构造函数中,按照示例6-11中所示创建度量和美国距离的Unit对象。添加FXCollections类的导入语句。稍后,您将使用这些单位实例化两个ConversionPanel对象。
示例6-11
import javafx.collections.FXCollections;
public Converter() {
metricDistances = FXCollections.observableArrayList(
new Unit("厘米", 0.01),
new Unit("米", 1.0),
new Unit("千米", 1000.0));
usaDistances = FXCollections.observableArrayList(
new Unit("英寸", 0.0254),
new Unit("英尺", 0.305),
new Unit("码", 0.914),
new Unit("英里", 1613.0));
}
创建图形场景
重写start方法来创建你的Converter应用的图形场景。将两个ConversionPanel对象添加到图形场景中,并垂直布局它们。注意,两个ConversionPanel对象都使用相同的meters对象进行实例化。使用VBox类作为图形场景的根容器。如示例6-12所示,实例化两个ConversionPanel对象。
示例6-12
@Override
public void start(Stage stage) {
VBox vbox = new VBox(
new ConversionPanel(
"公制系统", metricDistances, meters),
new ConversionPanel(
"美制系统", usaDistances, meters));
Scene scene = new Scene(vbox);
stage.setTitle("转换器");
stage.setScene(scene);
stage.show();
}
你可以在本文档底部的链接中查看Converter应用的源代码并下载NetBeans项目。
JavaFX中的Converter应用程序如图6-2所示。
将使用Swing库和JavaFX实现相同功能的两个应用程序进行比较。
与Swing应用程序的五个文件相比,JavaFX应用程序不仅包含三个文件,而且代码更加简洁。这两个应用程序在外观和感觉上也有所不同。

