免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1044 | 回复: 0
打印 上一主题 下一主题

用JavaFX写用户界面控制器 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-07-14 17:36 |只看该作者 |倒序浏览
 在本文中,我们关心的是BlueBill Mobile类,尤其是管理所有Search Species屏幕之后逻辑的控制器;因此本文有助于你了解JavaFX的语言性能。而且我们会举出一些实例来阐述要介绍的技巧和典型JavaFX结构的陷阱。
  笔者想应用程序中嵌入了更新的屏播。视频播放要求使用QucikTime。
  这里的概念是在搜索框中键入查询时,英文函数或科学名称函数会对清单过滤。此外,当这些生效的时候,BlueBill
Mobile还可以执行自动完成输入。例如,如果在键入查询的时候你仔细查看视频会发现只输入了"a-r-d-a-c"来选择"Ardea
Cinerea";或用于"Pied Avocet"的"p-i-e--a"。BlueBill Mobile 会自动会剩余部分进行补充因为在某些情况下,不存在其他选择。这是用来改善移动设备性能的重要功能:你可以以较少的输入达到相同目的。
  按照MVC模式,就非常有必要在单独的控制器中概括这种模式;此外,也很容易对这种模式进行单元测试。
  首先,让我们看一下代表了分类群的模式类:
  
     package it.tidalwave.bluebillmfx.taxon.model;
  import java.lang.Comparable;
  public class Taxon extends Comparable
  {
  public-read protected var displayName : string;
  public-read protected var scientificName : String;
  public-read protected var id : String;
  override function compareTo (other : object
[/url]
)
  {
  return displayName.compareTo((other as Taxon).displayName);
  }
  override function toString()
  {
  return "{displayName} ({scientificName}) ({id})"
  }
  }
  public function displayNameGetter (taxon : Taxon): String
  {
  return taxon.displayName;
  }
  public function scientificNameGetter (taxon : Taxon): String
  {
  return taxon.scientificName;
  }
  public def namePropertyGetters = [displayNameGetter, scientificNameGetter];
