0%

二进制I/O

17.1 引言

文件分类:

可以使用文本编辑器进行处理(读取、创建或者修改)的文件被称为文本文件。所有

所有其他的文件都被称为二进制文件。

不能使用文本编辑器来读取二进制文件——它们是为让程序来读取而设计的。就像,Java源程序存储在文本文件中,可以使用文本编辑器读取,而Java类是二进制文件,由Java虚拟机读取。

可以简单的认为: 文本文件是由字符序列构成的,而二进制是由位bit序列构成的。

二进制文件的优势在于它的处理效率比文本文件高。

17.2 在Java中如何处理文本I/O

要点提示: 使用Scanner类读取文本数据,使用PrintWriter类写文本数据。

File类: 封装了文件或路径属性,但是不包含从/向文件读/写数据的方法。

I/O类: 包含从/向文件读/写数据的方法。

输出对象: 输出流

输入对象: 输入流

17.3 文本I/O与二进制I/O

要点提示 :二进制I/O不涉及编码和解码,所以更高效

计算机并不区分二进制文件和文本文件。所有的文件都是以二进制形式来存储的,从本质上来说,所有的文件都是二进制的。

文本I/O能提供一层抽象,用于字符串层次的编码和解码。对于文本I/O,编码和解码是自动进行的。

对于文本编辑器或文本输出程序创建的文件,应该使用文本输入来读取,对于Java二进制输出程序创建的文件,应该使用二进制输入来读取。

二进制I/O不需要编码和解码,所以它的效率更高。同时,由于二进制文件与主机的编码方案无关,因此,它是可移植的。这也是Java的类文件存储为二进制文件的原因。

17.4 二进制I/O类

*要点提示: *抽象类InputStream是读取二进制数据的根类,抽象类是OutputStream是写入二进制数据的根类。

image-20200531193633640

image-20200531193655448

注意: 二进制I/O类中所有方法都声明为抛出java.io.IOException或java.io.IOException的子类

![image-20200531193942861](/Users/bowenkei/Library/Application Support/typora-user-images/image-20200531193942861.png)

17.4.1 FileInputStream和FileOutputStream

image-20200531194126051

如果为一个不存在的文件创建一个FileInputStream对象,将会发生java.io.FileNotFountException异常

image-20200531194506941

使用FileOutputStream构造方法创建对象时,如果这个文件不存在,就会创建一个新的文件

当文件已存在的时候,使用以下两个方法将会删除点文件中已经存在的内容:

1
2
FileOutputStream(file: File)
FileOutputStream(filename: String)

为了既保留文件现有内容又可以给文件追加新数据,可以在创建一个FileOutputStream对象时,添加append参数,并将其值设置为true。

几乎所有的I/O类都会抛出java.io.IOException。所以,必须在方法中声明会抛出java.io.IOException异常,或者将代码放到try-catch块中。

程序清单17-1使用二进制I/O将从1到10的10个字节值写入一个名为temp.dat的文件,再把他们从文件中读出来。

使用try-with-resource来声明和创建输入输出流,从而在使用后可以自动关闭。

java.io.InputStream和java.io.OutputStream实现了AutoClosable接口。

AutoClosable接口定义了close()方法,用来个关闭资源。任何AutoClosable类型的对象可以用于try-with-resources语法中,实现自动关闭。

二进制文件可以从程序中读取它,但是不能用文本编辑器阅读它。

提示:当流不再使用时,记得使用close()方法将其关闭,或者使用try-with-resource语句自动关闭。不关闭流可能会在输出文件中造成数据受损,或导致其他的程序设计错误。

*注意: *FileInputStream类的实例可以作为参数去构造一个Scanner=对象, FileOutputStream类的实例可以作为参数构造一个Printerwriter对象。可以创建一个PrintWriter对象来向文件中追加文本。如果xx.txt不存在,就会创建这个文件。如果xx.txt文件已经存在,就将新数据追加到该文件中。

1
new Printer(new FileOutputStream("xx.txt", true));

FileterInputStream 和 FilterOutputStream

过滤器数据流(file stream)是为某种目的过滤字节的数据流。读取整数值、双精度值和字符串,那就需要一个过滤类来包装字节输入流。使用过滤器类就可以读取整数值、双精度值和字符串,而不是字节或字符。

FileterInputStream 和 FilterOutputStream是过滤数据的基类。需要处理基本数值类型时,就是用DataInputStream和DataOutputStream类来过滤字节。

###DataInputStream和DataOutputStream

image-20200601195913906

image-20200601195934714

基本类型的值不需要做任何转化就可以从内存复制到输出数据流。字符串的字符可以写成多种形式 :

  1. 二进制I/O中的字符与字符串

一个统一码由两个字节构成。writerChar(char c )方法将字符c的统一码写入输出流。writerChars(String s )方法将字符串s中的所有字符的统一码写到输出流中。writeBytes(String s )方法将字符串s中的每个字符的统一码的低字节写入到输出流。统一码的高字节被抛弃。

writeBytes(String s )方法适用于由ASCII码构成的字符串,ASCII码仅存储统一码的低字节。如果毕业字符串包含非ASCII码的字符,就必须使用writeChars方法实现写入这个字符串。

writeUTF(String s )方法将两个字节的长度信息写入输入流,后面紧跟着的是字符串s中的每个字符的改进版UTF-8的形式。

