JDK17 |java17学习 第 11 章 网络编程
Chapter 12: Java GUI Programming
本章概述了 Java 图形用户界面 (GUI) 技术,并演示了如何使用 JavaFX 工具包创建一个图形用户界面应用程序。最新版本的 JavaFX 不仅提供了许多有用的功能,而且还允许保留和嵌入遗留的实现和样式。
在某些方面,GUI 是应用程序中最重要的部分。它直接与用户交互。如果 GUI 不方便、不吸引眼球或令人困惑,即使是最好的后端解决方案也可能无法说服用户使用此应用程序。相比之下,经过深思熟虑、直观且设计精美的 GUI 有助于留住用户,即使应用程序的工作不如其竞争对手。
本章的议程要求我们涵盖以下主题:
- Java GUI 技术
- JavaFX 基础知识
- 带有 JavaFX 的 HelloWorld
- 控制元件
- 图表
- 应用 CSS
- 使用 FXML
- 嵌入 HTML
- 播放媒体
- 添加效果
在本章结束时,您将能够使用 Java GUI 技术创建用户界面,以及创建用户界面项目并将其用作独立应用程序。
Technical requirements
为了能够执行本章提供的代码示例,您将需要以下内容:
- 装有 Microsoft Windows、Apple macOS 或 Linux 操作系统的计算机
- Java SE 版本 17 或更高版本
- 您选择的 IDE 或代码编辑器
第 1 章,Java 17 入门。本章的代码示例文件可在 GitHub 上的 https://github .com/PacktPublishing/Learn-Java-17-Programming.git 在 examples/src/main/java/com/packt/learnjava/ch12_gui
文件夹和gui
文件夹,其中包含一个独立的 GUI 应用程序。
Java GUI technologies
Java Foundation Classes (JFC) 的名称可能是一个来源 非常混乱。它暗示 Java 基础的类,而事实上,JFC 只包括与 GUI 相关的类和接口。准确地说,JFC 是三个框架的集合:Abstract Window Toolkit (AWT)、Swing 和 Java 2D。
JFC 是 Java 类库 (JCL) 的 的一部分,虽然名称JFC 于 1997 年才成立,而 AWT 从一开始就是 JCL 的一部分。当时,Netscape 开发了一个名为 Internet Foundation Classes (IFC) 的 GUI 库,以及 Microsoft 为 GUI 创建了应用程序基础类 (AFC)发展,也是。因此,当 Sun Microsystems 和 Netscape 决定组建一个新的 GUI 库时,他们继承了 Foundation 这个词并创建了 JFC。 Swing 框架从 AWT 接管了 Java GUI 编程,并成功使用了近二十年。
Java 8 中的 JCL 中添加了一个新的 GUI 编程工具包 JavaFX。它在 Java 11 中从 JCL 中删除,从那时起,作为 Gluon 公司支持的开源项目,作为 JDK 之外的可下载模块. JavaFX 使用与 AWT 和 Swing 不同的 GUI 编程方法。它提供了更一致的 和更简单的设计,并且很有可能成为获胜的 Java GUI 编程工具包。
JavaFX fundamentals
纽约、伦敦、巴黎和莫斯科等城市有许多剧院,居住在那里的人们几乎每周都会听到有关新剧和作品的消息。这让他们不可避免地熟悉戏剧术语,其中的术语stage、scene和 event 可能是最常用的。这三个术语也是 JavaFX 应用程序结构的基础。
JavaFX 中包含所有其他组件的顶级容器由 javafx.stage.Stage
类表示。因此,您可以说,在 JavaFX 应用程序中,一切都发生在 stage 上。从用户的角度来看,它是一个显示区域或窗口,所有控件和组件都在其中执行其操作(就像剧院中的演员)。而且,与剧院中的演员类似,他们是在 scene 的上下文中进行的,由 javafx.scene.Scene 表示代码>类。因此,JavaFX 应用程序,就像剧院中的戏剧一样,由
Scene
对象组成,这些对象分别呈现在 Stage
对象中时间。每个 Scene
对象都包含一个图形,该图形定义了 节点)的位置>JavaFX:控件、布局、组、形状等。它们中的每一个都扩展了抽象类 javafx.scene.Node
。
一些节点的控件与事件相关联:例如,单击按钮或选中复选框。这些事件可以由与相应控制元素关联的事件处理程序处理。
JavaFX 应用程序的主类必须扩展抽象的 java.application.Application
类,该类具有多个生命周期方法。我们按调用顺序列出它们:launch()
、init()
、 notifyPreloader()
、start()
和 stop()
。看起来有很多要记住的。但是,最有可能的是,您只需要实现一种方法,start()
,实际的 GUI 在此构造和执行。尽管如此,为了完整性,我们将回顾所有生命周期方法:
static void launch(Class appClass, String... args)
:这会启动应用程序,通常称为main< /代码>方法;在调用
Platform.exit()
或所有应用程序窗口关闭之前,它不会返回。appClass
参数必须是具有公共无参数构造函数的Application
类的公共子类。static void launch(String... args)
:同上方法,假设Application
的公共子类class 是直接封闭的类。这是最常用于启动 JavaFX 应用程序的方法;我们也将在示例中使用它。void init()
:该方法在Application
类加载完成后调用;它通常用于某种资源初始化。默认实现什么都不做,我们也不会使用它。void notifyPreloader(Preloader.PreloaderNotification info)
:这个可以用来在初始化耗时较长时显示进度;我们 不会使用它。abstract void start(Stage primaryStage)
:我们要实现的方法。在init()
方法返回后,系统准备好执行主要工作后调用它。primaryStage
参数是应用程序要呈现其场景的阶段。void stop()
:当应用程序停止时调用,可用于释放资源。默认实现什么都不做,我们也不会使用它。
JavaFX工具包的API可以在网上找到(https: //openjfx.io/javadoc/18//)。截至撰写本文时,最新版本是 18。 Oracle 也提供了大量的文档和代码示例(https://docs.oracle.com/javafx/2 //)。该文档包括 Scene Builder(一种提供可视化布局环境的开发工具,让您无需编写任何代码即可快速为 JavaFX 应用程序设计用户界面)的描述和用户手册。这个工具对于创建复杂的 GUI 可能很有用,而且很多人一直都在使用它。不过,在本书中,我们将专注于在不使用该工具的情况下编写 JavaFX 代码。
为了能够做到这一点,以下是必要的步骤:
- 将以下依赖项添加到
pom.xml
文件中: - 从 JavaFX SDK target="_blank">https://gluonhq.com/products/javafx/(
openjfx-18_osx-x64_bin-sdk.zip
文件,截至写作时间)并将其解压缩到任何目录中。 - 假设您已将 JavaFX SDK 解压缩到
/path/javafx-sdk/
文件夹中,请将以下选项添加到 Java 命令中,这将在 Linux 平台上启动您的 JavaFX 应用程序:
在 Windows 上,相同的选项如下所示:
/path/JavaFX/
和 C:\path\JavaFX\
是您需要用实际路径替换的占位符包含 JavaFX SDK 的文件夹。
假设应用程序的主类是HelloWorld
,对于IntelliJ,在VM options
字段中输入前面的选项,如如下(示例适用于 Linux):
这些选项必须添加到 HelloWorld
的 Run/Debug Configurations
, BlendEffect
,以及源代码
ch12_gui
包的OtherEffects
类。如果您更喜欢不同的 IDE 或有不同的操作系统,您可以在 openjfx.io
中找到 关于如何设置的建议文档(https://openjfx.io/openjfx-docs)。
从命令行运行 HelloWorld
、BlendEffect
和 OtherEffects
类,在项目根目录( pom.xml
文件所在位置)的Linux平台上使用以下命令:
每个 HelloWorld
、BlendEffect
和 OtherEffects
类都有两个 start()
方法:start1()
和 start2()
。运行一次类后,将 start()
重命名为 start1()
,并将 start1 ()
为 start()
,然后再次运行上述命令。然后,将 start()
重命名为 start2()
,并将 start2()
> 作为 start()
,然后再次运行前面的命令。以此类推,直到所有 start()
方法都执行完毕。这样,您将看到本章中所有示例的结果。
JavaFX 的高级介绍到此结束。有了这个,我们进入最令人兴奋的(对于任何程序员)部分:编写代码。
HelloWorld with JavaFX
这是 HelloWorld
JavaFX 应用程序,它显示 Hello, World!
和退出
文字:
如您所见,应用程序是通过调用 Application.launch(String... args)
静态方法启动的。 start(Stage primaryStage)
方法创建一个 Text
节点,其中包含消息 Hello, World! 位于绝对位置 135(水平)和 40(垂直)。然后,它 创建另一个节点 Button
,其中文本 Exit
位于在绝对位置 155(水平)和 80(垂直)。分配给 Button
的动作(当它被点击时),打印出 Bye!稍后再见! 在屏幕上并使用 Platform.exit()
方法强制应用程序退出。这两个节点作为子节点添加到布局窗格中,允许绝对定位。
Stage
对象的标题为初级阶段(顶级容器)
。在单击窗口右上角的关闭窗口符号(x 按钮)时,还会为其分配一个操作:Linux 系统的左上角和 Windows 的右上角系统。
在创建操作时,我们使用了 Lambda 表达式,我们将在 第 13 章,函数式编程。
创建的布局窗格设置在 Scene
对象上。场景大小设置为水平 350 像素和垂直 150 像素。 Scene
对象被放置在舞台上。然后,通过调用 show()
方法显示舞台。
如果我们运行前面的应用程序(HellowWorld
类的start()
方法),会弹出如下窗口:
单击 Exit 按钮会显示预期的消息:
但是,如果您需要在单击 x 按钮并关闭窗口后执行其他操作,则可以添加 stop() 的实现
方法。在这个例子中,它看起来如下:HelloWorld
类的
如果单击 x 按钮或 Exit 按钮,显示屏将显示以下内容:
此示例让您了解 JavaFX 的工作原理。从现在开始,在回顾 JavaFX 功能时,我们将只展示 start()
方法中的代码。
该工具包有大量的包,每个包都有很多类,每个类都有很多方法。我们将无法讨论所有这些。相反,我们将以最简单直接的方式呈现 JavaFX 功能的所有主要领域的概述。
Control elements
控制元素 包含在 javafx.scene.control
包中( https://openjfx.io/javadoc/11 /javafx.controls/javafx/scene/control/package-summary.html)。其中有 80 多个,包括按钮、文本字段、复选框、标签、菜单、进度条和滚动条等等。正如我们已经提到的,每个控件元素都是 Node
的子类,它有 200 多个方法。因此,您可以想象使用 JavaFX 构建的 GUI 可以有多么丰富和微调。然而,本书的范围仅允许我们涵盖少数元素及其方法。
我们已经在上一节的示例中实现了一个按钮。现在让我们使用标签和文本字段来创建一个简单的表单,其中包含输入字段(名字、姓氏和年龄)和 Submit 按钮。我们将逐步构建它。以下所有代码片段都是 HelloWorld
类中另一个 start()
方法的连续部分(重命名之前的 start()
方法 start1()
,并将 start2()
方法重命名为 start()
)。
首先,让我们创建控件:
您可以猜到,文本将用作表单说明。其余部分非常简单,看起来与我们在 HelloWorld
示例中看到的非常相似。 action()
是一个实现为以下方法的函数:
此函数接受三个参数(javafx.scene.control.TextField
对象),然后获取提交的输入值并仅打印他们。该代码确保始终有一些默认值可用于打印,并且输入 age
的非数字值不会破坏应用程序。
控制和操作到位后,我们使用 javafx.scene.layout.GridPane
类将它们放入网格布局中:
GridPane
布局窗格的行和列构成了可以在其中设置节点的单元格。节点可以跨越列和行。 setAlignment()
方法将网格的位置设置为场景的中心(默认位置是场景的左上角)。 setHgap()
和 setVgap()
方法设置列(水平)和行(垂直)之间的间距(以像素为单位) )。 setPadding()
方法沿网格窗格的边界添加了一些空间。 Insets()
对象按顶部、右侧、底部和左侧的顺序设置值(以像素为单位)。
现在,我们要将创建的节点放置在相应的单元格中(分为两列):
- 节点、列索引和行索引
- 节点、列索引、行索引、要跨越多少列、要跨越多少行
列和行索引从 0
开始。
setHalignment()
方法设置节点在单元格中的位置。 HPos
枚举具有值 LEFT
、RIGHT
和 CENTER
。 addRow(int i, Node... nodes)
方法接受行索引和节点的可变参数。我们用它来放置 Label
和 TextField
对象。
start()
方法的其余部分与 HelloWorld
示例非常相似(仅更改了标题和大小):
如果我们运行新实现的 start()
方法,结果如下:
单击提交按钮后,将显示以下消息并退出应用程序:
为了帮助可视化布局,尤其是在设计更复杂的情况下,您可以使用 setGridLinesVisible(boolean v)
网格方法使网格线可见。它有助于查看单元格是如何对齐的。我们可以在示例中添加(取消注释)以下行:
我们再次运行,结果如下:
如您所见,布局现在被明确地勾勒出来,这有助于我们将设计可视化。
javafx.scene.layout
包包含 Pane
等 24 个布局类(我们在 HelloWorld
示例),StackPane
(允许我们覆盖节点),FlowPane
(允许节点的位置随着窗口大小的变化而流动)和 AnchorPane
(保留 节点相对于其锚点的位置),仅举几例。 VBox
布局将在下一节中演示,Charts。
Charts
JavaFX 在 javafx.scene.chart
包中提供了 以下图表组件用于数据可视化:
LineChart
:在系列中的数据点之间添加 一条线。通常用于呈现一段时间内的趋势。AreaChart
:类似于LineChart
,但填充连接数据点和轴的线之间的区域。通常用于比较一段时间内的累计总数。BarChart
:将数据呈现为矩形条。用于离散数据的可视化。PieChart
:呈现一个分成多个段(用不同颜色填充)的圆,每个段代表一个值占总数的比例。我们将在本节中演示它。BubbleChart
:将数据呈现为称为气泡的二维椭圆形,允许呈现三个参数。ScatterChart
:按原样呈现一系列数据点。有助于识别是否存在聚类(数据相关性)。
以下示例(HellowWorld
类的 start3()
方法)演示了如何将测试结果显示为饼图图表。每个段代表测试成功、失败或忽略的数量:
我们创建了两个节点——Text
和 PieChart
——并将它们放置在 的单元格中VBox
布局,将它们设置在一列中,一个在另一个之上。我们在 VBox
窗格的边缘添加了 10 个像素的填充。请注意,VBox 扩展了 Node
和 Pane
类,就像其他窗格一样。我们还使用 setAlignment()
方法将窗格定位在场景的中心。除了场景标题和大小之外,其余部分与之前的所有其他示例相同。
如果我们运行这个例子(重命名之前的 start()
方法 start2()
,并重命名 start3()
方法 start()
),结果如下:
PieChart
类以及任何其他图表具有其他几种方法,可用于呈现 更复杂和动态的数据以用户友好的 方式。
现在,让我们讨论如何使用 Cascading Style Sheets (CSS) 的强大功能来丰富应用程序的外观和感觉.
Applying CSS
默认情况下,JavaFX 使用分发 JAR 文件附带的样式表。要覆盖默认样式,您可以使用 getStylesheets()
方法向场景添加样式表:
mystyle.css
文件必须放在 src/main/resources
文件夹中。让我们这样做,将具有以下内容的 mystyle.css
文件添加到 HelloWorld
示例中:
如您所见,我们希望设置 Button
节点和具有 Text
节点的样式">text-hello 某种方式的 ID。我们还必须修改 HelloWorld
示例,将 ID 添加到 Text
元素和样式表文件到场景中(start4()
方法):
如果我们运行这个 代码(重命名之前的 start()
方法 start3()
并将
start4()
方法重命名为 start()
),结果如下:
或者,可以在将用于覆盖文件样式表的任何节点上设置内联样式,无论是否默认。让我们在 HelloWorld
示例的最新版本中添加(取消注释)以下行:
如果我们再次运行该示例,结果将如下所示:
查看 JavaFX CSS 参考指南(https:// /docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html)了解自定义样式的多样性和可能的选项。
现在,让我们讨论另一种为 FX 应用程序构建用户界面的方法,无需编写 Java 代码,使用 FX 标记语言(FXML)。
Using FXML
FXML 是一种 基于 XML 的语言,它允许构建用户界面并独立于应用程序(业务)逻辑(如就外观而言,或其他与演示相关的更改)。使用 FXML,您甚至无需编写一行 Java 代码即可设计用户界面。
FXML 没有模式,但它的功能反映了用于构建场景的 JavaFX 对象的 API。这意味着您可以使用 API 文档来了解 FXML 结构中允许使用哪些标签和属性。大多数时候,JavaFX 类可以用作标记,它们的属性可以用作属性。
除了 FXML 文件(视图)之外,控制器(Java 类)还可用于处理模型和组织页面流。模型由视图和控制器管理的域对象组成。它还允许使用 CSS 样式和 JavaScript 的所有功能。但是,在本书中,我们将只能演示基本的 FXML 功能。其余的可以在 FXML 介绍中找到 (https ://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html)和许多在线可用的好教程。
为了演示 FXML 的使用,我们将重现我们在 Control elements 部分中创建的简单表单,然后通过添加页面流来增强它。以下是我们的表单(包含名字、姓氏和年龄)如何在 FXML 中表示:
如您所见,它 表达了您已经熟悉的所需场景结构,并指定了控制器类HelloWorldController
,它我们很快就会看到。正如我们已经提到的,这些标签与我们一直使用的类名相匹配,以仅使用 Java 构建相同的 GUI。我们将前面的 FXML 代码(作为 helloWorld.fxml
文件)放入 resources
文件夹。
现在,我们来看看 start5()
方法(重命名为 start()
) >HelloWorld 类使用 helloWorld.fxml
文件:
start()
方法 只是加载 helloWorld.fxml
文件并设置阶段,后者与我们之前的示例完全相同。
现在,让我们看看 HelloWorldController
类。如果需要,我们可以启动只有以下内容的应用程序:
表单将被显示,但按钮单击不会执行任何操作。这就是我们在谈论独立于应用程序逻辑的用户界面开发时的意思。注意 @FXML
注释。它使用它们的 ID 将方法和属性绑定到 FXML 标签。以下是完整控制器实现的外观:
在大多数情况下,它对您来说应该非常熟悉。唯一的区别是我们不是直接引用字段及其值(如前所述),而是使用标有 @FXML
注释的绑定。如果我们现在运行 HelloWorld
类(不要忘记将 start5()
方法重命名为 start()
),页面外观和行为将与我们在控制元素部分中描述的完全相同:
如果单击 Submit 按钮,输出将显示以下消息:
现在,让我们看看在 gui
文件夹中作为单独项目实现的两个页面的独立 GUI 应用程序:
如您所见,此应用程序由主要的 GuiApp
类、两个 Controller
类、User
类和两个页面(.fxml
文件)。让我们从 .fxml
文件开始。为简单起见,page01.fxml
文件的内容与前面描述的helloWorld.fxml
文件的内容几乎完全相同部分。唯一的区别是它引用了 Controller01
类,该类的 start()
方法与 start5()
方法也是前面描述的。 主 GuiApp
类看起来很简单:
如您所见,它只是调用了 Controller01
类中的 start()
方法,从而将熟悉的页面显示为你的表格:
填写完表单并点击Submit按钮后,提交的值会在Controller01
类中处理,然后传递给Controller02
类,使用 submitClicked()
方法 ="literal">Controller01 类:
Controller02.goToPage2()
方法 如下所示:
第二页只显示接收到的数据。以下是其 FXML 的外观(page2.fxml
文件):
可以看到,页面只有两个只读的Text
字段。第一个(带有 id="textHello"
)显示从前一页传递的数据。第二个只是显示消息,Do what has to be done here
。这不是很复杂,但它演示了如何组织数据流和页面。
如果我们执行 GuiApp
类,我们会看到熟悉的表格并可以用数据填充它:
当我们点击Submit按钮后,这个窗口会关闭,新的窗口会出现:
现在,我们可以单击左上角(或 Windows 右上角)的 x 按钮并看到以下消息:
stop()
方法按预期工作。
至此,我们结束对 FXML 的介绍,并转到下一个主题,即向 JavaFX 应用程序添加 HTML。
Embedding HTML
将 HTML 添加到 JavaFX 很容易。您所要做的就是使用 javafx.scene.web.WebView
类,它提供了一个窗口,添加的 HTML 在其中呈现类似于它在浏览器中发生的方式。 WebView
类使用开源浏览器引擎 WebKit,因此支持完整的浏览功能。
与所有其他 JavaFX 组件一样,WebView
类扩展了 Node
类,并且可以在 Java 代码中这样处理。此外,它有自己的属性和方法,允许通过设置窗口大小(最大、最小和首选高度和宽度)、字体比例、缩放率、添加 CSS、启用上下文(右键单击)菜单等。 getEngine()
方法返回一个与之关联的 javafx.scene.web.WebEngine
对象。它提供了加载 HTML 页面、导航它们、对加载的页面应用不同样式、访问它们的浏览历史和文档模型以及执行 JavaScript 的能力。
要开始使用 javafx.scene.web
包,首先必须执行两个步骤:
- 将以下依赖项添加到
pom.xml
文件中:
javafx-web
的版本通常与 Java 版本保持同步,但在撰写本文时,javafx-web
尚未发布,因此我们正在使用最新的可用版本,11.0.2。
- 由于
javafx-web
使用com.sun.*
包,它已从 Java 9 中删除(https://docs.oracle.com/javase/9/migrate/toc.htm#JSMIG-GUID-F7696E02-A1FB-4D5A-B1F2-89E7007D4096),访问com.sun.*
来自 Java 9+ 的包,除了--module-path
和--add-modules
,在HtmlWebView
类的Run/Debug Configuration
中的 JavaFX 基础部分中进行了描述ch12_gui
包(对于 Windows,将斜杠符号更改为反斜杠): - 要从命令行执行
HtmlWebView
类,请转到examples
文件夹并在 Unix/Linux/macOS 上使用以下命令系统(不要忘记将/path/JavaFX
替换为 包含 JavaFX SDK 的文件夹的实际路径): - 在 Windows 上,相同的 命令如下所示(不要忘记将
C:\path\JavaFX
替换为实际路径到包含 JavaFX SDK 的文件夹):
HtmlWebView
类也包含几个 start()
方法。如JavaFX基础部分所述,一一重命名并执行它们。
现在让我们看几个例子。我们创建一个新应用程序 HtmlWebView
,并使用 VM 选项(--module-path
, < code class="literal">--add-modules 和 --add-exports
) 我们已经描述过了。现在,我们可以编写和执行使用 WebView
类的代码。
首先,下面是如何将简单的 HTML 添加到 JavaFX 应用程序(HtmlWebView
类中的 start()
方法):
上述代码创建了一个WebView
对象,从中获取WebEngine
对象,使用获取到的 WebEngine
对象加载 HTML,设置场景中的 WebView
对象, 配置舞台。 loadContent()
方法接受两个字符串:内容及其 mime 类型。内容字符串可以在代码中构造或通过读取 .html
文件创建。
如果我们运行 HtmlWebView
类,结果如下:
如有必要,您可以在同一窗口中显示其他 JavaFX 节点以及 WebView
对象。例如,让我们在嵌入的 HTML 上方添加一个 Text
节点(start2()
方法">HtmlWebView 类):
如您所见, 对象不是直接在场景中设置的,而是在布局对象上设置的,以及txt
对象。然后,在场景中设置布局对象。上述代码的结果如下:
对于更复杂的 HTML 页面,可以使用 load()
方法直接从文件中加载它。为了演示这种方法,让我们在 resources
文件夹中创建一个 form.html
文件,其内容如下:
该 HTML 呈现的表单类似于我们在 使用 FXML 部分中创建的表单。点击 Submit 按钮后,表单数据被发送到服务器的 \formHandler
URI(参见 <form>
HTML 标签)。要在 JavaFX 应用程序中显示此表单,可以使用 以下代码:
如您所见,与我们其他示例的不同之处在于,我们现在使用 File
类及其 toURI()
方法直接访问 src/main/resources/form.html
文件中的 HTML,无需先将内容转换为字符串。如果您运行 HtmlWebView< 的
start3()
方法(重命名为 start()
) /code> 类, 结果如下所示:
当您需要从 JavaFX 应用程序发送请求或发布数据时,此解决方案很有用。但是,当您希望用户填写的表单已经在服务器上可用时,您可以从 URL 加载它。
例如,让我们在 JavaFX 应用程序中加入 Google 搜索。我们可以通过将 load()
方法的参数值更改为我们要加载的页面的 URL(start4( )
HtmlWebView
类的方法):
我们还在布局中添加了一个 样式,以增加字体并为背景添加颜色,因此我们可以看到嵌入渲染的 HTML 区域的轮廓。当我们运行这个例子时(别忘了把start4()
方法重命名为start()
),出现如下窗口:
在此窗口中,您 可以执行您通常通过浏览器访问的搜索的所有方面。
而且,正如我们已经提到的,您可以放大呈现的页面。例如,如果我们在前面的示例中添加 wv.setZoom(1.5)
行,结果将如下所示:
同样,我们可以设置字体的比例,甚至可以从文件中设置样式:
但是请注意,我们在 WebView
对象中设置字体比例,而在 WebEngine
对象中设置样式。
我们还可以使用 WebEngine
类方法 getDocument()
访问(和操作)加载页面的 DOM 对象:
对于历史的每个条目,我们可以提取其 URL、标题或上次访问日期:
阅读 WebView
和 WebEngine
类的文档,以获取有关如何利用它们的功能的更多想法。
Playing media
将图像 添加到 JavaFX 应用程序的 场景不需要 com.sun。 *
包,因此不需要 Embedding HTML 部分中列出的 --add-export
VM 选项。但是,无论如何拥有它们并没有什么坏处,所以如果您已经添加了它们,请保留 --add-export
选项。
可以使用 javafx.scene.image.Image
和 javafx.scene.image.ImageView
类将图像包含在场景中.为了演示如何做到这一点,我们将使用 Packt 徽标 packt.png
,它位于 resources
文件夹中。这是执行此操作的代码(HelloWorld
类的 start6()
方法):
如果我们运行上面的代码,结果如下:
当前支持的图像格式为 BMP、GIF、JPEG 和 PNG。查看 Image
和 ImageView
类的 API (https://openjfx.io/javadoc/11/javafx.graphics/javafx/scene/image/package-summary。 html) 来了解可以根据需要对图像进行格式化和调整的多种方式。
现在,让我们看看 如何 在 JavaFX 应用程序中使用其他媒体文件。播放音频或电影文件需要 嵌入 HTML 部分中列出的 --add-export
VM 选项。
目前支持的编码如下:
AAC
:高级音频编码音频压缩H.264/AVC
: H.264/MPEG-4 Part 10 / AVC (高级视频编码) 视频压缩MP3
:原始 MPEG-1、2 和 2.5 音频;第一层、第二层和第三层PCM
:未压缩的原始音频样本
您可以在 API 文档(https://openjfx.io/javadoc/11/javafx.media/javafx/scene/media/package-summary.html)。
以下三个类允许构建可以添加到场景的媒体播放器:
Media
类表示媒体的来源。 MediaPlayer
类提供了所有控制媒体播放的方法:play()
, stop ()
、pause()
、setVolume()
等。您还可以指定媒体应播放的次数。 MediaView
类扩展了 Node
类并且可以添加到场景中。它提供媒体播放器正在播放的媒体的视图,并负责媒体外观。
对于演示,让我们运行start5()
方法code class="literal">HtmlWebView 类,播放 resources
文件夹中的 jb.mp3
文件:
请注意 Media
对象 是如何基于源文件构造的。 MediaPlayer
对象是基于 Media
对象构造的,然后设置为 的属性MediaView
类构造函数。 MediaView
对象与两个 Text
对象一起设置在场景中。我们使用 VBox
对象来提供布局。最后,在场景设置在舞台上并且舞台变得可见之后(在 show()
方法完成后),play()< /code> 方法在
MediaPlayer
对象上调用。默认情况下,媒体播放一次。
如果我们执行这段代码,会出现下面的窗口并播放jb.m3
文件:
我们可以添加控件来停止、暂停和调整音量,但这需要更多的代码,这超出了本书的范围。您可以在 Oracle 在线文档 (https ://docs.oracle.com/javafx/2/media/jfxpub-media.htm)。
sea.mp4
电影 文件 可以类似地播放(HtmlWebView
类的 class="literal">start6() 方法):
唯一的区别是显示此特定剪辑的全帧所需的场景大小不同。经过几次试错调整,我们找到了必要的尺寸。或者,我们可以使用 MediaView
方法(autosize()
、preserveRatioProperty()
,
setFitHeight()
, setFitWidth()
, fitWidthProperty()
, fitHeightProperty()
和类似的)来调整嵌入窗口的大小并自动匹配场景的大小。如果我们执行前面的例子,会弹出如下窗口,播放剪辑:
我们甚至可以同时并行播放音频和视频文件,从而为电影提供配乐(HtmlWebView 的
类):start7()
方法
这样做是可能的,因为每个玩家都由自己的线程执行。
有关 javafx.scene.media
包的更多信息,请在线阅读 API 和开发人员指南,此处提供链接:
- https://openjfx.io/javadoc/11 /javafx.media/javafx/scene/media/package-summary.html
javafx.scene.media
包的API - https://docs.oracle.com/javafx/2/media/jfxpub -media.htm 获取关于
javafx 的 用法 的教程。 scene.media
包
Adding effects
javafx.scene.effects
包包含 许多允许向节点添加各种效果的类:
Blend
:使用预定义的BlendModes
之一组合来自两个来源(通常是图像)的像素Bloom
:使输入图像更亮,使其看起来发光BoxBlur
:为图像添加模糊ColorAdjust
:允许调整图像的色调、饱和度、亮度和对比度ColorInput
:渲染一个填充了给定颜料的矩形区域DisplacementMap
:将每个像素移动指定距离DropShadow
:在内容后面渲染给定内容的阴影GaussianBlur
:使用特定(高斯)方法添加模糊发光
:使输入图像看起来发光InnerShadow
:在框架内创建阴影Lighting
:模拟光源照射在内容上,使平面物体看起来更逼真MotionBlur
:模拟运动中看到的给定内容PerspectiveTransform
:转换透视图中的内容Reflection
:在实际输入内容下方呈现输入的反射版本SepiaTone
:产生棕褐色调效果,类似于古董照片的外观Shadow
:创建带有模糊边缘的内容的单色副本
所有效果共享父类,即Effect
抽象类。 Node
类有 setEffect(Effect e)
方法,这意味着可以将任何效果添加到任何节点。这是将效果应用于节点的主要方式——在舞台上产生场景的演员(如果我们回想一下本章开头介绍的类比)。
唯一的例外是 Blend
效果,这使得它的使用比其他效果的使用更复杂。除了使用 setEffect(Effect e)
方法,一些 Node
类的子类也有 setBlendMode(BlendMode bm)
方法,允许调节图像在重叠时如何相互融合。因此,可以以不同的方式设置不同的混合效果,这些效果相互覆盖并产生可能难以调试的意外结果。这就是使 Blend
效果使用更加复杂的原因,这就是为什么我们要开始概述 Blend
可以使用效果。
三个方面调节两个图像重叠区域的外观(我们在示例中使用两个图像以使其更简单,但在实践中,许多图像可以重叠):
- opacity 属性的值:这定义了可以通过图像看到多少; opacity 值 0.0 表示图像完全透明,而 opacity 值 1.0 表示图像后面什么都看不到。
- 每种颜色的 alpha 值和强度:这将颜色的透明度定义为 0.0-1.0 或 0-255 范围内的双精度值。
- 混合模式,由 BlendMode 枚举值定义:根据每种颜色的模式、不透明度和 alpha 值,结果可能还取决于图像的顺序添加到场景中;第一个添加的图像称为底部输入,而重叠图像中的第二个称为顶部输入。如果顶部输入完全不透明,则底部输入被顶部输入隐藏。
重叠区域的最终外观是根据不透明度、 颜色的 alpha 值、颜色的数值(强度)和混合模式计算得出的,可以是以下之一:
ADD
:将顶部输入的颜色和 alpha 分量添加到底部输入的分量中。BLUE
:将底部输入的蓝色分量替换为顶部输入的蓝色分量;其他颜色分量不受影响。COLOR_BURN
:底部输入颜色分量的倒数除以顶部输入颜色分量,然后将所有这些分量反转以产生结果颜色。COLOR_DODGE
:底部输入颜色分量除以顶部输入颜色分量的倒数以产生结果颜色。DARKEN
:从两个输入中选择较暗的颜色分量来生成结果颜色。DIFFERENCE
:从两个输入中较暗的颜色分量从较亮的分量中减去,以产生结果颜色。EXCLUSION
:将两个输入的颜色分量相乘和加倍,然后从底部输入颜色分量的总和中减去,以产生结果颜色。GREEN
:将底部输入的绿色分量替换为顶部输入的绿色分量;其他颜色分量不受影响。HARD_LIGHT
:输入颜色分量是相乘还是筛选,取决于顶部输入颜色。LIGHTEN
:选择来自两个输入的颜色分量中较亮的一个来产生结果颜色。MULTIPLY
:第一个输入的 颜色分量乘以第二个输入的颜色分量。OVERLAY
:根据底部输入颜色,输入颜色分量是相乘还是加网。RED
:将底部输入的红色分量替换为顶部输入的红色分量;其他颜色分量不受影响。SCREEN
:来自两个输入的颜色分量被反转,相互相乘,并且该结果再次反转以产生结果颜色。SOFT_LIGHT
:输入颜色分量变暗或变亮,取决于顶部输入颜色。SRC_ATOP
:位于底部输入内部的顶部输入部分与底部输入混合。SRC_OVER
:顶部输入与底部输入混合。
为了演示 Blend
效果,让我们创建另一个应用程序,名为 BlendEffect
。它不需要 com.sun.*
包,因此不需要 --add-export
VM 选项。只有 --module-path
和 --add-modules
选项,在 中描述JavaFX 基础 部分,必须设置为编译和执行。
本书的范围不允许我们展示所有可能的组合,因此我们将创建一个红色圆圈和一个蓝色方块(参见 BlendEffect
类):
我们使用 Color.rgb(int red, int green, int blue, double alpha)
方法来定义每个颜色的数字,但还有更多的方法可以做到这一点。阅读 Color
类 API 文档了解更多详情(https://openjfx.io/javadoc/11/javafx.graphics/javafx/scene/paint/Color.html)。
为了重叠创建的圆形和正方形,我们将使用 Group
节点:
在前面的代码中,正方形是底部输入。我们还将创建一个组,其中正方形是顶部输入:
区别很重要,因为我们将圆形定义为半透明,而正方形则 完全不透明。我们将在所有示例中使用相同的设置。
让我们比较一下 MULTIPLY
和 SRC_OVER
这两种模式。我们将使用 setEffect()
方法将它们设置在组上,如下所示:
在被调用的 BlendEffect
类的 start()
方法中,对于每种模式,我们创建两个组,其中一个输入为圆形在正方形的顶部,另一个带有输入的正方形在圆形的顶部,我们将四个创建的组放在 GridPane
布局中(参见详细的源代码)。如果我们运行 BlendEffect
应用程序,结果如下:
正如预期的那样,当正方形在顶部时(右侧的两个图像),重叠区域 完全被不透明的正方形占据。但是,当圆形是顶部输入时(左侧的两个图像),重叠区域在某种程度上是可见的,并且是根据混合效果计算得出的。
但是,如果我们直接在组上设置相同的模式,结果会略有不同。让我们运行相同的代码,但在组上设置模式:
在 start()
方法中找到以下代码:
并将其更改为以下内容:
如果我们再次运行 BlendEffect
类,结果将如下所示:
可以看到,圆圈的红色略有变化,MULTIPLY
和 SRC_OVER
模式没有区别。这就是我们在本节开头提到的将节点添加到场景的顺序的问题。
结果还 根据设置效果的节点而变化。例如,我们只在圆上设置效果,而不是在组上设置效果:
在 start()
方法中找到以下代码:
并将其更改为以下内容:
我们运行应用程序并看到以下内容:
右边的两个图像与前面所有示例中的相同,但左边的两个图像 显示了重叠区域的新颜色。现在,让我们在正方形而不是圆形上设置相同的效果,如下所示:
在 start()
方法中找到以下代码:
并将其更改为以下内容:
结果将再次略有变化,如下图所示:
MULTIPLY
和 SRC_OVER
模式之间没有 区别,但是红色颜色与我们在圆圈上设置效果时不同。
我们可以再次改变方法,只在圆上直接设置混合模式,使用以下代码:
在 start()
方法中找到以下代码:
并将其更改为:
结果又变了:
在方块上设置混合模式只会再次消除 MULTIPLY
和 SRC_OVER
模式之间的差异。
并将其更改为以下内容:
结果如下:
为避免混淆并使混合结果更可预测,您必须注意将节点添加到场景中的顺序以及应用混合效果的方式的一致性。
在本书提供的源代码中,您将找到javafx.scene.effects
包中包含的所有效果的示例。它们都通过并排比较得到证明。这是一个例子:
为方便起见,提供了 Pause 和 Continue 按钮,可让您暂停演示并查看不同值的结果在混合效果上设置不透明度。
为了演示所有其他效果,我们创建了另一个应用程序,称为 OtherEffects
,它也不需要 com.sun.*
包,因此不需要
--add-export
VM 选项。演示的效果包括 Bloom
、BoxBlur
、ColorAdjust
、DisplacementMap
, DropShadow
, 发光
, InnerShadow
, Lighting
, MotionBlur
, PerspectiveTransform
, 反射
、ShadowTone
和SepiaTone
。我们使用了两张图片来展示应用 每种效果的结果(Packt 徽标和山湖景观):
我们还添加了两个按钮,允许您暂停和继续演示(它会迭代效果及其参数的值):
et
对象是 EffectsThread
线程的对象:
线程遍历效果列表,创建对应的效果 10 次(具有 10 个不同的效果参数值),并且每次都在每个效果上设置创建的 Effect
对象图像,然后休眠 1 秒,让您有机会 查看结果:
我们将在带有效果结果的屏幕截图下展示接下来如何创建每个效果。为了呈现 结果,我们使用了 GridPane
布局:
最后,将创建的 GridPane
对象传递给场景,然后将其放置在我们之前示例中熟悉的舞台上:
以下 屏幕截图描述了 13 个参数值中每个参数值的效果示例。在每个屏幕截图下,我们展示了创建此效果的 createEffect(String effect, double d, Text txt)
方法的代码片段:
- 参数值 1 的影响:
- 参数值 7 的影响:
本演示的完整源代码 随本书提供,可在 GitHub 上获取。
Quiz
- JavaFX 中的顶级内容容器是什么?
- JavaFX 中所有场景参与者的基类是什么?
- 命名 JavaFX 应用程序的基类。
- JavaFX 应用程序必须实现的一种方法是什么?
Application
方法必须由main
方法调用才能执行 JavaFX 应用程序?- 执行 JavaFX 应用程序需要哪两个 VM 选项?
- 使用右上角的 x 按钮关闭 JavaFX 应用程序窗口时会调用哪个
Application
方法? - 必须使用哪个类来嵌入 HTML?
- 说出三个必须用来播放媒体的类。
- 播放媒体需要添加什么 VM 选项?
- 说出五种 JavaFX 效果。