Just Java IT

西门町学士关于Java的随便一说而已……

2006年3月16日 #

走进JavaFX-(2)

     摘要: 我犹豫了好一阵才决定写JavaFX的语法部分。个人认为这是学习中最枯燥的部分。因为JavaFX的语法非常简单且直观,比如Sun提供的在线 Tutorial的GUI部分,即使你是第一次听说JavaFX这个东西,只要你稍有一点点编程经验,你也基本上能够毫无障碍地理解这个Tutorial 的内容了。
话虽如此,部分语法可能确实会造成一些理解困难,比如有的地方分隔符用逗号(,)分号(;)和空格都可以,def和var的区别,=>操作符,等等这些还得初看一遍语法才能理解(当然,基本上就没有必要看第二遍了吧)。因此,我也在此将JavaFX的语法照着Sun的语法 Tutorial快速地过一遍,为以后打下一个坚实(!)的基础,呵呵。  阅读全文

posted @ 2008-12-16 01:05 西门町学士 阅读(1789) | 评论 (4)编辑 收藏

走进JavaFX-(1u1)

/**
以前写了一个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
}

结果如图:

posted @ 2008-12-12 22:42 西门町学士 阅读(1460) | 评论 (1)编辑 收藏

走进JavaFX-(1)

     摘要: JavaFX出来已经很长一段时间了。一直在计划跟进,可是因为比较懒,现在才慢慢地学习。这里就暂做做学习总结的地方吧。
虽然是总结,我还是打算写详细一点。本来我对JavaFX了解也不是很多,有的东西还要在网上查证了才能写(比较JavaFX是如何诞生,如何从F3变成 JavaFX的)。今天要写的主要是:1、JavaFX的前世今生;(了解了它的历史也就了解了它是什么,它的发展方向,呵呵)2、如何拥有 JavaFX;(知道从哪里去下载开发工具,如何配置它)3、Hello JavaFX World(当然,一个经典的Hello World是不能少的)  阅读全文

posted @ 2008-07-18 11:12 西门町学士 阅读(1833) | 评论 (6)编辑 收藏

NetBeans无好书[顺便推荐两本Java书]

首先声明,本文作者信手乱写,以前候捷写无责任书评,无责任这三个字,在我这儿也差不多——西门町学士 (注)

前两天逛书店,看到一本《精通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入门与提升均应多读此书。
这两本书最大的特点就是,呵呵,用侯捷的话说,叫深入浅出。在讲一个技术的同时,也讲正确的编码和设计方法,既能让一个新手从正门登堂入室,也能让一个有经验的开发人员获得提升,以此大力推介之。

posted @ 2007-06-10 23:45 西门町学士 阅读(900) | 评论 (1)编辑 收藏

又说Eclipse与NetBeans

文:西门町学士

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一边码字儿的),感谢你的眼睛不辞辛劳地看到这里!

posted @ 2006-12-15 22:42 西门町学士 阅读(1129) | 评论 (4)编辑 收藏

数组的力量

    假如我们要精确计算一个很大的数,比如说,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

posted @ 2006-04-16 21:19 西门町学士 阅读(1943) | 评论 (3)编辑 收藏

JTextField内容有效性验证几种方式

在使用 SwingJTextField时,我们常常希望只接受那些符合我们要求的录入,如数字、电话号码、邮政编码、E-mail等。JFC工作组在这方面也做了很多工作,每一次新的Java Se发布,往往都提供了新的、更方便和强大的有效性验证方式,在这里列举几种不同的验证方式。

  • 利用键盘和焦点事件

这是最直觉的方式。利用 KeyListener来选择允许的字符,且添加FocusListener,使得

内容不符合要求时不允许焦点转移。这种方式很繁琐, Sun的建议是不推荐使用这种方式。

  • 使用自定义的 Document

我们知道, Swing组件是基于MVC实现的。JTextComponentModel是一个叫做DocumentInterface,我们可以通过限制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 Applicationmain函数写法如上所示:先建一个Runnable,然后把这个Runnable放到event-dispatch thread中去执行。另外,以前有的Developer(比如我)喜欢用SwingUtilities.invokeLater(runner)来将一个thread放到event-dispatch thread中,现在Sun也建议用EventQueue.invokeLater(runner),因为SwingUtilities方法版本仅仅是对EventQueue方法版本的一个包装。

  • InputVerifier来实现

J2SE 1.3中加入了一个名为InputVerifier的抽象类,可用于任何JComponent。其中定义了boolean verifiy(JComponent input)方法。如果组件中的文本是有效的,当焦点转移时(如按下TabShift-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);
}
}

这个例子的效果和上一个是不同的。自定义 DocumentApp中,用户将会发现任何非数字的字符都不会在JTextField中出现;而在使用InputVerifierApp中,用户在录入字符时不会发现任何异常,但是当他确认录入完成后,如果内容不符合有效性,焦点将不会转移!这两种情况都可能让一个没有经验的用户茫然,具体使用哪一种是一个见仁见智的问题。

  • 使用 Document Filter

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

posted @ 2006-04-09 16:26 西门町学士 阅读(2353) | 评论 (0)编辑 收藏

Tiger pitfall

在SDN踩到一个Tiger的pitfall:
package sdn;

import java.util.ArrayList;

public class BoxingEquality {
   
    /** Creates a new instance of BoxingEquality */
    public BoxingEquality() {
    }
   
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        int i = 1;
        int j = 1;
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(i);
        list.add(j);
        System.out.printf("It is %b that i == j.\n", (i==j));
        System.out.printf("It is %b that list.get(0) == list.get(1).\n", (list.get(0)==list.get(1)));
        System.out.printf("It is %b that list.get(0).equals(list.get(1)).",            list.get(0).equals(list.get(1)));
    } 
}

输出结果出乎意料:
It is true that i == j.
It is true that list.get(0) == list.get(1).    // WHY???
It is true that list.get(0).equals(list.get(1)).

然而,仅仅将 i 和 j 的值改成1000:
int i = 1000;
int j = 1000;
就这一个改动后输出结果虽然符合了java的思维方式,但在这个context中却更显得怪异:
It is true that i == j.
It is false that list.get(0) == list.get(1). // Oops
It is true that list.get(0).equals(list.get(1)).

Sun给出的解释:
The primitives are equal and the values of the boxed ints are equal. But this time the ints point to different objects. What you have discovered is that for small integral values, the objects are cached in a pool much like Strings. When i and j are 2, a single object is referenced from two different locations. When i and j are 2000, two separate objects are referenced. Autoboxing is guaranteed to return the same object for integral values in the range [-128, 127], but an implementation may, at its discretion, cache values outside of that range. It would be bad style to rely on this caching in your code.

呵呵,要不注意说不定还真中招了!

posted @ 2006-03-16 22:03 西门町学士 阅读(327) | 评论 (4)编辑 收藏