JavaFX2:简化属性定义

在说明FXBindable注解之前,先来看一篇介绍如何使用JavaFX的属性与绑定功能的文章。里面的第一个例子代码如下:

package org.frkd.fx;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Person {

	private StringProperty firstName;

	public void setFirstName(String val) {
		firstNameProperty().set(val);
	}

	public String getFirstName() {
		return firstNameProperty().get();
	}

	public StringProperty firstNameProperty() {
		if (firstName == null)
			firstName = new SimpleStringProperty(this, "firstName");
		return firstName;
	}

	private StringProperty lastName;

	public void setLastName(String value) {
		lastNameProperty().set(value);
	}

	public String getLastName() {
		return lastNameProperty().get();
	}

	public StringProperty lastNameProperty() {
		if (lastName == null) {// etc.
		} 
		return null;
	}
}

是不是觉得有些繁琐?有什么办法能简化定义属性呢?答案是有的。无意中试用了下JavaFX2的框架GroovyFX,初步了解了下API的结构,看到其中有个FXBindable注解,具体实现使用了AST;用FXBindable注解后,代码可以简化为如下:

public class Person {
  @FXBindable String firstName; 
  @FXBindable String lastName;
}

不过不支持某些对象类型,例如对java.util.Date对象类型进行注解;bug已提交,但作者时隔9个月后才有回复……只好自己动手修复了;修复后写了个单元测试如下:

/*
 * Copyright 2013-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.frkd.fx;

import static org.junit.Assert.*
import javafx.beans.property.SimpleIntegerProperty
import javafx.beans.property.SimpleObjectProperty
import javafx.beans.property.SimpleStringProperty
import javafx.beans.property.StringProperty

/**
 * 
 * @author Franklyn Tang <lovefree103@gmail.com>
 *
 */
class FXBindableTests extends GroovyTestCase{  

	void testFXBindable(){
		def now = new Date()      
		def p = new Person()  
		assert p.getBirth() == null     

		def sp = new SimpleStringProperty('john')
		def ip = new SimpleIntegerProperty(26)
		def op = new SimpleObjectProperty(now)   	

		// Person p的所有属性(例如name)是懒加载的,必须通过p.nameProperty()来初始化
		assert p.@name == null
		assert p.name() != null  
		p.nameProperty().bindBidirectional(sp)
		p.ageProperty().bindBidirectional(ip)   
		p.birthProperty().bindBidirectional(op)	

		assert p.nameProperty()==p.getNameProperty()
		assert p.nameProperty()==p.@name
		assert p.@name==p.name()

		assert p.name == 'john'
		assert p.name == p.getName()			
		assert p.@name instanceof StringProperty
		assert p.@name instanceof SimpleStringProperty
		assert p.name instanceof String

		assert p.age == 26
		assert p.@age instanceof SimpleIntegerProperty
		assert p.age == p.getAge()

		assert p.birth == now
		assert p.getBirth() == now
		assert p.birth().value == now
		assert p.birth().get() == now
		assert p.birthProperty().value == now

		assert p.@birth instanceof SimpleObjectProperty
		p.age = 27

		assert ip.value == 27
		assert ip.get() == 27

		p.name = 'steven'
		assert sp.value == 'steven'

		p.setSet([5,6,7] as Set)
		println p.getSet()

	} 

	@FXBindable
	class Person{

		String name
		int age = 5

		boolean old

		Date birth

		Map map
		List list
		Set set
	}

}

对于Oracle官网中给的javafx-samples,里面的Ensemble.jar中有个关于Table的使用例子,代码可以修改为如下:

package org.frkd.fx
/**
 * Copyright (c) 2008, 2012 Oracle and/or its affiliates.
 * All rights reserved. Use is subject to license terms.
 */
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.beans.property.StringProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.util.Callback;

/**
 * A simple table with a header row.
 *
 * @see javafx.scene.control.TableCell
 * @see javafx.scene.control.TableColumn
 * @see javafx.scene.control.TablePosition
 * @see javafx.scene.control.TableRow
 * @see javafx.scene.control.TableView
 */