类托架外面定义的函数和变量相当于Java静态分析。
  这里我们省略了一些不相关的实际项目。基本上,该模式暴露了三个属性,其中有意思的两个分别是displayName和scientificName。我们也可以定义两个函数来处理这两个问题,我们会把这些函数放在namePropertyGetters序列中。
  
      package it.tidalwave.bluebillmfx.taxon.controller;
  import it.tidalwave.bluebillmfx.taxon.model.Taxon;
  public class TaxonSearchController
  {
  public var selectedTaxon = bind if (selectedTaxonIndex intiger = -1;
  public var taxons: Taxon[];
  public var filter
[url=http://whatis.ctocio.com.cn/searchwhatis/408/5947908.shtml]

= "" on replace
  {
  filteredTaxons = taxons[taxon | matches(taxon, filter)];
  update();
  }
  public-read var autoCompleted = "";
  public var filteredTaxons: Taxon[];
  protected function matches (taxon : Taxon, string: String) : Boolean
  {
  if (string == "")
  {
  return true;
  }
  for (propertyGetter in Taxon.namePropertyGetters)
  {
  if (propertyGetter(taxon).toLowerCase().startsWith(filter.toLowerCase()))
  {
  return true;
  }
  }
  return false;
  }
  protected function update(): Void
  {
  def autoCompletedTry = commonLeadingSubstring(filteredTaxons, findMatchingPropertyGetter());
  //
  // Sometimes it can't find a better auto-completion than the current filter, since it searches the displayName
  // and the scientificName at the same time. In this case, we just ignore the new value.
  //
  if (autoCompletedTry.length() > filter.length())
  {
  autoCompleted = autoCompletedTry;
  }
  selectedTaxonIndex = if (sizeof filteredTaxons == 1) then 0 else -1;
  println("selectedTaxonIndex: {selectedTaxonIndex}")
  }
  protected function findMatchingPropertyGetter(): function (:Taxon): String
  {
  for (taxon in filteredTaxons)
  {
  for (propertyGetter in Taxon.namePropertyGetters)
  {
  if (propertyGetter(taxon).toLowerCase().startsWith(filter.toLowerCase()))
  {
  return propertyGetter;
  }
  }
  }
  return null;
  }
  // some stuff later
  }
这个类揭示了以下的属性:
  ·taxons:你需要用完整的鸟类列表来填充
  ·filter: 字符串包括需要输入到搜索栏中的文本
  ·filteredTaxons: 种类由filter字符串过滤
  ·autoCompleted: 控制器猜测的自动完成输入字符串
  ·selectedTaxon: 如果filter向下细分种类,它就会分配到这个变量
  ·selectedTaxonIndex: -1如果无法获取时,selectedTaxon的索引。
  最新的四种属性由客户代码来绑定,这样做可以获取更改提示。
  Filter获取了一个触发事件,也就是变量值更改时所执行的代码。触发器用JavaFX运算符
︳执行了过滤操作:我们可以将触发事件的第一行当作分配到taxons序列中的filteredTaxons来读取,在这一序列中,matches()函
数返回值为true。第二行的代码调用了接下来要介绍的update()函数。
  出于某些原因,这种方法并不一定奏效,因为filteredTaxons通常会被整体扫描。有多种方法可用来加速选择过程,但是本文不会在这一方法真正应用到手机前前作出过早的优化。在笔记本上,它可以加快1000个项目的速度。
  Matches()函数在所有属性上执行了一次迭代以获取函数并检查看相关属性是否以过滤值启动。
  创建获得属性值函数的序列的一大好处是我们可以通过定义新的函数轻松添加新的匹配标准:例如,其他语言中的本地化名称。控制器可能会使用在搜索过程中使用这些名称,而我们则不需要再做多余修改。
  Update()函数运算出了自动完成输入提示。它会提取filteredTaxons序列以及用于当前选择的获取属性函数,还会调用刚刚在字
符串属性的序列中找到了通用子字符串的commonLeadingSubstring()。它不是每次都会作出很好的自动完成输入猜想,因此有时建议甚至
比当前过滤器还短,而这种情况我们大可忽略不计。请不要忽视指定临时变量的重要性:由于自动完成输入可能被绑定,因此我们不想为其指定一个会迅速失效的
值。
  要明白这一点的重要性,这不仅仅是避免无用更新,还能避免程序被破坏。在实际程序中,自动完成输入更改时,TextBox会更新,因此过滤器也
会随之更新:已经输入了"cal"后,再输入一个"i",那么TextBox暂时会显示"cali",然后自动输入完成的猜测失败,它会返回一
个"cal",TextBox中的字符串会变为"cal":这时候你要坚持自己的想法!绑定确实很强大,但是它也同时具有负面效应。
  最后一步操作中,代码会检查看我们是否获取单独的已选定鸟类。
  或许,你对于自动完成输入失败的原因仍然感到很困惑。毕竟,我们正在逐步缩小项目列表。因此,如果你已经输入了"cali",那么所有经过过滤
的种类会以"cali"开头,对吗?如果你过滤的是一套单一名称,情况就应该是这样;但是我们是同时对两套名称执行搜索,那么就会产生矛盾。看看下例
由"cali"过滤器选取的名称组(英语,科学的):("Calandra Lark", "Melanocorypha calandra"),
("Dunlin", "Calidris alpina"), ("California Quail", "Callipepla
californica")
  另一个有意思的地方是findMatchPropertyGetter()。它必须猜测当前过滤器是否是以"英语"或"科学"名称运行,而且它
还会返回相关的属性获取函数。基本上,控制器已经获取了matches()函数中的这一信息,但是我们会将其移走。可能会有人思考让matches()函
数返回一个以上的布林值,但是这是不可能的,因为它是由运算符
︳过滤序列的时候使用的:该运算符需要一个布林值。或许我们可以为稍后调用信息的操作指定一个成员变量,不过此时的代码应该会更具可读性。
  为了对文章进一步作补充说明,这里给大家列出了最后两个忽略的函数:
  
      protected function commonLeadingSubstring (taxons: Taxon[], propertyGetter: function (:Taxon): string): String
  {
  if (sizeof taxons == 0)
  {
  return "";
  }
  if (sizeof taxons == 1)
  {
  return propertyGetter(taxons[0]);
  }
  var common = propertyGetter(taxons[0]);
  for (other in taxons[1..])
  {
  common = commonLeadingSubstring(common, propertyGetter(other));
  if (common == "")
  {
  break; // don't waste time in further iterations, "" it's for sure the final result
  }
  }
  return root;
  }
  function commonLeadingSubstring (string1 : String, string2 : String): String
  {
  return if (string1.length() > string2.length())
  {
  commonLeadingSubstring(string2, string1);
  }
  else if (string1 == "")
  {
  "";
  }
  else if (string2.startsWith(string1))
  {
  string1;
  }
  else
  {
  commonLeadingSubstring(string1.substring(0, string1.length() - 1), string2);
  }
  }
这里的逻辑很简单。通常主要的字符串搜索被分解成了临近字符串对;而对于单一对的搜索则有递归执行。
  这里显示了视图类是如何绑定到控制器的:
  
      package it.tidalwave.bluebillmfx.taxon.view;
  public class TaxonSearchScreen
  {
  public var taxons : Taxon[];
  var filter = "";
  public-read def controller = TaxonSearchController
  {
  taxons: bind taxons
  filter: bind filter
  }
  def autoCompleted = bind controller.autoCompleted on replace
  {
  if (autoCompleted != "")
  {
  filter = autoCompleted;
  }
  }
  def list = ListBox
  {
  items: bind controller.filteredTaxons
  };
  def searchBox = TextBox
  {
  text: bind filter with inverse
  };
  }
  你必须用所有可得的种类加载taxon;ListBox会随着过滤的种类自动更新,TextBox与过滤器是双重指令型绑定。之所以需要双重绑定是因为向搜索栏中输入时,一个指令用于给控制器发出新的选择命令,另一个则是自动完成输入时的更新。
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/98439/showart_1996179.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP