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应用程序不仅包含三个文件,而且代码更加简洁。这两个应用程序在外观和感觉上也有所不同。