| 本课对 JavaFX Script 编程语言进行了实例介绍。您将通过编写一个从命令行运行的简单的计算器来学习有关变量和函数的基础知识。每一节都将介绍一个新的核心概念,对其进行讨论,并提供您可以编译和运行的示例代码。讨论还包含“实际”代码摘录,说明实际的 SDK 演示中是如何使用特定结构的。单击每个演示的链接可以访问 javafx.com Web 站点,该站点提供了完整的代码列表以及开发者的附加注释。 |
目录
前一课介绍了如何建立开发环境;这里我们将更深入地研究 calculator.fx 源代码。下面的红色代码声明了程序的脚本变量。脚本变量是使用 var 或 def 关键字声明的。二者之间的区别在于:在脚本的整个生命周期内都可以为 var 变量赋予新值,而 def 变量在被首次赋予新值后将保持不变。这里我们已经为 numOne 和 numTwo 赋予了特定的值,但未对 result 进行初始化,因为此变量将用来存放将来的计算结果:
def numOne = 100; def numTwo = 2; var result;
add(); subtract(); multiply(); divide();
function add() { result = numOne + numTwo; println("{numOne} + {numTwo} = {result}"); }
function subtract() { result = numOne - numTwo; println("{numOne} - {numTwo} = {result}"); }
function multiply() { result = numOne * numTwo; println("{numOne} * {numTwo} = {result}"); }
function divide() { result = numOne / numTwo; println("{numOne} / {numTwo} = {result}"); }
|
您可能注意到,我们不需要将这些变量明确指定为存放数值型数据(而不是字符串或任何其他类型的数据)。编译器非常智能,可以根据使用变量的上下文来弄清您的意图。这称为类型推断。类型推断可以使脚本程序员的工作有所简化,这是由于它省去了声明变量与之兼容的数据类型的工作。
实际示例:效果场
上面的屏幕抓图显示了“效果场”演示应用程序。右边的代码摘录显示了该应用程序的几个脚本变量。您还不能理解整个列表,但应该可以根据刚学过的内容看懂突出显示的部分。请记住,尽管本教程的重点仅针对非图形核心结构,但您最终要把这些知识用于自己的基于 GUI 的应用程序。
有关变量的较低层面的讨论,请参见《JavaFX Language Reference》中的 "Chapter 3: Variables"。
在计算器示例中还定义了一些脚本函数,用于对两个数字进行加、减、乘、除。函数是用来执行特定任务的可执行代码块。下面的红色代码定义了四个函数;每个函数执行一种简单的数学计算,然后输出结果。将代码组织成函数是一种常见的做法,这会使程序更易于阅读、使用和调试。函数体通常会缩进以增强可读性。
def numOne = 100; def numTwo = 2; var result;
add(); subtract(); multiply(); divide();
function add() { result = numOne + numTwo; println("{numOne} + {numTwo} = {result}"); }
function subtract() { result = numOne - numTwo; println("{numOne} - {numTwo} = {result}"); }
function multiply() { result = numOne * numTwo; println("{numOne} * {numTwo} = {result}"); }
function divide() { result = numOne / numTwo; println("{numOne} / {numTwo} = {result}"); }
|
此外,除非函数代码被明确调用,否则不会执行。这样就可以在脚本的任何位置运行函数。将函数调用放在函数定义之前还是之后无关紧要(在我们的示例源文件中,函数是在实际定义之前调用的):
def numOne = 100; def numTwo = 2; var result;
add(); subtract(); multiply(); divide();
function add() { result = numOne + numTwo; println("{numOne} + {numTwo} = {result}"); }
function subtract() { result = numOne - numTwo; println("{numOne} - {numTwo} = {result}"); }
function multiply() { result = numOne * numTwo; println("{numOne} * {numTwo} = {result}"); }
function divide() { result = numOne / numTwo; println("{numOne} / {numTwo} = {result}"); }
|
实际示例:可拖动的 MP3 播放器
在“可拖动的 MP3 播放器”演示中,程序员定义了用于停止或播放当前歌曲的函数。尽管我们正在研究的这些代码完全脱离了上下文,但这些函数的命名选择(stopCurrentSong 和 playCurrentSong)使这些代码是自说明的,因此更易于分析。在对变量和函数进行命名时,请尽量使用这种有意义的字词。约定名称中的第一词全部使用小写字母,后续的每个词的首字母都使用大写字母。
还可以将脚本函数定义为接受参数。参数是指在调用函数时所传入的特定值。这种方法可使计算器应用程序执行对任何两个数字(而不仅是硬编码到 numOne 和 numTwo 变量中的值)的计算。实际上,在该版本中已完全删除了 numOne 和 numTwo,仅保留了 result 脚本变量。
var result;
add(100,10); subtract(50,5); multiply(25,4); divide(500,2);
function add(argOne: Integer, argTwo: Integer) { result = argOne + argTwo; println("{argOne} + {argTwo} = {result}"); }
function subtract(argOne: Integer, argTwo: Integer) { result = argOne - argTwo; println("{argOne} - {argTwo} = {result}"); }
function multiply(argOne: Integer, argTwo: Integer) { result = argOne * argTwo; println("{argOne} * {argTwo} = {result}"); }
function divide(argOne: Integer, argTwo: Integer) { result = argOne / argTwo; println("{argOne} / {argTwo} = {result}"); }
|
此脚本的输出现在为:
100 + 10 = 110 50 - 5 = 45 25 * 4 = 100 500 / 2 = 250
|
实际示例:有趣的照片
在这段来自“有趣的照片”演示的代码摘录中,我们看到一个名为 loadImage 的脚本函数,它可以接受一组参数。同样,函数和参数名称的选择使代码更容易理解。理解该函数的完整实现此时并不重要。重要的是识别可以接受两个参数的函数。当您开始编写自己的应用程序时,您很可能会依赖此类样例代码,从中学习正确的语法。
函数也可能会向调用它的代码返回一个值。例如,可以更改计算器的 add 函数,使其返回每次计算的结果:
function add(argOne: Integer, argTwo: Integer) : Integer { result = argOne + argTwo; println("{argOne} + {argTwo} = {result}"); return result;
}
|
第一段红色代码指定函数返回一个 Integer;第二段红色代码是实际返回值的代码。
现在,可以按如下方式调用 add 函数:
var total;
total = add(1,300) + add(23,52);
|
如果未指定返回值,函数会默认返回 Void。
实际示例:来自 Flickr 的动画照片
在“来自 Flickr 的动画照片”演示的这段代码摘录中,我们可以看到三个不同的函数使用了返回值。这些返回值比您以前见过的要稍微复杂一点,但核心概念是一样的:每个函数执行某种特定的计算,然后返回一个结果。前两个函数随后调用了一个 Math 函数(用于计算平方根)并返回其结果。第三个函数返回了一个新的 Vector2D 对象。单从此列表来看,没有足够的信息来确切地了解其含义,但借助完整的源代码您就可以看懂它们的含义了(如果您已经首先花时间学习了该语言!)
有关函数的较低层面的讨论,请参见《JavaFX Language Reference》中的 "Chapter 4: Functions"。
最后,脚本也可以接受命令行参数。在计算器示例中,这将使最终用户可以在运行时指定要进行计算的数字。
var result;
function run(args : String[]) {
// Convert Strings to Integers def numOne = java.lang.Integer.parseInt(args[0]); def numTwo = java.lang.Integer.parseInt(args[1]);
// Invoke Functions add(numOne,numTwo); subtract(numOne,numTwo); multiply(numOne,numTwo); divide(numOne,numTwo); }
function add(argOne: Integer, argTwo: Integer) { result = argOne + argTwo; println("{argOne} + {argTwo} = {result}"); }
function subtract(argOne: Integer, argTwo: Integer) { result = argOne - argTwo; println("{argOne} - {argTwo} = {result}"); }
function multiply(argOne: Integer, argTwo: Integer) { result = argOne * argTwo; println("{argOne} * {argTwo} = {result}"); }
function divide(argOne: Integer, argTwo: Integer) { result = argOne / argTwo; println("{argOne} / {argTwo} = {result}"); }
|
此更改引入了 run 函数,脚本通过此函数接收命令行参数。与您以前看到的其他函数不同,run 是用作脚本主入口点的特殊函数。run 函数会将所有命令行参数存储在 args(一个 String 对象序列)中。(序列是对象的有序列表,与其他编程语言中的数组相似;第 5 课:序列中详细介绍了序列。)
为了运行此脚本,用户现在必须在运行时指定第一个数字和第二个数字:
输出现在为:
100 + 50 = 150 100 - 50 = 50 100 * 50 = 5000 100 / 50 = 2
|
请注意,在所有以前版本的计算器脚本中,我们没有明确提供 run 函数,我们只是在脚本级别键入了代码,然后代码按照预期方式运行。在这些情况下,编译器会在无提示的情况下生成一个不带参数的 run 函数,并将要执行的代码放在该函数中。当指定您自己的 run 函数时,名称 args 可以是您希望的任何字符串;这里使用了 "args",但您很可能会看到程序员使用该名称的其他变体,如 "arg"、"ARGS"、"__ARGS__"、"argv" 等。
同时请注意,在该版本中我们重新使用了变量 numOne 和 numTwo,现在是在 run 函数中(而不是在脚本级别)定义它们。(当变量在函数中定义时,该变量在技术上称作局部变量,因为只有该函数中的其他代码可以看到该变量。)我们的计算器函数需要接受数字,但命令行参数是字符串;因此,我们必须首先将每个命令行参数从 String 转换为 Integer,然后才能将它们传递给函数:
// Convert Strings to Integers def numOne = java.lang.Integer.parseInt(args[0]); def numTwo = java.lang.Integer.parseInt(args[1]);
|
为此,我们借助于 Java 编程语言来执行实际的类型转换。根据需要利用现有的 Java 生态系统会给这个原本简单的脚本语言带来强大的功能。
实际示例:撞砖
这段摘录来自“撞砖”演示,显示了用作游戏主入口点的 run 函数。尽管这个特殊示例实际上并未使用其命令行参数,但我们可以看到,run 函数对应用程序的主框架进行了初始化(设置其标题、宽度、高度等)。
|