image-20200601201352901

*警告: *

应该按存储的顺序和格式读取文件中的数据。

  1. 检测文件的末尾

如果达到InputStream的末尾之后还继续从中读取数据,就会发生EOFException异常。这个异常可以用来检查是否已经到达文件末尾。

BufferedInputStream 和 BufferedOutputStream

BufferedInputStream 和 BufferedOutputStream没有包含新的方法,它们的方法都是从InputStream 和OutputStream继承而来的。它们在后来管理了一个缓冲区,根据要求自动从磁盘中读取数据和写入数据。

image-20200602160930843

image-20200602161036165

缓冲区指定大小是512字节。

*提示: *应该总是使用缓冲区I/O来加速输入和输出。

17.5 示例学习: 复制文件

17.6 对象I/O

要点提示:ObjectInputStream 和ObjectOutputStream类可以用于读/写可序列化的对象。

ObjectInputStream 和ObjectOutputStream类除了实现基本数据类型与字符串的输入和输出之外,还可以实现对象的输入和输出。因而,可以使用ObjectInputStream 和ObjectOutputStream类代替DataInputStream和DataOutputStream。

读取时为了得到所需的数据类型,必须使用Java安全的类型转换。例如:

1
Date date = (Date)(inputStream.readObject());

readObject()方法可能会抛出ClassNotFoundException.注意使用时要抛出它

17.6.1 Serializable 接口

可以写入到输出流中的对象被称为可序化的。

可序化对象的类必须实现Serializable接口。

Serializable是一个标记接口。它没有方法,不需要在类中为实现Serializable接口增加额外的代码。实现这个接口可以启动Java的序列化机制,自动完成存储对象和数组的过程。

Java提供一个内在机制自动完成写对象的过程。这个过程称为对象序列化(object serialization),它是在ObjectOutputStream中实现的。相反,读取对象的过程称作反对象序列化(object deserialization),它是在ObjectInputStream中实现的。

试图存储一个不支持Serializable接口的对象会引起一个NotSerializableexception异常。

当存储一个可序列化对象时,会对该对象的类进行编码。编码包括类名、类的签名、对象实例变量的值以及该对象引用的任何其他对象的闭团,但是不存储对象静态变量的值。

注意: 非序列化的数据域

如果一个对象是Serializable的实例,但它包含了非序列化的实例数据域,那么就不可以序列化这个对象。为了使该对象是可序列化的,需要给这些数据域加上关键字transient,告诉Java虚拟机将对象写入流时忽略这些数据域。看下面的例子:

image-20200602201849302

注意: 重复的对象

如果一个对象不止一次写入对象流,不会存储对象的多分副本。第一次写入一个对象时,就会为它创建一个序列号。Java虚拟机将对象的所有内容和序列号一起写入对象流。以后每次存储时,如果再写入相同的对象,就只存储序列号。读出这些对象时,它们的引用相同,因为在内存中实际上存储的只是一个对象。

17.6.2 序列化数组

如果数组中所有元素都是可序列化的,那这个数组就是可序列化的。一个完整的数组可以使用writeObject方法写入文件,随后使用readObject方法恢复。

17.7 随机访问文件

*要点提示: *Java提供了RandomAccessFile类,允许从文件的任何位置进行数据的读写。

只读的流或者只写的流被称为顺序(sequential)流。使用顺序流打开的文件被称为顺序访问文件。顺序访问文件的内容不能更新。

使用RandomAccessFile类打开的文件称为随机访问文件。

RandomAccessFile类实现了DateInput和DataOutput接口。

image-20200603110915507

创建一个RandomAccessFile时,可以指定两种模式(“r”,“rw”)。

1
RandomAccessFile raf = new RandomAccessFile("test.dat", "rw");

如果test.dat 已经存在,则创建raf以便访问这个文件,否则就创建一个名为test.dat的新文件,再创建raf以便访问这个文件。raf.length()返回给定时刻文件test.dat中的字节数。向文件中追加数据,raf.length就会增加。

image-20200603111803022

在RandomAccessFile中使用setLength(0)方法将文件长度设置为0。这样做的效果是将文件的原有内容删除。

JavaFx UI组件和多媒体

引言JavaFX提供了许多UI组件,用于开发全面的用户界面

Oracle公司提供了可视化设计和开发GUI的工具。这使得程序员可以用最少的编码快速将图形用户界面(GUI)元素组装在一起,然而,任何工具都不是万能的。有时需要修改这些工具生成的程序。所以,理解JavaFx GUI程序设计的一些基本概念非常有必要。

-w1120

-w1154

Labeled和Label

要点提示 :JavaFX提供了许多组件,用于开发全面的用户界面

标签(label)是一个显示小段文字、一个节点或同时显示两者的区域。它通常用来给其他组件(通常是文本域)做标签。

标签和按钮共享许多共同的属性。这些属性定义在Labeled类中。
-w1144

Label可以使用下面三种构造方法的其中之一进行构建,如图:
-w1080

Graphic属性可以是任何一个节点,比如一个形状、一个图像或者一个组件。

*注意: *
使用ContentDisplay()用于设置的不是标签相对于图像节点的位置,而是图像节点相对于标签的位置
HBox将所有节点放在水平线上

按钮