public class TableSample extends Application {
    private void init(Stage primaryStage) {
        Group root = new Group();
        primaryStage.setScene(new Scene(root));
        final ObservableList<Person> data = FXCollections.observableArrayList(
            new Person("Jacob",     "Smith",    "jacob.smith@example.com" ),
            new Person("Isabella",  "Johnson",  "isabella.johnson@example.com" ),
            new Person("Ethan",     "Williams", "ethan.williams@example.com" ),
            new Person("Emma",      "Jones",    "emma.jones@example.com" ),
            new Person("Michael",   "Brown",    "michael.brown@example.com" )
        );
        TableColumn firstNameCol = new TableColumn();
        firstNameCol.setText("First");
        firstNameCol.setCellValueFactory(new PropertyValueFactory("firstName"));
        TableColumn lastNameCol = new TableColumn();
        lastNameCol.setText("Last");
        lastNameCol.setCellValueFactory(new PropertyValueFactory("lastName"));
        TableColumn emailCol = new TableColumn();
        emailCol.setText("Email");
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(new PropertyValueFactory("email"));
        TableView tableView = new TableView();
        tableView.setItems(data);
        tableView.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
        root.getChildren().add(tableView);
    }

	@FXBindable
    public static class Person {
//        private StringProperty firstName;
//        private StringProperty lastName;
//        private StringProperty email;
		String firstName
		String lastName
		String email

        private Person(String fName, String lName, String email) {
//            this.firstName = new SimpleStringProperty(fName);
//            this.lastName = new SimpleStringProperty(lName);
//            this.email = new SimpleStringProperty(email);
			this.firstName().value = fName
			this.lastName().value = lName
			this.email().value = email
        }

//        public StringProperty firstNameProperty() { return firstName; }
//        public StringProperty lastNameProperty() { return lastName; }
//        public StringProperty emailProperty() { return email; }
    }

    @Override public void start(Stage primaryStage) throws Exception {
        init(primaryStage);
        primaryStage.show();
    }
    public static void main(String[] args) { launch(TableSample,args); }
}

源码下载

发表在 groovy, javafx | 标签为 , , | 留下评论

Groovy循环性能

最近有个朋友要我帮写个求解方程的程序,条件为:

1)1800*x+1320*y+820*z==3086160

2)x+y+z==2640

问题简单啊,便很快用Groovy实现了下,代码如下:

package test

import groovy.transform.CompileStatic

@CompileStatic
class Test {

	static main(args){

		def t1 = System.currentTimeMillis()

		(0..99).each{int x->
			(0..2246).each {int y->
				(0..3062).each {int z->  
					if((1800*x+1320*y+820*z==3086160) && (x+y+z==2640) ){
						println("x:"+x+" y:"+y+" z:"+z);
					}
				}
			}
		}
		def t2 = System.currentTimeMillis()
		println((t2-t1)/1000)

	}

}

输出结果为:

x:7 y:1829 z:804
x:32 y:1780 z:828
x:57 y:1731 z:852
x:82 y:1682 z:876
34.911

半分钟的时间才算完…改为for..in看看:

package test

import groovy.transform.CompileStatic

@CompileStatic
class Test {

	static main(args){

		def t1 = System.currentTimeMillis()

		for(x in 0..99){
			for(y in 0..2246){
				for(z in 0..3062){
					if((1800*x+1320*y+820*z==3086160) && (x+y+z==2640) ){
						println("x:"+x+" y:"+y+" z:"+z);
					}
				}
			}
		}
		def t2 = System.currentTimeMillis()
		println((t2-t1)/1000)

	}

}

输出结果为:

x:7 y:1829 z:804
x:32 y:1780 z:828
x:57 y:1731 z:852
x:82 y:1682 z:876
10.171

嗯,好一点点了…改为java写法看看?

package test

import groovy.transform.CompileStatic

@CompileStatic
class Test {

	static main(args){

		def t1 = System.currentTimeMillis()

		for (int x = 0; x <= 99; x++) {
			for (int y = 0; y <= 2246; y++) {
				for (int z = 0; z <= 3062; z++) {
					if((1800*x+1320*y+820*z==3086160) && (x+y+z==2640) ){
						println("x:"+x+" y:"+y+" z:"+z);
					}
				}
			}
		}
		def t2 = System.currentTimeMillis()
		println((t2-t1)/1000)
	}
}

输出结果为:

x:7 y:1829 z:804
x:32 y:1780 z:828
x:57 y:1731 z:852
x:82 y:1682 z:876
1.617

