摘要: 我犹豫了好一阵才决定写JavaFX的语法部分。个人认为这是学习中最枯燥的部分。因为JavaFX的语法非常简单且直观,比如Sun提供的在线 Tutorial的GUI部分,即使你是第一次听说JavaFX这个东西,只要你稍有一点点编程经验,你也基本上能够毫无障碍地理解这个Tutorial 的内容了。
话虽如此,部分语法可能确实会造成一些理解困难,比如有的地方分隔符用逗号(,)分号(;)和空格都可以,def和var的区别,=>操作符,等等这些还得初看一遍语法才能理解(当然,基本上就没有必要看第二遍了吧)。因此,我也在此将JavaFX的语法照着Sun的语法 Tutorial快速地过一遍,为以后打下一个坚实(!)的基础,呵呵。
阅读全文
/**
以前写了一个JavaFX入门例子,但由于JavaFX正式版中变化较大,那个例子已无法在正式版中运行,因此重写,标题叫1u1,也是遵守Sun的更新规范,代表update1,呵呵
文:西门町学士
*/
08
年12月4日,Sun正式发布了JavaFX1.0。JavaFX在演进过程中发生了很多的变化,因此,我以前写的JavaFX的第一个
HelloWorld的例子已经无法在正式版下运行,于是在这里重写那个例子。而新的API我也还没有开始学习,只好大略地浏览了一遍API就草草写就,
因此,这个例子虽然在1.0版下正确运行,却未必就是最适合的写法,以后如发现问题再来update2吧,呵呵……
正式版中很多包的命名有了天翻
地覆的变化,class的位置和名称很多也面目全非。比如GUI这块就经历了由javafx.ui变化成javafx.gui再变化成
javafx.scene和javafx.application再进化成javafx.scene和javafx.stage,而跟Swing相关的组
件也统统加上了Swing前缀。有的class我已经找不到了,比如以前的javafx.ui.MessageDialog,我在1.0中没有找到对应的
class,只好直接叫用javax.swing.JOptionPane了。好了,废话不说了,贴新代码如下:
package sc.tmp;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.ext.swing.SwingButton;
import javax.swing.JOptionPane;
/**
* @author stevech
*/
Stage {
title: "Application title"
width: 250
height: 80
scene: Scene {
fill: Color.ORANGE
content: SwingButton {
text: "Click"
action: function():Void {
JOptionPane.showMessageDialog(null, "Have Fun!\nThis is your first JavaFX app!")
}
translateX: 90 translateY: 10
}
}
visible: true
}
结果如图:
摘要: JavaFX出来已经很长一段时间了。一直在计划跟进,可是因为比较懒,现在才慢慢地学习。这里就暂做做学习总结的地方吧。
虽然是总结,我还是打算写详细一点。本来我对JavaFX了解也不是很多,有的东西还要在网上查证了才能写(比较JavaFX是如何诞生,如何从F3变成 JavaFX的)。今天要写的主要是:1、JavaFX的前世今生;(了解了它的历史也就了解了它是什么,它的发展方向,呵呵)2、如何拥有 JavaFX;(知道从哪里去下载开发工具,如何配置它)3、Hello JavaFX World(当然,一个经典的Hello World是不能少的)
阅读全文
首先声明,本文作者信手乱写,以前候捷写
无责任书评,无责任这三个字,在我这儿也差不多——西门町学士 (注)
前两天逛书店,看到一本《
精通NetBeans——Java桌面、Web、企业级程序开发》 ,遂在书店里站了一个多小时(好厚啊!书厚脸皮也厚),基本把这本书看了一遍,整体感觉失望,内容完全配不上
精通NetBeans这个标题。基本上就是在NetBeans环境里写一些很简单的JavaSE和JavaEE代码,而且代码质量也很不高。像Web部分,为了图简单,在JSP页面中写了大量的scriptlet,很不推荐开发人员看这种代码。这本书勉勉强强可以起名叫《
初涉NetBeans》,看来要想更好地推介NetBeans,还需要更多的技术作者的努力。什么时候NetBeans的书能跟Delphi的书媲美了,估计NetBeans的大业差不多就定了吧,呵呵
不管用什么IDE,关键是看开发人员本人对语言和框架的功力,这里也推介两本书,都是老书了,但内容基本不落伍,提升功力更是不错。
一本是:Swing,Matthew Robinson 和 Pavel Vorobiev合写的,学士手上的很老了,上个世纪末的英文原版,但是真的非常非常经典,国内应该有更新的中文版的,做Swing的一定要看,很不错。
一
本关于JSP和Servlet方面的,学士是从TSS下载的免费电子版,Servlets and JavaServer Pages, The
J2EE technology Web Tier,Jayson Falkner 与 Kevin
Jones合著,(基于J2EE4,无JSF方面内容),国内好像没有中文版的。这也是一本好书,Java Web入门与提升均应多读此书。
这两本书最大的特点就是,呵呵,用侯捷的话说,叫
深入浅出。在讲一个技术的同时,也讲正确的编码和设计方法,既能让一个新手从正门登堂入室,也能让一个有经验的开发人员获得提升,以此大力推介之。
文:西门町学士
Eclipse的阵营一向强大,最近又加入了一家重量级的公司:Google,相形之下,NetBeans的阵营显得有点那么“势单力薄”。
我本人则由于对Swing的喜爱及对SWT的不喜爱,一直(从NB3.0以来)使用NetBeans。
(以前的NetBeans确实不够好用,建个Project还得先mount一下,典型的Unix思维)双方这几年的发展,从架构和功能上来说,现在NetBeans和Eclipse已经是大同小异,没有谁比谁牛×。对于developers,用谁凭喜好。
可
对于想通过这两个平台来赚钱的企业来说,二者的区别可就太大了。看看Eclipse的阵营(双方的家长就不提了):BEA, Borland,
Intel, Sybase, Adobe, Oracle, Google,
etc全是些IT届NB哄哄的大牛;再看看NetBeans的部队:一队的无名小卒,大名鼎鼎的也有:Amazon:卖书的;eBay:做生意的;HP:
卖PC的;还有卖手机的,做开源的,不一而足,感觉有点歪瓜裂枣似的。我就纳闷儿了:同样都是做Java IDE
的,受到的待遇区别咋就这么大呢!何况像Borland这样的本来JBuilder和NetBeans就很相近,为什么还得绕个弯儿去舔SWT的屁股?
(李維还在信心满满的说什么
Java開發王者,反正我是不信
)
今
儿个感觉有点想明白了:Eclipse是搭个基本架子,剩下的这些公司在上面做自己的东东然后就可以拿去卖钱了,像MyEclipse、Borland都
是这么个想法;而NetBeans呢,Sun好像是把它定位成送给Developers的礼物(那里面装的当然就会是Sun所领导的Java技术,而不会
是那个觊觎者IBM的Java技术),IDE free, Web pack free, mobility pack free,
Enterprise pack free,
等等等等通通free,免费大赠送,咱们开发者当然是高兴了,既不要钱,又是最新技术,还有个Sun盖的“正统”大章。可对于那些公司就不一样了,老子吃
的就是这碗饭,你全送人了我喝西北风啊?还活不活啊我?你以为我像JBoss那样傻,不卖产品卖服务?JBoss不就是发现这碗饭不好吃才把
Rickard
Oberg这个顽固不化的家伙给踹出门的吗。所以这些公司才纷纷对NetBeans离的远远的,像见了娘亲一向扑向Eclipse的怀抱~~
不管怎么说,我还是Swing的坚定支持者,支持Sun,支持NetBeans,最后,感谢James Golsing,感谢Groove Coverage(我是边听God is A Girl一边码字儿的),感谢你的眼睛不辞辛劳地看到这里!
假如我们要精确计算一个很大的数,比如说,256的阶乘(结果有500多位),怎么办?
你会说,很好办啊,从JDK 1.1起Java不是提供了一个java.math.BigInteger吗?不错,用BigInteger确实能解决问题。不过,如果没有Sun给的这个class,仅仅靠Java最基本的那些类型,我们有没有办法来进行计算呢?答案是,肯定是能嘛,要不然在BigInteger之前怎么办。
方法之一就是用数组来表示。比如说:
int[] data = new int[100];
我们知道,一个int的最大值为2^31-1即2147483647(10位),如果我们把这100个int值串起来,我们就能表示一个1000位的数。这里我们就用这种方式来计算256的阶乘(256!)。
我们先分配100个int的数组,由于是static,所以每个int的初始值都是0。
然后每个int表示6位数,即最大值为999999。因为我们要做乘法,如果给int的位数过大,如9位,那么999999999乘上一个数,如100,它的值就大于了int的max值,造成溢出。所以int表示的位数需要根据需要仔细选择。(用long来表示也同样需要仔细权衡位数)
再定义一个num来表示我们占用的数组的int个数
在乘法的时候,对每个占用的int中的数都要乘,然后一个一个地判断每个int中的值是不是超出了6位:
if (data[j]) > 1000000)
如果超出了则需要进位:
data[k+1] += data[k]/1000000;
data[k] %= 1000000;
一个个判断,最后,如果最高位(即data[num])中的数值也超过了6位,我们就需要占用一个新的int,同样地进位,当然也不要忘了给num加一。
if (data[num] > 1000000) num++;
最后,将我们的数组顺序输出即可。在输出的时候需要小心的是,如果int中的值小于6位,如25,别忘了补上0,即000025,否则你会得到错误的答案的。
完整的代码如下:
package tmp;
/**
*
* @author Stevech
*/
public class BigNumbers {
static int[] data = new int[100];
/** Creates a new instance of BigNumers */
public static void main(String[] args) {
int num = 0; // 占用的个数
data[0] = 1; // 0和1的阶乘是1
for (int i = 2; i < 257; i++) {
for (int j = 0; j < num + 1; j++) {
data[j] *= i; // 对每个int中的数都乘上 i
}
for (int j = 0; j < num + 1; j++) {
if (data[j] > 1000000) {
for (int k = j; k < num + 1; k++) {
if (data[num] > 1000000) num++;
data[k+1] += data[k]/1000000; // 进位
data[k] %= 1000000; // 进位后的余数
}
}
}
}
System.out.println("占用的int数:" + (num+1) + "\n值:");
System.out.print(data[num]);
for (int i = num-1; i > -1; i--) {
System.out.print(new java.text.DecimalFormat("000000").format(data[i]));
}
}
}
输出结果为:
占用的int数:85
值:
85781777534284265411908227168123262515778152027948561985965565037726945255314
75893774402913604514084503758853423365843061571968346936964753222892884974260256
79637332563368786442675207626794560187968867971521143307702077526646451464709187
32610083287632570281898077367178145417025052301860849531906813825748107025281755
94594769870346657127381392862052347568082188607012036110831520935019474371091017
26968262861606263662435022840944191408424615936000000000000000000000000000000000
000000000000000000000000000000
在使用
Swing的JTextField时,我们常常希望只接受那些符合我们要求的录入,如数字、电话号码、邮政编码、E-mail等。JFC工作组在这方面也做了很多工作,每一次新的Java Se发布,往往都提供了新的、更方便和强大的有效性验证方式,在这里列举几种不同的验证方式。
这是最直觉的方式。利用
KeyListener来选择允许的字符,且添加FocusListener,使得
内容不符合要求时不允许焦点转移。这种方式很繁琐,
Sun的建议是不推荐使用这种方式。
我们知道,
Swing组件是基于MVC实现的。JTextComponent的Model是一个叫做Document的Interface,我们可以通过限制Document的内容来达到有效性验证的目的。javax.swing.text包中有多个不同的Document的实现,JTextField使用的是PlainDocument。如果我们希望JTextField只接受数字,可以实现我们特定的Document并使之替换默认的Document:
package sdn;
import javax.swing.text.*;
public class IntegerDocument extends PlainDocument {
int currentValue = 0;
public int getValue() {
return currentValue;
}
public void insertString(int offset, String string,
AttributeSet attributes) throws BadLocationException {
if (string == null) {
return;
} else {
String newValue;
int length = getLength();
if (length == 0) {
newValue = string;
} else {
String currentContent = getText(0, length);
StringBuffer currentBuffer =
new StringBuffer(currentContent);
currentBuffer.insert(offset, string);
newValue = currentBuffer.toString();
}
currentValue = checkInput(newValue, offset);
super.insertString(offset, string, attributes);
}
}
public void remove(int offset, int length)
throws BadLocationException {
int currentLength = getLength();
String currentContent = getText(0, currentLength);
String before = currentContent.substring(0, offset);
String after = currentContent.substring(length+offset,
currentLength);
String newValue = before + after;
currentValue = checkInput(newValue, offset);
super.remove(offset, length);
}
public int checkInput(String proposedValue, int offset)
throws BadLocationException {
if (proposedValue.length() > 0) {
try {
int newValue = Integer.parseInt(proposedValue);
return newValue;
} catch (NumberFormatException e) {
throw new BadLocationException(proposedValue, offset);
}
} else {
return 0;
}
}
}
然后用
IntegerDocument去替换JTextField默认的Document:
package sdn;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
public class NumericInput {
public static void main(String args[]) {
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("Numeric Input");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(2, 2));
frame.add(new JLabel("Number"));
JTextField fieldOne = new JTextField();
Document doc= new IntegerDocument();
fieldOne.setDocument(doc);
frame.add(fieldOne);
frame.add(new JLabel("All"));
JTextField fieldTwo = new JTextField();
frame.add(fieldTwo);
frame.setSize(250, 90);
frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
代码很简单,一目了然。这里说点题外话,
Sun建议的Swing Application的main函数写法如上所示:先建一个Runnable,然后把这个Runnable放到event-dispatch thread中去执行。另外,以前有的Developer(比如我)喜欢用SwingUtilities.invokeLater(runner)来将一个thread放到event-dispatch thread中,现在Sun也建议用EventQueue.invokeLater(runner),因为SwingUtilities方法版本仅仅是对EventQueue方法版本的一个包装。
在
J2SE 1.3中加入了一个名为InputVerifier的抽象类,可用于任何JComponent。其中定义了boolean verifiy(JComponent input)方法。如果组件中的文本是有效的,当焦点转移时(如按下Tab或Shift-Tab),verify方法返回true;否则返回false,使得焦点仍停留在当前组件上。我们仍以数字为例:
package sdn;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class NumericVerifier{
public static void main(String args[]) {
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("Numeric Verifier");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel1 = new JPanel(new BorderLayout());
JLabel label1 = new JLabel("Numeric-only");
JTextField textField1 = new JTextField();
panel1.add(label1, BorderLayout.WEST);
panel1.add(textField1, BorderLayout.CENTER);
JPanel panel2 = new JPanel(new BorderLayout());
JLabel label2 = new JLabel("Anything");
JTextField textField2 = new JTextField();
panel2.add(label2, BorderLayout.WEST);
panel2.add(textField2, BorderLayout.CENTER);
JPanel panel3 = new JPanel(new BorderLayout());
JLabel label3 = new JLabel("Numeric-only");
JTextField textField3 = new JTextField();
panel3.add(label3, BorderLayout.WEST);
panel3.add(textField3, BorderLayout.CENTER);
InputVerifier verifier = new InputVerifier() {
public boolean verify(JComponent comp) {
boolean returnValue;
JTextField textField = (JTextField)comp;
try {
Integer.parseInt(textField.getText());
returnValue = true;
} catch (NumberFormatException e) {
Toolkit.getDefaultToolkit().beep();
returnValue = false;
}
return returnValue;
}
};
textField1.setInputVerifier(verifier);
textField3.setInputVerifier(verifier);
frame.add(panel1, BorderLayout.NORTH);
frame.add(panel2, BorderLayout.CENTER);
frame.add(panel3, BorderLayout.SOUTH);
frame.setSize(300, 95);
frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
这个例子的效果和上一个是不同的。自定义
Document的App中,用户将会发现任何非数字的字符都不会在JTextField中出现;而在使用InputVerifier的App中,用户在录入字符时不会发现任何异常,但是当他确认录入完成后,如果内容不符合有效性,焦点将不会转移!这两种情况都可能让一个没有经验的用户茫然,具体使用哪一种是一个见仁见智的问题。
在
J2SE 1.4中,又加入了一个新的类:DocumentFilter。你无需再实现一个新的Document,而是对现有的Document过滤一遍。它的结果与实现自定义的Document并无二样,仅仅是思路不同而已。
package snd;
import javax.swing.text.*;
import java.awt.Toolkit;
public class IntegerDocumentFilter extends DocumentFilter {
int currentValue = 0;
public IntegerDocumentFilter() {
}
public void insertString(DocumentFilter.FilterBypass fb,
int offset, String string, AttributeSet attr)
throws BadLocationException {
if (string == null) {
return;
} else {
replace(fb, offset, 0, string, attr);
}
}
public void remove(DocumentFilter.FilterBypass fb,
int offset, int length)
throws BadLocationException {
replace(fb, offset, length, "", null);
}
public void replace(DocumentFilter.FilterBypass fb,
int offset, int length, String text, AttributeSet attrs)
throws BadLocationException {
Document doc = fb.getDocument();
int currentLength = doc.getLength();
String currentContent = doc.getText(0, currentLength);
String before = currentContent.substring(0, offset);
String after = currentContent.substring(
length+offset, currentLength);
String newValue = before +
(text == null ? "" : text) + after;
currentValue = checkInput(newValue, offset);
fb.replace(offset, length, text, attrs);
}
private int checkInput(String proposedValue, int offset)
throws BadLocationException {
int newValue = 0;
if (proposedValue.length() > 0) {
try {
newValue = Integer.parseInt(proposedValue);
} catch (NumberFormatException e) {
throw new BadLocationException(
proposedValue, offset);
}
}
return newValue;
}
}
再将这个
Filter应用于Document:
package sdn;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
public class NumericInputFilter {
public static void main(String args[]) {
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("Numeric Input Filter");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(2, 2));
frame.add(new JLabel("Number"));
JTextField textFieldOne = new JTextField();
Document doc= textFieldOne.getDocument();
DocumentFilter filterOne = new IntegerDocumentFilter();
((AbstractDocument)doc).setDocumentFilter(filterOne);
textFieldOne.setDocument(doc);
frame.add(textFieldOne);
frame.add(new JLabel("All"));
JTextField textFieldTwo = new JTextField();
frame.add(textFieldTwo);
frame.setSize(250, 90);
frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
DocumentFilter只能用于Swing中的与text有关的组件(而InputVerifier可用于任何组件)。除了这几种方法,在对于TextField而言,我们还有JFormattedTextField,很多时候用JFormattedTextField将是非常容易和简单的方式。
注:这篇文章基本根据SDN的Core Java Tech Tips意译而来,代码基本跟其一致,另外还参考了M. Robinson & P. Vorobiev的Swing, Chapter 11