这些任务是根据以下标准选择的。任务集应该尽可能小,但应尽可能多地反映GUI编程中的典型(或基本的或代表性的)挑战。每项任务都应该尽可能简单和自给自足,但又不能过于人为。最好是,任务应该基于现有的示例,因为这使任务更有理由是有用的,并且至少已经有一个参考实现。
下面给出了每个任务的描述,其中突出显示了它所反映的挑战,并给出了用Java/Swing生成的GUI应用程序的屏幕截图。
任务是构建一个包含标签或只读文本字段T和按钮B的框架。最初,T中的值是“0”,每次单击B都会将T中的值加1。
Counter是对语言、范例和工具包的基础知识的简单介绍,用于可以想象到的最简单的GUI应用程序之一。因此,COUNTER揭示了所需的搭建,以及最基本的功能如何协同工作来构建GUI应用程序。一个好的解决方案几乎不需要脚手架。
任务是构建一个包含两个文本字段TC和TF的框架,它们分别以摄氏度和华氏度表示温度。最初,TC和TF都是空的。当用户在TC中输入数值时,TF中的相应值会自动更新,反之亦然。当用户在TC中输入非数字字符串时,TF中的值不会更新,反之亦然。将摄氏温度C转换成华氏温度F的公式是C=(F-32)*(5/9),双向是F=C*(9/5)+32。
温度转换器在摄氏和华氏输入之间有双向数据流,并且需要检查用户输入的有效性,从而增加了计数器的复杂性。一个好的解决方案将用最少的样板代码使双向依赖非常清晰。
温度转换器的灵感来自“用Scala编程”一书中的摄氏度/华氏度转换器。这是一个如此广泛的例子-有时也以货币转换器的形式-以至于人们可以给出一千个参考。计数器任务也是如此。
该任务是构建一个框架,其中包含具有两个选项“单向飞行”和“返回航班”的组合框C、分别表示开始日期和返回日期的两个文本字段T1和T2,以及用于提交所选航班的按钮B。如果C的值是“返回飞行”,则启用T2。当C具有值“返回航班”并且T2的日期严格在T1之前时,则B被禁用。当未禁用的文本字段T具有格式错误的日期时,T将显示为红色,而B将被禁用。当点击B时,会显示一条消息通知用户他的选择(例如。您已经预订了2014年4月4日的单程机票。最初,C的值为“单向飞行”,T1和T2的日期相同(任意)(暗示T2被禁用)。
Flight Booker的重点在于一方面对小部件之间的约束进行建模,另一方面对小部件内的约束进行建模。这种约束在与GUI应用程序的日常交互中非常常见。一个好的Flight Booker解决方案将使源代码中的约束清晰、简洁和显式,而不是隐藏在大量的脚手架后面。
Flight Booker的灵感直接来自于Sodium中的Flight Bookking Java示例,它简化了使用文本字段进行日期输入,而不是专门的日期挑选小部件,因为Flight Booker的重点不是专门的/自定义的小部件。
任务是构建一个框架,该框架包含用于经过的时间e的量规G、将经过的时间显示为数值的标签、在定时器运行时可以通过其调整定时器的持续时间d的滑块S、以及复位按钮R。调整S必须立即反映在d上,而不仅仅是当S被释放时。由此推论,当移动S时,G的填充量(通常)会立即改变。当e_≥_d为真时,定时器停止(并且G将满)。此后,如果d增加,使得d>;e将为真,则计时器重新开始滴答,直到e_≥_d再次为真。单击R会将e重置为零。
计时器处理并发性,因为更新运行时间的计时器进程与用户与GUI应用程序的交互同时运行。这也意味着对竞争的用户和信号交互的解决方案进行了测试。此外,必须立即反映滑块调整这一事实测试了解决方案的响应性。一个好的解决方案将清楚地表明,该信号是计时器滴答声,并且一如既往地没有太多的脚手架。
Timer的灵感直接来自论文“跨越状态线:使面向对象的框架适应函数式反应语言”中的Timer示例。
任务是构建一个包含以下元素的框架:一个文本字段T前缀、一对文本字段T姓名和T姓氏、一个列表框L、按钮B C、B U和B D,以及屏幕截图中所示的三个标签。L显示数据库中数据的视图,该视图由名称列表组成。在L中一次最多只能选择一个条目。通过在T前缀中输入一个字符串,用户可以过滤姓氏以输入的前缀开头的姓名-这应该立即发生,而不必使用Enter提交前缀。单击B、C将把T name和T surname中的字符串连接到L后追加结果名称。如果选择了L中的条目,则启用B U和B D。与B-C相反,B-U不会附加结果名称,而是用新名称替换所选条目。B D将删除所选条目。布局将按照截图中的建议进行。特别地,L必须占据所有剩余空间。
CRUD(Create,Read,Update and Delete,创建、读取、更新和删除)代表了一个典型的图形业务应用程序。主要的挑战是源代码中的域逻辑和表示逻辑的分离,由于能够按前缀过滤视图,这或多或少地强制实现者做到了这一点。传统上,使用某种形式的MVC模式来实现域和表示逻辑的分离。此外,还测试了管理姓名列表突变的方法。一个好的解决方案将在域和表示逻辑之间有很好的分离,没有太多开销(例如,以特定于工具包的概念或语言/范例概念的形式)、快速但不容易出错的突变管理和布局的自然表示(当然,允许布局构建器,但会增加开销)。
CRUD的灵感直接来自博客文章FRP中的CRUD示例-双向数据流的GUI元素的三个原则。
任务是构建一个包含撤消和重做按钮的框架,以及下面的画布区域。在画布内的空白区域内单击鼠标左键将创建一个直径固定的未填充圆圈,其中心为左击点。距离鼠标指针最近的圆(如果存在)从其中心到指针的距离小于其半径,则用灰色填充。灰色圆圈是选定的圆圈C。右击C将出现一个弹出菜单,其中包含一个条目“调整直径..”。单击此条目将打开另一个带有滑块的帧,其中的滑块可调整C的直径。更改将立即应用。关闭此帧将把最后一个直径标记为对撤消/重做历史有重要意义。单击撤消将撤消上一次重要更改(即创建圆或调整直径)。单击重做将重新应用上次撤消的更改,除非用户在此期间进行了新的更改。
Circle Drawer的目标之一是测试如何很好地解决为GUI应用程序实现撤消/重做功能这一常见挑战。在理想的解决方案中,撤消/重做功能是免费提供的。只是作为语言/工具箱/范例的自然结果出现。此外,Circle Draker测试了如何在源代码中实现对话框控制*,即在几个连续的GUI交互步骤之间保持相关上下文。最后但并非最不重要的一点是,测试了自定义绘图的易用性。
任务是创建一个简单但可用的电子表格应用程序。电子表格应该是可滚动的。行的编号应该从0到99,列的编号应该从A到Z。双击单元格C可以让用户更改C的公式。完成编辑后,将解析并计算公式,其更新值以C显示。此外,所有依赖于C的单元格都必须重新计算。重复此过程,直到任何单元格的值不再发生更改(更改传播)。请注意,不应该只重新计算每个单元格的值,而应该只重新计算那些依赖于另一个单元格的更改值的单元格的值。如果已经提供了电子表格小部件,则不应使用它。相反,应该定制另一个类似的小部件(如Swing中的JTable),使其成为可重用的电子表格小部件。
Cells是一个更真实、更复杂的任务,它测试特定的方法是否也可以扩展到更大的应用程序。与GUI相关的两个主要挑战是更改的智能传播和小部件定制。诚然,有很大一部分不一定与GUI相关,但这正是更真实挑战的本质。一个好的解决方案的更改传播不会涉及太多的工作,并且小部件的定制应该不会太困难。特定于域的代码与特定于GUI的代码明显分开。生成的电子表格小部件是可重用的。
Cells的灵感直接来自“用Scala编程”一书中的SCells电子表格示例。请参考本书(或此存储库中的实现)了解更多详细信息,特别是关于与GUI无关的问题,如解析和计算公式以及电子表格语言的精确语法和语义。