button是单击时触发动作时间的组件。JavaFx提供了常规按钮、开关按钮、复选框按钮和单选按钮。这些按钮的共同特性在ButtonBase和Label类中定义。

按钮与标签非常相似,除了按钮具有定义在ButtonBase类中的onAction属性,该属性设置一个用于处理按钮动作的处理器。
-w1128

*注意: *
BorderPane是这样一个面板: 将节点放置在顶部、右边、底部、左边以及中间区域

复选框

复选框用于提供给用户进行选择。
复选框提供了selected属性用于表明一个复选框是否被选中。

-w1113

VBox: 节点放在单列里
HBox: 节点放在单行里

单选按钮 radio button

又称为选项按钮,用于让用户从一组选项中选择一个单一的条目。

外观上单选按钮类似于复选框
复选框是方形的,可以选中或者不选中
单选按钮显示一个圆,或是填充的或是空白的。分别对应选中和未选中
RadioButton是ToggleButton的子类。单选按钮和开关按钮的不同之处是,单选按钮显示一个圆,而开关按钮渲染成类似按钮
-w1142

-w1132

文本域 text filed

可以用于输入或者显示一个字符串。
TextField是TextInputControl的子类。
-w1150
注意: *
如果一个文本域用于输入密码,使用PasswordField来替代TextFiled。PasswordField继承自TextField,将输入文本隐藏为回显字符
…..

文本区域 TextArea

要点提示: TextArea允许用户输入多行文本
如果需要让用户输入多行文本,可以创建多个TextField的实例。或者选择使用TextArea,它允许用户输入多行文本
-w1120

TextArea提供滚动支持,但是通常而言,创建一个ScrollPane对象来包含一个TextArea的实例,并且让ScrolPane处理TextArea的滚动会更加方便。
提示: 可以将任何节点放置在ScrollPane中。如果空间太大以至于不能在显示区域内完整显示,ScrollPane提供了垂直和水平方向的自动滚动支持

组合框 combo box

要点提示 :组合框也称为选择列表(choice list)或下拉式列表(drop-down),他包含一个条目列表,用户能够从中进行选择。

组合框可以限制用户的选择范围,并避免对输入数据有效性进行繁琐的检查。以下为ComBox类中的一些常用的属性和构造方法。

image-20200520224822234

ComboBox定义为一个泛型类。泛型T为保存在一个组合框中的元素指定元素类型。

ComBox继承自ComBoxBase。ComBox可以触发一个ActionEvent事件。当一个条目被选中后,一个ActionEvent事件被触发。

ObservableList是Java.util.List的子接口,因此你可以将定义在List中的所用方法应用于ObservableList。

JavaFX提供了一个静态方法FXCollections.observableArrayList(arrayOfElements)来从一个元素数组中创建一个ObservableList。

列表视图 ListView

ListView是一个泛型类。泛型T为存储在一个列表视图中的元素指定了元素类型。

如下是: ListView的详细:

image-20200521175156890

getSelectionModel()方法返回一个SelectionModel实例,该实例包含了设置选择模式以及获得被选中的索引值和条目的方法。

选择模式由以下连个常量之一定义,分别是SelectionMode.MULTIPLE和SelectionMode.SINGLE。它们表明可以选择单个还是多个条目。默认为SINGLE.

image-20200521175948759

注意⚠️

程序代码运行之后,在列表视图中具体实现多选需要结合特定的按键。例如在mac os上,按住command的同时,用鼠标多选项目即可。

滚动条 ScrollBar

要点提示: ScrollBar是一个允许用户从一个范围的值中进行选择的组件

用户可以通过鼠标操作改变滚动条的值。

ScrollBar的属性如下:

image-20200521221513304

注意: 滚动条的轨道宽度对应于max + visibleAmount。当一个滚动条设置为它的最大值时,块的左侧位于max,右侧位于max + visibleAmount。

实际操作中的经验: 想要实现拖动滑动条移动Text的位置,必须将文本放在一个面板中,然后面板置于边框面板的中央。如果文本直接放在边框面板的中央,不能通过重设它的x和y属性改变文本的位置。

滑动条 Slider

要点提示 :Slider与ScrollBar类似,但是Slider有更多属性,并且可以以多种形式显示。Slider允许用户通过在一个有界的区间中滑动滑块,从而以图形方式选择一个值。滑动条可以显示区间中的主刻度以及次刻度。刻度之间的像素值是由majorTickUnit和minorTickUnit属性指定的,分别表示主像素和次要像素。

滑块可以水平显示也可以垂直显示,可以带刻度可以不带刻度。

image-20200522092106948

注意:垂直滚动条的值从上向下是增加的,但是垂直滑动条的值从上到下是减少的。

示例学习: 开发一个井字游戏

*注意: *在开发和测试一个Java项目时,可以采用渐进的方法。

视频和音频

*要点提示: *使用Media来获得媒体源,使用MediaPlayer类来播放和控制媒体,使用MediaView来显示视频。

媒体(视频和音频)对于开发富因特网应用是必要的。

JavaFX支持MP3、AIFF、WAV以及MPEG-4音频格式以及FLV和MPEG-4视频格式。

Media类代表了一个媒体源,具有duration、width以及height属性。

可以从一个Internet URL字符串中创建以一个Media对象。

image-20200527152400018