性能大增,再把CompileStatic注解去掉试了下,输出结果:

x:7 y:1829 z:804
x:32 y:1780 z:828
x:57 y:1731 z:852
x:82 y:1682 z:876
0.854

以上运行环境为 groovy-2.1.4、jdk1.7、eclipse indigo3.7

结论:

1)遇到计算量大又要求高性能的问题,如果只能在Java与Groovy之间进行选择,应该回归到使用Java来实现;

2)使用CompileStatic注解并非总能带来性能上的提升

发表在 groovy | 标签为 , , | 留下评论

自定义Galaxy Note 3随笔窗口关联的应用程序

Galaxy Note 3的随笔窗口功能很好使,但默认提供的程序太少,有没有APK来实现自定义添加功能呢?今天google到一个好东西,不敢独享,特分享之!该android程序应用名为PEN Window Manager;程序作者发布的说明帖子链接为http://forum.xda-developers.com/showthread.php?p=46171000,里面包含了下载地址及使用教程,具体如何安装及使用这里就不再重复说明了=。=

使用该程序需要root,电信版N9009的root教程参见http://samsung.zol.com.cn/278/98_2772487.html,其它机型的机友就自己查找相关root教程吧…

作者已经出了2个版本,我下载的是最新版,也建议大家下载最新版,因为作者的第1个版本有些缺陷,最新版下载地址为:http://forum.xda-developers.com/attachment.php?attachmentid=2342413&d=1382437385

来张使用效果的截图~HOHO……

SPen随笔窗口使用截图

SPen随笔窗口使用截图

发表在 Galaxy Note 3 | 标签为 , , , | 留下评论

Win7操作系统平台下搭建Grails2.x开发环境

  • 搭建Grails命令行开发环境
  1. 下载JDK1.7+,配置JAVA环境变量,此步详细步骤略过,网上太多相关资料
  2. 下载Grails2.2.4开发环境包快速参考手册及API文档;英文好的自己直接上Grails官网下载
  3. 将grails-2.2.4.zip解压;(注意解压的路径不应该包括有空格,最好全英文不要包含中文),这里假设解压至G:\grails-2.2.4
  4. 新建系统环境变量GRAILS_HOME,GRAILS_HOME的值设为G:\grails-2.2.4
  5. 将%GRAILS_HOME%\bin添加到path变量值行尾,注意用分号隔开;至此,基于Grails的命令行开发环境已经配置完毕。
  6. 验证Grails命令行环境:打开cmd,输入grails -version回车后如果看到如下截图,那么Congratulations!
    验证grails版本命令截图

PS:虽然可以在命令行下可以创建grails项目,但个人一般只在命令行下执行一些集成测试的命令,因为在eclipse的控制台下输入grails命令,tab键的自动补全及回显执行过的历史命令功能都将失效!虽然GGTS有一套类似命令行操作的UI(Grails Tools->Open Grails Command Prompt),但这个东东存在一些BUG,不好使;例如执行测试命令test-app,如果对项目的源码如某个Controller做了修改,修改的内容不会被加载到内存中;CMD下执行test-app不会有这个问题

 

  • 使用eclipse开发Grails项目
  1. eclipse版本:eclipse有很多版本,对于juno4.2、indigo3.7这2个版本我都用过,最开始用的是juno版,给JVM开了最小2G最大4G的内存,在编辑切换GSP文件时依然卡的很;后改用indigo,用的很爽。推荐大家使用indigo3.7
  2. 下载GGTS(Groovy/Grails Tool Suite)插件;安装插件Help->Install New Software…->Add,选择下载好的ggts zip包,安装完后需要重启eclipse
    ggts_plugin
  3. 设置关联Grails开发环境:Window->Preferences->Groovy->Grails->Add…
    添加Grails开发环境包位置
  4. 设置eclipse使用的jre为第1步安装的jdk,eclipse默认使用的jre是eclipse自带的jre;操作路径为Window->Preferences->Java->Installed JREs->Edit…;

 

  • 新建并运行Grails项目
grails_create_project
grails_create_project2
grails_run
grails_run2
发表在 grails | 标签为 , | 留下评论

Grails2.3中文文档

2013/9/22 文档首页翻译完成。

Grails2.3中文文档链接地址:http://frkd.org/grails-doc/index.html

 

发表在 grails | 标签为 , , , , , , | 一条评论