MediaPlayer类播放媒体,并通过一些属性来控制媒体播放,比如autoPlay、currentCount、cycleCount、mute、volume和totalDuration。可以从一个媒体对象来构建一个MediaPlayer对象,并使用pause()、play()方法来暂停和继续播放。

MediaView类是Node的子类,提供MediaPlayer播放的Media视图。MediaView类提供了一些属性用于观看媒体。

image-20200527152730968

Media,MediaPlayer,MediaView的关系如下:
image-20200527155944537

一个Media对象支持实时流媒体。一个Media对象可以被多个播放器共享,并且不同的视图可以使用同一个MediaPlayer对象。

Java 事件驱动编程和动画

引言

要点提示: 可以编写代码以处理诸如单击按钮、鼠标移动以及按键盘之类的时间。

为了响应一个按钮单击事件,你需要编写代码来处理按钮单击动作。按钮是一个事件源对象,即动作起源的地方。需要创建一个能对一个按钮动作事件进行处理的对象,即事件处理器。

image-20200522103644432

不是多有对象都可以成为一个动作事件的处理器。要成为一个动作事件的处理器,必须满足两个要求:

  1. 该对象必须是EventHandler接口的一个示例。接口定义了所有处理器的共同行为。T extends Event是一个Event子类型的泛型。
  2. EventHandler对象handler必须使用方法source.setOnAction(handler)和事件源对象注册
  3. EventHandler 接口包含了 handle ( ActionEvent ) 方法用于处理动作事件。你的处理器类必须覆盖这个方法来响应事件 。 15 ActionEvent 事件的代码 。

事件和事件源

要点提示: 事件是从一个事件源上产生的对象。触发一个事件意味着产生一个事件并委托处理器处理该事件。

事件驱动编程: 当运行一个Java GUI程序的时候,程序和用户进行交互,并且事件驱动它的执行。这称为事件驱动编程。

事件可以被定义为一个告知程序某件事发生的信号。

事件由外部的用户动作,比如鼠标的移动、单击和键盘按键所触发。

事件源对象: 产生一个事件并且出发它的组件称为事件源对象,或称为源对象或者源组件。

image-20200522110409887

注意:如果一个组件可以触发一个事件,那么这个组件的任何子类都可以触发同样类型的事件。比如,每个JavaFX形状、布局面板和组件都可以触发MouseEvent和KeyEvent事件,因为Node是形状、布局面板和组件的超类。

image-20200522110728861

注册处理器和处理事件

要点提示: 处理器是一个对象,它必须通过一个事件源对象进行注册,并且它必须是一个恰当的事件处理接口的实例。

image-20200522111645923

技巧:设计一个类来建模一个包含了支持方法的面板是一个好的策略,这样相关的方法和面板都耦在一个对象中来。

内部类

要点提示: 内部类,或者称为嵌套类,是一个定义在另外一个类范围中的类。内部类对于定义处理器非常有用。

一个内部类可以如常规类一样使用。通常,在一个类只被它的外部类所使用的时候,才将它定义为内部类。

一个内部类具有下面的特征:

  • 一个内部类被被编译为OuterClassName$InnerClassName的类。
  • 一个内部类可以引用定义在它所在的外部类中的数据和方法。所以,没有必要将外部类对象的引用传递给内部类的构造方法。内部类可以使程序更加精简。
  • 一个内部类可以使用可见性修饰符所定义,和应用于一个类中的成员的可见性规则一样
  • 一个内部类可以被定义为static。一个static的内部类可以使用外部类的名字所访问。一个static的内部类不能访问外部类中非静态成员。
  • 内部类对象通常在外部类中所创建。也可以从另外一个类中来创建一个内部类的对象。如果内部类是非静态的,你必须先创建一个外部类的实例,然后使用以下语法来创建一个内部类的对象。
1
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
  • 如果内部类是静态的,使用以下语法来创建一个内部类对象。
1
OuterClass.InnerClass innerObject = new OuterClass.InnerClass();

内部类的用途:

  • 将相互依赖的类结合到一个主类中
  • 避免类名的冲突

一个处理器类被设计为针对一个GUI组件创建一个处理器对象(比如,一个按钮)。处理器类不会被其他应用所共享,所以将它定义在主类里面作为一个内部类是恰如其分的。

匿名内部类处理器

要点提示:一个匿名内部类是一个没有名字的内部类。它将进一步实现定义一个内部类以及创建一个内部类的实例。

下面是一个内部类被匿名内部类替代的示例:

image-20200522154958242

匿名内部类的语法如下所示:

1
2
3
4
5
new superClassName/InterfaceName(){
// Implement or override methods in superclass or interface
// Other methods if necessary

}

匿名内部类是一种特殊类型的内部类,它被当作一个内部类对待,同时具有下面的特征:

  • 一个匿名内部类必须总是从一个父类继承或者实现一个接口,但是它不能有显式的extends或者implements子句
  • 一个匿名内部类必须实现父类或者接口中的所有抽象方法
  • 一个匿名内部类总是使用它父类的无参构造方法来创建一个实例。如果一个匿名内部类实现一个接口,构造方法是Object().
  • 一个匿名内部类被编译成一个名为OuterClassName$n.class。

例如如果外部类Test有两个匿名的内部类,它们将被编译成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

## 使用lambda表达式简化事件处理

要点提示: lambda表达式可以用于极大简化事件处理器的代码编写.

lambda表达式可以被看作使用精简语法的匿名内部类。

如图是将匿名内部类用lambda表达式代替的一个例子:

![image-20200524001209498](https://tva1.sinaimg.cn/large/007S8ZIlly1gf2u5ud8zgj31qq0kmdrp.jpg)

一个lambda表达式的基础语法是:

```java
(type1 parm1, type2 parm2, ...) -> expression

或者

1
(type1 parm1, type2 parm2, ...) -> {statements;}

一个参数的数据类型既可以显式声明,也可以由编译器隐式推断。如果只有一个参数,并且没有显示的数据类型,圆括号可以被省略。

因而上面(截图)的例子可以表示为:

1
2
3
e -> {
// Code for processing event e
}

image-20200524124547574

示例学习: 贷款计算器

示例学习: 鼠标事件

要点提示:当一个鼠标按键在一个节点或者一个场景中被按下、释放、单击、移动或者拖动时,一个MouseEvent事件被触发。

MouseEvent对象捕捉事件,例如和它相关的单击数、鼠标位置或者那个叫鼠标按键被按下:

image-20200524151800627

四个常数——PRIMARY,SECONDARY,MIDDLE和None在MouseEvent中被定义,表明鼠标的左、右、中以及无按钮。shiyonggetButton()方法来探测哪个按钮被按下。

在任何节点和场景都可触发鼠标事件。

键盘事件 KeyEvent

要点提示:在一个节点或者一个场景上面只要按下、释放或者敲击键盘,就会触发一个KeyEvent事件。

键盘事件使得可以采用键盘来控制和执行动作,或者从键盘获得输入。KeyEvent对象描述了事件的性质(即,一个按键被按下释放或者敲击)以及键值。

image-20200524154213607

每个键盘事件有一个相关的编码,可以通过KeyEvent的getCode()方法返回。键的编码是定义在KeyCode中的常量。KeyCode是一个enum类型的变量。

对于按下键和释放键的事件,getCode()返回表中的值, getText()返回一个描述键的代码的字符串, getCharacter()返回一个空字符串。对于敲击键额事件,geCode()返回UNDEFINED, getcCharacter()返回相应的Unicode字符或者和敲击事件相关的一个字符序列。

image-20200524154812371

image-20200524154825125

注意

在一个枚举类型值的switch语句中,case后面跟的是枚举常量。常量是不受限制的(unqalified)即无须加KeyCode等类限定。例如: 在case子句中使用keyCode.DOWN将出现错误。

只有一个被拒交的节点可以接受KeyEvent事件。在一个text上调用requestFocus()使得text可以接受键盘输入。这个方法必须在舞台被显示后调用。

注意: 单击一个按钮之后,circlePane将不再被聚焦,为了修复这个问题,可以在每次按钮被单击后,在circlePane上再次调用requestFocus()。

可观察对象的监听器

*要点提示: *可以通过添加一个监听器来处理可观察对象中的值的变化

一个Observable类的实例被认为是一个可观察对象,它包含了一个addListener(InvalidationListener listener)方法用于添加监听器。监听器类必须实现InvalidationListenr接口以重写invalidate(Observable o)方法,从而可以处理值的改变。一旦observable中的值改变了,通过调用invalidate(Observable o)方法,监听器得到通知。每个绑定属性都是Observable的实例。

可以使用lambda来简化添加监听器的流程。注意处理器使用的是e,监听器使用的是ov。

动画

*要点提示: *JavaFx中的Animaiton类为所有的动画制作提供了核心功能。

JavaFX提供了许多Animation的具体子类。

image-20200524191335802

其中autoReverse是一个Boolean属性,表示下一周期中动画是否要倒转方向。cycleCount表示了该动画的循环次数。使用Tiemline.INDEFINTE表示无限循环。rate定义了动画的速度。一个负的rate值表示动画的相反方向。status是只读属性,表明了动画的状态(Animation.Status.PAUSED、Animation.Status.RUNNING和Animation.Status.STOPPED)。方法pause(),play(),stop()分别表示暂停、播放和终止动画。

PathTrasition

PathTrasition类制作一个在给定时间,节点沿着一条路从一个端点到另一个端点的移动动画,PathTransition是Animation的子类型。

image-20200524192103626

Duration类定义了持续事件。它是一个不可更改的类。这个类定义类常量INDEFINTE,ONE,UNKNOW和ZERO来代表一个无限循环、1毫秒、未知以及哦的持续时间。可以使用new Duration(double millis)来创建一个Duration实例,使用add、substract、multiply和divide方法来执行算数操作,还可以使用toHours(),toMinutes(),toSeconds()和tomMillis()来返回持续时间值中的小时数、分钟数、秒钟数和毫秒数。还可以使用comPareTo来比较两个持续时间。

常量NONE和ORTHOGONAL_TO_TANGET在PathTransiton.OrientationType中定义。后者确定节点在沿着几何路径移动的过程中是否和路径的切线保持垂直。

FadeTransition

FadeTransition类在一个给定的时间内,通过改变一个节点的透明度来产生动画。FadeTransition是Animation的子类型。

image-20200525230347355

Timeline

PathTransition和FadeTransition定义类的特定的动画。Timeline类可以通过使用一个或者更多的KeyFrame(关键帧)来编写任意动画。每个KeyFrame在一个给定的时间间隔内顺序执行。Timeline继承自Animation。

通过new Timeline(KeyFrame… keyframe)来构建一个Timeline。

一个KeyFrame可以使用以下语句来构建:

1
new KeyFrame(Duration duration, EeventHandler<ActionEvent> onFinished)

处理器onFinished方法当这个关键帧的持续时间结束后被调用。

示例学习 :弹球

第一章 启程

1.2 历史背景

Steve Jobs 成立了NeXT公司。NeXT选择Unix作为其操作系统,创建了NextSTEP。NextSTEP后被命名为Cocoa。

1.3 内容简介

oc是C语言的一个扩展集。

Swift初见

简单值

使用let来宣告常数,使用var来宣告变数

常数或者变数的型别必须和你赋给它们的值一样。但是不一定在声明的时候显示声明类型,因为编译器会自动推断类别。

如果初始值没有提供足够的资讯(或者没有初始值),就需要在变数后面宣告类型,用冒号分隔,例如:
let implicitDouble = 70.0
let explicitDouble: Double = 70

值永远不会被隐式转换为其他类别。如果需要对值进行转换,需要显示转换 例如:
let label = “The width is “
let width = 94
let widthLabel = label + String(width)

JavaFX基础

javaFX是学习面向对象编程的优秀教学工具

JavaFX与Swing以及AWT的比较

要点提示: JavaFX用于开发富因特网应用

富因特网应用是一种Web应用,可以表现一般桌面应用具有的特点和功能。JavaFX可以无缝地在桌面或者Web浏览器中运行。

JavaFX程序的基本结构

要点提示 : 抽象类 javafx . application . Application 定义编写 JavaFX 程序的基本框架 。

面板、UI组件以及形状

要点提示: 面板、UI组件以及形状是Node的子类型
-w247
(各个部分的包含情况)

属性绑定

要点提示: 可以将一个目标对象绑定到源对象中。源对象的修改将自动反应到目标对象中。

属性绑定: 将一个目标对象和一个源对象绑定。如果源对象中的值改变了,目标对象也将自动改变。目标对象称为绑定对象或者绑定属性,源对象称为可绑定对象或者可观察属性。

一个属性既可以作为目标,也可以作为源。目标监听源中的变换,一旦源中发生变化,目标将自动更新自身。
一个目标采用bind方法和源进行绑定,如下所示:
target.bind(source);
-w660
绑定的演示:
-w667

双向绑定
这样,一个属性的改变将反应到另一个对象上,反过来也一样,这样的绑定叫做双向绑定。如果目标和源同时是绑定属性和可观察熟悉你个,他们就可以使用bindBidirectional方法进行双向绑定。

节点的通用属性和方法

要点提示: 抽象类Node定义来许多对于节点而言通用的属性和方法
节点具有通用属性;
JavaFx的样式属性称为JavaFx CSS

设定样式的语法是styleName:value
一个节点的多个属性可以一起设置,通过分号(;)进行分隔。例如:
circle.setStyle(“-fx-stroke: black; -fx-fill: red”);
它等效于:
circle.setStyle(Color.Black);
circle.setFill(Color.Red);
如果使用了一个不正确的JavaFx CSS,程序依然可以编译和运行,但是样式会被忽略

rotate属性可以设定一个以度为单位的角度,让节点围绕它的中心旋转该角度。如果设置的角度是正的,表示顺时针旋转,否则是逆时针旋转
例如:将一个按钮旋转80度
button.setRotate(80);

Color类

要点提示: Color类可以用于创建颜色

JavaFx定义类抽象类Paint用于绘制节点。Javafx.scene.paint.Color是Paint的具体子类,用于封装颜色信息。具体如下:
-w1051
可以通过一下构造方法创建颜色实例:
public Color(double r, double g, double b, double opacity);其中的每个double值的范围从0.0到1.0,由浅到深。opacity定义了一个颜色的透明度,也是从0.0到1.0,由完全透明到完全不透明。这称为RGB模型,A表示alpha值,是透明度的意思。

Color color = new Color(0.25, 0.14, 0.333, 0.51);
Color类是不可修改的。当一个Color对象创建后,它的属性就不能再修改。brighter()返回一个具有更大的红、绿、蓝值的新的Color对象,而darker()方法返回一个具有更小的对象,opacity值与原来的Color对象中的值相同。

采用静态方法color(r,g,b),color(r,g,b,opacity),rgb(r,g,b),rgb(r,g,b,opac ity)来创建一个颜色对象。

另外一种方法是: 可以采用Color类中定义的许多标准颜色之一,如BEIGE(米色),BLACK,BLUE,CYAN,DARKGRAY,GREEN,LIGHTGRAY,MAGENTA(品红),NAVY(海军蓝),ORANGE,PINK,SILVER,WHITE,YELLOW

Font类

要点提示: Font类描述字体名、粗细和大小
可以在渲染文字的时候设置字体信息。javafx.scene.text.Font类用于创建字体
-w1156

Font类实例可以用它的静态方法或者哦构造方法来创建,Font可以用它的名字、粗细、字体形态和大小来描述。Times,Courier和Arial是字体名字的示例。可以通过调用静态方法getFamilies()获得一个可用的字体系列名字列表。List是一个为列表定义通用方法的接口。ArrayList是List的一个具体实现。

字体形态是两个常量:FontPosture.ITALTC(意大利文)和FONTPosture.REGULAR.下面语句生成两个字体。
Font font1 = new Font(“SansSerif”,16);
Font font2 = Font.font(“Times New Roman “,FontWeight.BOlD, FontPosture.ITALIC, 12)
StackPane将节点置于中央,节点依次位于最上面

Image和ImageView类

要点提示: Image类表示一个图像,ImageView用于显示一个图像。

javafx.scene.image.Image类表示一个图像,用于从一个特定的文件名或者一个URL载入一个图像。

javafx.scene.image.ImageView是一个用于显示图像的节点。ImageView可以从一个Image对象产生。例如:以下代码从一个图像文件创建一个ImageView:
Image image = new Image(“image/us.gif”);
ImageView imageView = new ImageView(image);

当然,也可以周姐从一个文件或者一个URL来创建一个ImageView

-w1099
-w1176

HOX是一种面板,他将所有的节点排列在水平的一行上。
seRoate方法在Node类中定义,可以用于任何节点。
Image对象可以被多个节点共享。
ImageView这样的节点是不能共享的。不能讲一个ImageView多次放入一个面板或者场景中。
注意,务必将图像文件放在类文件的相同个目录中。

如果使用URL来定位图像文件,必须提供URL协议http://

pane.setPadding(new Insets(5, 5 ,5, 5)); // 用于设置节点到边缘的距离

布局面板

要点提示: javafx提供了许多种类型的面板,用于自动地将节点布局在希望的位置和大小。面板的种类有下面这些。

-w1118

Pane通常用作显示形状的画布。

Pane是所有特定面板的基类。

特定的面板StackPane。节点放置在StackPane面板的中央。

FlowPane

FlowPane 将节点按照加入的次序,从左到右或者从上到下垂直组织。当一行或者一列排满的时候,开始新的一行或者一列。可以使用下面两个常数中的一个来确定节点是水平还是垂直排列:
Orientation.HORIZONTAL 或者 Orientation.VERTICAL。(默认是水平的)可以使用像素为单位指定节点之间的距离。FlowPane的类图如图所示:
-w1066

其中数据域alignment、oritentation、hap和vgap是绑定属性。JavaFX中的每个绑定属性都有一个获取方法,例如getHgap()返回其值,一个设置方法,如sethGap(double)设置一个值,以及一个获取方法返回属性本身,(如hGapProperty())。对于一个ObjectProperty类型的数据值,值的获取方法返回一个T类型的值,属性获取方法返回一个ObjectProperty类型的属性值。

文本域这样的节点只能加到一个面板中一次。将一个节点加入到一个面板中多次或者不同面板中将引起运行时错误

一个节点只能放置在一个面板中。因此,面板和节点的关系是组合关系,使用一个填充的菱形表示。

GridPane

GridPane将节点布局在一个网络(矩阵)中。节点放在一个指定的列和行索引中。GridPane的类图如下:
-w1203

注意
场景的大小没有设置时,场景会根据其中节点的大小自动计算。

BorderPane

BorderPane可以将节点放置在五个区域: 顶部、底部、左边、右边以及中间,分别使用:
setTop(node), setBottom(node),setLeft(node),setRight(node),setCenter(node)
-w1077

注意
面板自己就是一个节点,所以面板可以加入到另一个面板中。
如果要将一个节点从顶部区域移除,调用setTop(null);
如果一个区域没有被占据,那么不会分配空间给这个区域

HBox和VBox

HBox将它的字节点布局在单个水平行中。VBox将它的节点布局在单个垂直列中。
和FlowPane想比,HBox和VBox只能将节点布局在一行或者一列中,而不是将它的额节点布局在多行或者多列中。
-w1162
-w1110

形状

JavaFx提供了多种形状类,用于绘制文本、直线、圆、矩形、椭圆、弧、多边形以及折线
Shape类是一个抽象基类,定义了所有形状的共有属性。这些属性有fill,stroke,strokeWidth。

fill指定一个填充形状内部区域的颜色
stroke指定用于绘制形状边缘的颜色。
strokeWidth指定形状边缘的宽度。

-w761

Text

Text类定义类一个节点,用于在一个起始点(x,y)处显示一个字符串。
Text对象通常置于一个面板中。

对于一个面板,左上角是(0,0),右下角是(pane.getWidth(),pane.getHeight())

一个字符串可以通过\n分隔从而显示在多行。
以下是Text的UML图:
-w1165

Line

一条线通过4个参数(startX, startY, endX, endY)连接两个点。Line类的UML图:
-w1116

Rectangle

一个矩形通过参数x, y, width, height, arcWidth以及arcHeight定义。
矩形的左上角处于(x,y),参数aw(arcWidth)表示圆角处弧的水平直径,ah(arcHeight)表示圆角处弧的垂直直径。Rectangle的UML图如下:
-w1199

Circle和Ellipse(椭圆)

-w1112
对于Ellipse,其中的radiusX值的是a,radiusY指的是b(椭圆数学定义中的a和b)

Arc

一段弧可以认为是椭圆的一部分,由参数centerX, centerY, radiusX, radiusY, startAngle, length以及一个弧的类型(ArcType.OPEN, ArcType.CHORD或者ArcType.ROUND)来确定。

其中startAngle是起始角度,length是跨度(即弧所覆盖的角度)。

角度使用度来作为单位,并且遵循通常的数学约定(即,0度是最东的方向,正的方向表示从最东方向开始顺时针方向的旋转角度)
-w1188
单词解释: chord - 弦
不同类型弧长如下 :
-w530

角度可以是负数。一个负的起始角度从最东的方向顺时针旋转一个角度。一个负的跨度角度从起始角度开始顺时针旋转一个角度
(一句话总结: 这里的正负就和数学中一样)

Polygon(多边形)和polyline(折线)

Polygon类定义一个连接一个点序列的多边形,polyline类类似于Polygon类,不同之处是Polyline类不会自动闭合。分别如下图所示:
-w1178

-w1169

示例学习: ClockPane 类

要点提示: 学习开发一个类,在面板中显示一个始终
ClockPane的合约图如下
-w1058

因为一分钟有60s,所以第二个指针的角度是:
second * (2*pi/60)
包含秒数的确切分钟数是(minute + second / 60)

因为一小时有60分,因此分针的角度是(minute + second / 60) * (2pi/60)

由于一个圆被分为12个小时,所以时针的角度是: (hour + minute / 60 + second / (60 + 60)) * (2pi/12)
-w1163

Java-黑马教程

I/O

硬盘: 永久存储
内存: 临时存储

I: input输入,读取
O: output输出,写入
流: 数据(字符,字节)
1字符=2字节=
1字节=8个二进制位(即8个byte)

输入:把硬盘中的数据读取到内存中使用
输出 :把内存中的数据写入到硬盘中保存
-w1448

字节流

一切文件数据(文本、图片、视频)都是以字节方式存储的。
所以,字节流可以传输任意文件数据,在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终是二进制数据

OutputStream 字节输出流

此抽象类是表示输出字节流的所有类的超类
定义了一些子类共性的成员方法。

FileOutputStream 文件字节输出流

作用: 把内存中的数据写入到硬盘的文件中

构造方法:

FileOutputStream(File file)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的输出文件流。

参数: 写入数据的目的地
string name:目的地是一个文件的路径
File file: 目的地是一个文件
构造方法的作用:

  1. 创建一个FileOutputStream对象
  2. 会根据构造方法中传递的文件/文件路径,创建一个空的文件
  3. 会把FileOutputStream对象只想创建好的文件
写入数据

原理:如果 内存 -> 硬盘
java程序 — JVM(java虚拟机)— OS(操作系统)— OS调用写数据的方法 — 把数据写入到文件

字节流的使用步骤(重点)

  1. 创建一个FIleOutputStream对象,构造方法中传入数据的目的地
  2. 调用FIleOutputStream对象中的方法write,把数据写入到文件中
  3. 释放资源(这样可以节约内存,因为流的使用会占用一定的内存)

文件存储的原理和记事本打开
写数据的时候会把十进制的整数转换为二进制的整数

记事本在打开文件的时候都会查询编码表,把字节转换为字符表示,故如果写入为:
0-127 - 查询ASCII表
其他值:会查询系统默认码表(中文系统GBK)
-w1433

一次写多个字节的方法

-w706
第一个:
用于一次写多个字节:

  • 如果写的第一个字节是正数(0-127),那么显示的时候会查询ASCII表
  • 如果写的第一个字节是负数,那么第一个字节会和第二个字节,连个字节组成一个中文显示,查询系统默认码表(GBK)

第二个用来写字节数组的一部分:
int off: 数组的开始索引
int len: 写几个字节

另外一种写入字符的方法:
使用String类中的方法把字符串,转换为字节数组

数据的续写和换行写

续写即追加写

构造方法:
FileOutputStream(String name, boolean append)
创建一个向具有指定 name 的文件中写入数据的输出文件流。
FileOutputStream(File file, boolean append)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。

参数:
String name,File file : 写入数据的目的地
boolean append: 续写开关

  • true: 继续在文件末尾续写数据
  • false: 创建一个新文件,覆盖

换行写,写完数据之后写上换行符号

InputStream 字节输入流

方法:
int read()
从此输入流中读取下一个数据字节。
int read(byte[] b)
从此输入流中将 byte.length 个字节的数据读入一个 byte 数组中。
void close()
关闭此输入流并释放与此流关联的所有系统资源。

FileinputStream 文件字节输入流

-w354

作用: 把硬盘文件中的数据,读取到内存中使用

构造方法:
-w1110

参数:
读取文件的数据源
String name:文件的路径
File file: 文件
构造方法的作用:

  1. 会创建一个FileInputStream对象

  2. 会把FileInputStream对象指向构造方法中要读取的文件

    读取数据的原理:
    原理:如果 硬盘 -> 内存
    java程序 — JVM(java虚拟机)— OS(操作系统)— OS调用读数据的方法 — 读入文件
    使用步骤:

    1. 创建一个FileInputStream对象,构造方法中绑定要读取的数据
    2. 使用FileInputStream对象中的方法read,读取文件
      int read()读取文件中的一个字节并返回,读取到文件的末尾返回-1
    3. 释放资源

注意
不知道文件中有多少字节,使用while循环
boolean表达式:while((len = fis.read())!= -1){
}
实际过程:
int len;
len = fis.read();
len = fis.read())!= -1

而不能写成:
while((fis.read())!= -1){
System.out.println(fis.read())
}

方法