Do you drink java?



      像写情书一样coding

 

2005年9月11日

发发牢骚

IE7访问我的部落格页面布局异常!

Firefox2.0添加新随笔JS脚本异常!!

|/__


换了风格

posted @ 2006-11-23 16:49 leon 阅读(386) | 评论 (0)编辑 收藏

[Swing]在 JFileChooser 中进行文件验证的小技巧

我们在做GUI编程的时候经常需要用到JFileChooser组件构造一个文件选取对话框来为用户提供打开文件、保存文件等操作。

通常的做法是调用JFileChooser.showXXX()方法显示文件选取对话框并且选择一个文件后,点击Approve 按钮(默认情况下标有 "Open" 或 "Save")当对话框关闭后使用JFileChooser.getSelectedFile()方法得到选取的文件(或使用JFileChooser.getSelectedFiles()取得选取的文件数组),然后再对被选取的文件有效性进行验证(例如,文件的文件名是否合法、选取的路径下是否已有同名文件存在等等),如果验证不通过,需要再次打开文件选择对话框进行选取。

显然,验证没有通过的情况下,文件选取对话框被反复的打开和关闭,影响用户体验。

我现在介绍一个方法,在点击了文件选取对话框上的Approve 按钮后,文件选取对话框关闭前对选取的文件进行验证,如果验证没有通过,那么对话框不关闭,直接进行下一次选择。

查看JFileChooser的API,可以发现这样一个方法 public void approveSelection() ,这个方法会在用户单击 Approve 按钮时由 UI 调用此方法。导致使用等于 APPROVE_SELECTION 的命令字符串激发一个操作事件。

那么,我们现在可以选择继承JFileChooser再覆写这个方法,将对选中文件的有效性验证写入这个方法中,只有当验证通过时才调用超类的approveSelection() 完成文件选取,否则直接返回,继续选择新的文件。

下面是我写的一个demo以供参考:

import java.io.File;
import javax.swing.JOptionPane;

/**
 * 在 JFileChooser 中进行文件验证的小技巧
 * @author Chen Wei
 * @email chenwei.mobi@gmail.com
 */
public class JFileChooserDemo extends javax.swing.JFileChooser{
   
    public void approveSelection(){
        File file = getSelectedFile();
       
        // 验证文件名是否合法
        if (!validateFileName(file.getName())) {
            JOptionPane.showMessageDialog(getParent(), "文件名不能包含下列任何字符之一:\n \\ / : * ? \" < > |");
            return;
        }else{
            super.approveSelection();
        }
    }
   
    /**
     * 验证输入字符串参数是否为有效文件名。
     * @param name 待验证的文件名字符串。
     * @return 通过验证,文件名无效返回 false,有效返回 true。
     */
    public static boolean validateFileName(String name) {
        if (name.indexOf('\\') != -1 || name.indexOf('/') != -1 ||
            name.indexOf(':') != -1 || name.indexOf('*') != -1 ||
            name.indexOf('?') != -1 || name.indexOf('"') != -1 ||
            name.indexOf('<') != -1 || name.indexOf('>') != -1 ||
            name.indexOf('|') != -1) {

            return false;
        } else {
            return true;
        }
    }
   
    public static void main(String[] args){
        JFileChooserDemo chooser = new JFileChooserDemo();
        chooser.showOpenDialog(null);
    }
}


程序运行截图:
JFileChooserDemo.jpg

posted @ 2006-11-23 14:15 leon 阅读(5380) | 评论 (7)编辑 收藏

[news]chenwei.mobi

本博搬家到CSDN,网址 http://blog.csdn.net/chenweionline ,可以通过 www.chenwei.mobi 访问!

posted @ 2006-10-30 17:16 leon 阅读(529) | 评论 (0)编辑 收藏

[tips]使用Java将中文字符转换成Unicode编码

这两天操作XML使用到了Jdom,在创建XML文件并输出到硬盘的时候遇到一个中文编码的问题:Jdom默认输出的XML编码是UTF-8,但是文档中如果出现中文字符那么该中文字符就会变成乱码,造成XML文件无法被正确解析。

UTF-8应该是可以用来表示中文的吧?我不知道这是不是Jdom的一个BUG(Jdom 1.0,beta了10次的产物哦!)。我google了一下,大家解决这个问题的办法无非是把Jdom的输出字符集改为GBK或者GB2312,但是这样就会有一些副作用,如果在没有特定字符集(GBK或者GB2312)的操作系统上不是依然不能正确解析吗?一个比较好的解决办法是先把中文转换成Unicode编码在直接输出,程序解析XML后的时候再把Unicode编码转回中文就没有问题了。

于是我查看了JDK的文档,截至Java 5好像都没有做类似转换的类可以直接使用,但是我发现一个类 java.util.Properties,它的源代码里有两个私有(private)方法 loadConvert (char[] in, int off, int len, char[] convtBuf) 和 saveConvert(String theString, boolean escapeSpace) 其实就是做特殊字符和Unicode编码字符间转换的,我把它们提取出来,单独包装到一个类里就可以使用了。

下面是我包装的类 CharacterSetToolkit

/*
 * CharacterSetToolkit.java
 *
 * Created on 2006年10月27日, 下午2:06
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package mobi.chenwei.lang;

/**
 * 进行字符操作的工具类
 * @author Chen Wei
 * @email chenwei.mobi@gmail.com
 */
public class CharacterSetToolkit {
   
    /** Creates a new instance of CharacterSetToolkit */
    public CharacterSetToolkit() {
    }
   
    private static final char[] hexDigit = {
        '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
    };
   
    private static char toHex(int nibble) {
        return hexDigit[(nibble & 0xF)];
    }
   
    /**
     * 将字符串编码成 Unicode 。
     * @param theString 待转换成Unicode编码的字符串。
     * @param escapeSpace 是否忽略空格。
     * @return 返回转换后Unicode编码的字符串。
     */
    public static String toUnicode(String theString, boolean escapeSpace) {
        int len = theString.length();
        int bufLen = len * 2;
        if (bufLen < 0) {
            bufLen = Integer.MAX_VALUE;
        }
        StringBuffer outBuffer = new StringBuffer(bufLen);

        for(int x=0; x<len; x++) {
            char aChar = theString.charAt(x);
            // Handle common case first, selecting largest block that
            // avoids the specials below
            if ((aChar > 61) && (aChar < 127)) {
                if (aChar == '\\') {
                    outBuffer.append('\\'); outBuffer.append('\\');
                    continue;
                }
                outBuffer.append(aChar);
                continue;
            }
            switch(aChar) {
                case ' ':
                    if (x == 0 || escapeSpace)
                        outBuffer.append('\\');
                    outBuffer.append(' ');
                    break;
                case '\t':outBuffer.append('\\'); outBuffer.append('t');
                          break;
                case '\n':outBuffer.append('\\'); outBuffer.append('n');
                          break;
                case '\r':outBuffer.append('\\'); outBuffer.append('r');
                          break;
                case '\f':outBuffer.append('\\'); outBuffer.append('f');
                          break;
                case '=': // Fall through
                case ':': // Fall through
                case '#': // Fall through
                case '!':
                    outBuffer.append('\\'); outBuffer.append(aChar);
                    break;
                default:
                    if ((aChar < 0x0020) || (aChar > 0x007e)) {
                        outBuffer.append('\\');
                        outBuffer.append('u');
                        outBuffer.append(toHex((aChar >> 12) & 0xF));
                        outBuffer.append(toHex((aChar >>  8) & 0xF));
                        outBuffer.append(toHex((aChar >>  4) & 0xF));
                        outBuffer.append(toHex( aChar        & 0xF));
                    } else {
                        outBuffer.append(aChar);
                    }
            }
        }
        return outBuffer.toString();
    }
   
    /**
     * 从 Unicode 码转换成编码前的特殊字符串。
     * @param in Unicode编码的字符数组。
     * @param off 转换的起始偏移量。
     * @param len 转换的字符长度。
     * @param convtBuf 转换的缓存字符数组。
     * @return 完成转换,返回编码前的特殊字符串。
     */
    public String fromUnicode(char[] in, int off, int len, char[] convtBuf) {
        if (convtBuf.length < len) {
            int newLen = len * 2;
            if (newLen < 0) {
                newLen = Integer.MAX_VALUE;
            }
            convtBuf = new char[newLen];
        }
        char aChar;
        char[] out = convtBuf;
        int outLen = 0;
        int end = off + len;

        while (off < end) {
            aChar = in[off++];
            if (aChar == '\\') {
                aChar = in[off++];
                if (aChar == 'u') {
                    // Read the xxxx
                    int value = 0;
                    for (int i = 0; i < 4; i++) {
                        aChar = in[off++];
                        switch (aChar) {
                        case '0':
                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                        case '8':
                        case '9':
                            value = (value << 4) + aChar - '0';
                            break;
                        case 'a':
                        case 'b':
                        case 'c':
                        case 'd':
                        case 'e':
                        case 'f':
                            value = (value << 4) + 10 + aChar - 'a';
                            break;
                        case 'A':
                        case 'B':
                        case 'C':
                        case 'D':
                        case 'E':
                        case 'F':
                            value = (value << 4) + 10 + aChar - 'A';
                            break;
                        default:
                            throw new IllegalArgumentException(
                                    "Malformed \\uxxxx encoding.");
                        }
                    }
                    out[outLen++] = (char) value;
                } else {
                    if (aChar == 't') {
                        aChar = '\t';
                    } else if (aChar == 'r') {
                        aChar = '\r';
                    } else if (aChar == 'n') {
                        aChar = '\n';
                    } else if (aChar == 'f') {
                        aChar = '\f';
                    }
                    out[outLen++] = aChar;
                }
            } else {
                out[outLen++] = (char) aChar;
            }
        }
        return new String(out, 0, outLen);
    }
}

posted @ 2006-10-28 20:53 leon 阅读(10668) | 评论 (3)编辑 收藏

[ad]city8升级预告

9月26日(下周二),city8(www.city8.com)将进行一次升级。

更新内容:

1、上海的中环、外环以内的数据添加,这样一来整个上海的数据就全了,大家想去哪,就可以看到哪了。

 2、三维实景窗口变大,看高楼不那么累了:)

3、操作按钮重新设计,这样大家可以方便实现在街道中行走、全屏浏览等很酷的体验。

4、实景地图分享:可以方便在地图添加文字表述,如“我的家”,并通过msn,qq,blog,论坛等方式与他人分享

界面先睹为快:

首页:
homepage

搜索结果页面:
main search

posted @ 2006-09-23 14:25 leon 阅读(462) | 评论 (2)编辑 收藏

[tips]Java 中十进制十六进制相互转换

// 十进制转化为十六进制,结果为C8。
Integer.toHexString(200);

// 十六进制转化为十进制,结果140。
Integer.parseInt("8C",16);

posted @ 2006-09-19 12:02 leon 阅读(18189) | 评论 (2)编辑 收藏

[Image]使用 Java 2D 对图像进行缩放

     /**
     * 缩放 - 参数指定目标图缩放比例。
     * 
@param  srcImage 源图像对象。
     * 
@param  xscale 图像 x 轴(宽度)上的的缩放比例。
     * 
@param  yscale 图像 y 轴(高度)上的的缩放比例。
     * 
@param  hints 重新绘图使用的 RenderingHints 对象。
     * 
@return  缩放后的图像对象。
     
*/

    
public   static  BufferedImage scaleJ2D(BufferedImage srcImage,  double  xscale,  double  yscale, RenderingHints hints)  {
        
int  width  =  ( int ) (( double ) srcImage.getWidth()  *  xscale);
        
int  height  =  ( int ) (( double ) srcImage.getHeight()  *  yscale);
        
        AffineTransform affineTransform 
=   new  AffineTransform();
        affineTransform.scale(xscale, yscale);
        
if (hints  ==   null ) {
            hints 
=   new  RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_DEFAULT);
        }

        AffineTransformOp affineTransformOp 
=   new  AffineTransformOp( affineTransform, hints);
        
        BufferedImage dstImage 
=   new  BufferedImage(width, height, srcImage.getType());
        
        
return  affineTransformOp.filter(srcImage, dstImage);
    }

posted @ 2006-08-27 18:41 leon 阅读(1207) | 评论 (1)编辑 收藏

[Image]使用 Java 2D 将彩色图像转换成灰度图

     /**
     * 将彩色图像转换为灰度图。
     * 
@param  srcImage 源彩色图像。
     * 
@param  hints 重新绘图使用的 RenderingHints 对象。
     * 
@return  目标灰度图。
     
*/

    
public   static  BufferedImage transformGrayJ2D(BufferedImage srcImage,RenderingHints hints)  {
        BufferedImage dstImage 
=   new  BufferedImage(srcImage.getWidth(), srcImage.getHeight(), srcImage.getType());
        
        
if  (hints  ==   null {
            Graphics2D g2 
=  dstImage.createGraphics();
            hints 
=  g2.getRenderingHints();
            g2.dispose();
            g2 
=   null ;
        }

        
        ColorSpace grayCS 
=  ColorSpace.getInstance(ColorSpace.CS_GRAY);
        ColorConvertOp colorConvertOp 
=   new  ColorConvertOp(grayCS, hints);
        colorConvertOp.filter(srcImage, dstImage);
        
        
return  dstImage;
    }

posted @ 2006-08-27 14:33 leon 阅读(1612) | 评论 (0)编辑 收藏

[Image]使用 Java 2D 取得图像上指定位置像素的 rgb 颜色分量

     /**
     * 取得图像上指定位置像素的 rgb 颜色分量。
     * 
@param  image 源图像。
     * 
@param  x 图像上指定像素位置的 x 坐标。
     * 
@param  y 图像上指定像素位置的 y 坐标。
     * 
@return  返回包含 rgb 颜色分量值的数组。元素 index 由小到大分别对应 r,g,b。
     
*/

    
public   static   int [] getRGB(BufferedImage image, int  x, int  y) {
        
int [] rgb  =   null ;
        
        
if (image  !=   null   &&  x  <  image.getWidth()  &&  y  <  image.getHeight()) {
            rgb 
=   new   int [ 3 ];
            
int  pixel  =  image.getRGB(x,y);
            rgb[
0 =  (pixel  &   0xff0000 >>   16 ;
            rgb[
1 =  (pixel  &   0xff00 >>   8 ;
            rgb[
2 =  (pixel  &   0xff );
        }

        
        
return  rgb;
    }


使用这个方法前需要先将图像文件从磁盘上读到一个 java.awt.image.BufferedImage 对象中,我们可以用 J2SE 包含的 ImageIO 库。

try   {
    BufferedImage bi 
=  ImageIO.read( new  File( "  test.jpg  " ));
}
  catch  (IOException ex)  {
    ex.printStackTrace();
}

posted @ 2006-08-16 10:55 leon 阅读(2952) | 评论 (0)编辑 收藏

胃痉挛

胃痉挛,疼痛,瞬间失去意识。

只剩触觉,全身抽搐,十几到几十秒钟后意识逐渐清晰,发现躺在地上。

后遗症是身体多处划伤和脖子扭了。

人生经验:一大早不要喝冰可乐。

posted @ 2006-07-03 12:06 leon 阅读(21319) | 评论 (69)编辑 收藏

[Download] Java 2 图形设计卷Ⅰ:AWT

Java2AWT_s.jpg
Java 2 图形设计卷Ⅰ:AWT
Graphic Java 1.2 Mastering the JFC Volume Ⅰ:AWT
[美]David M.Geary 著 马欣民等译
机械工业出版社

http://www.blogjava.net/Files/leon/Java2图形设计卷1AWT.rar

posted @ 2006-06-21 11:07 leon 阅读(2075) | 评论 (9)编辑 收藏

[zt] Swing是MVC设计的典范

不管你的项目是否用到了Swing技术,我都要说,Swing是一个设计优秀的Java包,它充满了大师的智慧。如果你学了Java却连一个Button还不会写,就象你学习Visual Basic却不会用Button,那可绝对是不能被原谅的。Swing技术的应用已经在国外大行其道,由于java的免费、易学以及大家对于java技术的充分信赖,好多公司早早的就把应用程序的一切,从后台服务到前台人机交互界面,统统移到了java开发上。Swing出现了快10年了,凭借其先进的设计思想,一直未曾落后于哪种语言的界面开发技术,使用和理解Swing的设计思想,对软件开发者大有裨益。

Swing的设计是MVC的典范。虽然MVC的概念有点泛滥,可是真正能够理解并熟练掌握、在设计和开发里面自然流露的并不多见。记得用VC++开发程序时候,MFC向导也是生成Document和View两个类,当时一直奇怪为什么这么绕圈子。再看Swing的设计,则到处充满了MVC的痕迹。仔细研究Swing中事件监听、Model-View分离、Renderer/Editor机制、可插拔的LookAndFeel等机制,简直就是一门艺术,充满了美感。而如果你非常痛恨这些设计并觉得他们怪异,很可能你是刚从VB或者Delphi转过来,这些快速开发工具帮助了你也“害”了你。

Swing设计的不错,不过可能过度学术化的设计也使得Swing跑起来并不灵巧,学习难度也大。这客观上确实使得Swing一直没有被广泛使用,而且广受诟病。记得以前“Swing有什么成功的应用吗?”之类的帖子一直是热门话题。IBM等则趁机抓住小辫子弄了SWT吸引了不少人,使得Java GUI技术面临分裂的危险。

不过随着JAVA的不断升级和优化,Swing的速度一直在提高,美观性也在改善,基于Swing的成功应用也越来越多了。关于Swing是否消亡或被SWT代替或是否能作桌面应用的争论逐渐少了。不过喜欢并精通Swing技术的开发者,尤其在国内,依旧非常少。

好在情况在转好。Sun正意识到Eclipse和SWT所带来的威胁,下了大力气发展NetBeans,其最新版本对Swing GUI可视化设计的支持已经超过了所有对手,其Rich Client框架也走向成熟,这对Swing的发展和应用是一个很大的推动。随着WEB热潮的减退,人们又更多的开始理性的思考B/S和C/S架构的选择,某些领域Swing技术已经成为首选的解决方案。随着JGoodies、JIDE、TWaver等优秀Swing产品的不断涌现,Swing会以更快速度在桌面应用中普及。




原文地址http://www.matrix.org.cn/resource/article/44/44417_Swing+MVC.html

posted @ 2006-06-13 10:28 leon 阅读(458) | 评论 (0)编辑 收藏

[tips] Java中的四舍五入

Java.lang.Math的round()方法返回的是整型,如果要保留小数位的话可以先乘以(小数位数 *  10),使用Java.lang.Math的round()方法计算之后再除以(小数位数 *  10)。

     /**
     * 浮点数的四舍五入。
     * 
@param  f float 代表源浮点数
     * 
@param  digits int 保留的小数点后位数
     * 
@return  float
     
*/

    
public   static   float  round( float  f,  int  digits)  {
        
float  offset  =  1f;
        
if  (digits  ==   0 {
            offset 
=  1f;
        }
  else   if  (digits  >   0 {
            offset 
=  digits  *  10f;
        }
  else   if  (digits  <   0 {
            
return  f;
        }


        f 
=  java.lang.Math.round(f  *  offset)  /  offset;
        
return  f;
    }

posted @ 2006-06-07 11:50 leon 阅读(494) | 评论 (1)编辑 收藏

纵横四海

 我喜欢的一张海报,一部电影。

100分钟的光影,一个纵横四海的梦。

英文片名却叫做《Once A Thief》,曾经是个贼。Once,只一个单词,埋葬了所有过往。


OnecAThief.jpg

posted @ 2006-06-03 20:45 leon 阅读(311) | 评论 (0)编辑 收藏

[tips] 获取当前系统的所有可用字体

 // 返回一个数组,它包含此 GraphicsEnvironment 中所有可用字体的像素级实例。
 
Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();

// 返回一个包含此 GraphicsEnvironment 中所有字体系列名称的数组,它针对默认语言环境进行了本地化,由 Locale.getDefault() 返回。
 
String fontNames =  GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();

posted @ 2006-06-03 14:51 leon 阅读(721) | 评论 (0)编辑 收藏

[Image] 读取数码照片中的EXIF信息

相信大家都有使用数码相机拍照的经历,一张数码照片可以包含的内容远远超过了我们当前观察到的景物,他可能包括摄影时的光圈、快门、ISO、日期时间等各种与当时摄影条件相关的讯息,相机品牌型号,色彩编码,拍摄时录制的声音以及全球定位系统(GPS)等信息。这些信息都是存放在一个叫做Exif的文件里,然后把Exif文件放置在我们熟知的 JPEG/TIFF 文件的头部,也就是说 EXIF 信息是镶嵌在 JPEG/TIFF 图像文件格式内的一组拍摄参数。

我在网上找到一个开源的开发工具包Metadata-Extractor,使用它可以像ACDSee等图像软件一样读取数码照片的Exif信息。

我写了一个小Demo程序演示通过使用metadata-extractor-2.2.2读取数码照片的Exif信息并从Exif中读取图像缩略图。
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;

import com.drew.imaging.jpeg.*;
import com.drew.metadata.*;
import com.drew.metadata.exif.*;


 
public class ExifExtractor {
  
public ExifExtractor() {
  }


  
public static void main(String[] args) {
    
try {
      Metadata metadata 
= JpegMetadataReader.readMetadata(new File("o_P4140147.JPG.jpg"));

      Iterator directories 
= metadata.getDirectoryIterator();
      
while (directories.hasNext()) {
        Directory directory 
= (Directory) directories.next();

        Iterator tags 
= directory.getTagIterator();
        
while (tags.hasNext()) {
          Tag tag 
= (Tag) tags.next();

          
// modify Exif
//          if (tag.getTagName().equalsIgnoreCase("User Comment")) {
//                      Directory exifDirectory = metadata.getDirectory(ExifDirectory.class);
//                      exifDirectory.setString(tag.getTagType(), "LeonChen");
//          }

          
// read thumbnail
          if (tag.getTagName().equalsIgnoreCase("Thumbnail Data")) {
            Directory exifDirectory 
= metadata.getDirectory(ExifDirectory.class);

            
byte[] dataBuffer = exifDirectory.getByteArray(tag.getTagType());
            FileChannel channel 
= new RandomAccessFile(new File("thumbnail.jpg"),
                
"rw").getChannel();
            MappedByteBuffer fileBuffer 
= channel.map(FileChannel.MapMode.
                READ_WRITE, 
0, dataBuffer.length);
            fileBuffer.put(dataBuffer);
            fileBuffer.force();
            channel.close();
          }


          
// print exif
          System.out.println(tag);
        }

      }

    }

    
catch (FileNotFoundException ex) {
      ex.printStackTrace();
    }

    
catch (IOException ex) {
      ex.printStackTrace();
    }

    
catch (MetadataException ex) {
      ex.printStackTrace();
    }

    
catch (JpegProcessingException ex) {
      ex.printStackTrace();
    }

  }

}


我在上面的测试程序里注释了一段代码,他们可以在内存中修改Exif中某一节点的信息,但是我不知道怎样才能将修改后的Exif信息保存到文件,如果你知道方法,请给我留言。

测试图片下载地址:
http://www.blogjava.net/images/blogjava_net/leon/2174/o_P4140147.JPG

EXIF参考:
http://www.exif.org

posted @ 2005-11-29 17:04 leon 阅读(2582) | 评论 (5)编辑 收藏

[Swing] 布局管理器 - OverlayLayout

OverlayLayout是用于排列重叠组件的布局管理器。它的用途是以一些对齐的点为基准将一些组件层叠的放置在布局容器中。

组件的横轴和纵轴的对齐点介于0.0和1.0之间。横轴(X轴)上0.0代表组件的左侧面,1.0代表组件的右侧面;纵轴(Y轴)上0.0和1.0分别代表组件的顶部和底部。

构造函数
public OverlayLayout(Container target)

因为构造函数不会为target对象安装结果布局管理器,所以我们还必须调用setLayout()来完成此功能。
JPanel p1 = new JPanel();
OverlayLayout overlay 
= new OverlayLayout(p1);
p1.setLayout(overlay); 

在OverlayLayout布局管理器中,每个组件都有一对横纵坐标值,每个组件的位置只和它本身的横纵坐标值有关,换句话说就是组件以他自己的位置作为基准,横轴上0.0和1.0分别代表组件的左侧面和右侧面;纵轴上0.0和1.0分别代表组件的顶部和底部,和容器位置无关。如果一个组件的alignmentX属性设置为0.5,原本左侧面的位置对应0.0,现在变成了0.5,那么,现在组件的位置就要向左移动width/2的距离,使左侧面的位置对应现在的0.0。纵轴亦是如此,明白了吗?

为了容易理解,我们来看《Java Swing》中关于OverlayLayout的一段样例程序,它可以编译运行。如图,你可以在输入框中调节容器中3个按钮的X,Y轴的值来看他们在容器中的位置是怎样改变的,多试几次,你就可以完全理解OverlayLayout。

OverlayTest.jpg
// OverlayTest.java
// A test of the OverlayLayout manager allowing experimentation.
//

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class OverlayTest extends JFrame {

    
public OverlayTest() {
        
super("OverlayLayout Test");
        setSize(
500300);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        
final Container c = getContentPane();
        c.setLayout(
new GridBagLayout());

        
final JPanel p1 = new GridPanel();
        
final OverlayLayout overlay = new OverlayLayout(p1);
        p1.setLayout(overlay);

        
final JButton jb1 = new JButton("B1");
        
final JButton jb2 = new JButton("B2");
        
final JButton jb3 = new JButton("B3");

        Dimension b1 
= new Dimension(6050);
        Dimension b2 
= new Dimension(8040);
        Dimension b3 
= new Dimension(10060);

        jb1.setMinimumSize(b1);
        jb1.setMaximumSize(b1);
        jb1.setPreferredSize(b1);
        jb2.setMinimumSize(b2);
        jb2.setMaximumSize(b2);
        jb2.setPreferredSize(b2);
        jb3.setMinimumSize(b3);
        jb3.setMaximumSize(b3);
        jb3.setPreferredSize(b3);

        SimpleReporter reporter 
= new SimpleReporter();
        jb1.addActionListener(reporter);
        jb2.addActionListener(reporter);
        jb3.addActionListener(reporter);

        p1.add(jb1);
        p1.add(jb2);
        p1.add(jb3);

        JPanel p2 
= new JPanel();
        p2.setLayout(
new GridLayout(2,6));
        p2.add(
new JLabel("B1 X", JLabel.CENTER));
        p2.add(
new JLabel("B1 Y", JLabel.CENTER));
        p2.add(
new JLabel("B2 X", JLabel.CENTER));
        p2.add(
new JLabel("B2 Y", JLabel.CENTER));
        p2.add(
new JLabel("B3 X", JLabel.CENTER));
        p2.add(
new JLabel("B3 Y", JLabel.CENTER));
        p2.add(
new JLabel(""));

        
final JTextField x1 = new JTextField("0.0"4); // Button1 x alignment
        final JTextField y1 = new JTextField("0.0"4); // Button1 y alignment
        final JTextField x2 = new JTextField("0.0"4); 
        
final JTextField y2 = new JTextField("0.0"4); 
        
final JTextField x3 = new JTextField("0.0"4); 
        
final JTextField y3 = new JTextField("0.0"4); 

        p2.add(x1);
        p2.add(y1);
        p2.add(x2);
        p2.add(y2);
        p2.add(x3);
        p2.add(y3);


        GridBagConstraints constraints 
= new GridBagConstraints();
        c.add(p1, constraints);

        constraints.gridx 
= 1;
        JButton updateButton 
= new JButton("Update");
        updateButton.addActionListener(
new ActionListener() {
            
public void actionPerformed(ActionEvent ae) {
                jb1.setAlignmentX(
                    Float.valueOf(x1.getText().trim()).floatValue());
                jb1.setAlignmentY(
                    Float.valueOf(y1.getText().trim()).floatValue());
                jb2.setAlignmentX(
                    Float.valueOf(x2.getText().trim()).floatValue());
                jb2.setAlignmentY(
                    Float.valueOf(y2.getText().trim()).floatValue());
                jb3.setAlignmentX(
                    Float.valueOf(x3.getText().trim()).floatValue());
                jb3.setAlignmentY(
                    Float.valueOf(y3.getText().trim()).floatValue());

                p1.revalidate();
            }

        }
);
        c.add(updateButton, constraints);

        constraints.gridx 
= 0;
        constraints.gridy 
= 1;
        constraints.gridwidth 
= 2;
        c.add(p2, constraints);
    }


    
public static void main(String args[]) {
        OverlayTest ot 
= new OverlayTest();
        ot.setVisible(
true);
    }


    
public class SimpleReporter implements ActionListener {
        
public void actionPerformed(ActionEvent ae) {
            System.out.println(ae.getActionCommand());
        }

    }


    
public class GridPanel extends JPanel {
        
public void paint(Graphics g) {
            
super.paint(g);
            
int w = getSize().width;
            
int h = getSize().height;

            g.setColor(Color.red);
            g.drawRect(
0,0,w-1,h-1);
            g.drawLine(w
/2,0,w/2,h);
            g.drawLine(
0,h/2,w,h/2);
        }

    }

}



最后提醒,使用OverlayLayout布局管理器关键要记住X,Y轴对应组件位置,和容器没有关系。只要明白这一点,使用还是很简单方便的,我用OverlayLayout布局管理器clone了一个PhotoShop的工具面板。
ToolWidget.jpg

posted @ 2005-11-02 23:08 leon 阅读(3839) | 评论 (0)编辑 收藏

[Image] 将屏幕截图保存成图像文件

import  java.io. * ;
import  java.awt. * ;
import  java.awt.image. * ;
import  javax.imageio. * ;

public   class  CropScreen  {
  
public   static   void  main(String[] args)  {
    
try   {
      Toolkit toolkit 
=  Toolkit.getDefaultToolkit();
      Dimension screenSize 
=  toolkit.getScreenSize();
      Rectangle screenRect 
=   new  Rectangle(screenSize);

      Robot robot 
=   new  Robot();
      BufferedImage image 
=  robot.createScreenCapture(screenRect);
      ImageIO.write(image, 
" jpg " new  File( " screen.jpg " ));
    }

    
catch  (Exception ex)  {
      ex.printStackTrace();
    }

  }

}

posted @ 2005-10-26 11:39 leon 阅读(1259) | 评论 (0)编辑 收藏

[Image] 使用JAI将实现RenderedImage接口的图像对象序列化

我们都知道,图像对象可以编码成指定图像格式文件保存在硬盘上,需要时再对其进行解码读入内存。但是除了这样还有别的办法可以将图像对象保存在硬盘上吗?熟悉Java I/O 的人也许可以想到采用对象序列化(Object serialization)试一试,很好,但是如果你研究了 BufferedImage 类的结构后就会大失所望(至少当时我是这样)。
BufferedImage.jpg

BufferedImage 提供一般图像管理。BufferedImage 对象包括另外两个对象:Raster 和 ColorModel。Raster 对象包含另外两个对象:DataBuffer 和 SampleModel。不幸的是,他们都没有实现序列化所必需的 Serializable 接口,所以无法直接对他们进行对象序列化。

我在学习 JAI 的时候发现了 javax.media.jai.remote 包里有一个类 SerializableRenderedImage,这个类实现了RenderedImage, Serializable 接口,可以将 RanderedImage 对象作为构造函数的参数实例化一个可以序列化的图像对象。

javax.media.jai.remote.SerializableRenderedImage

public final class SerializableRenderedImage
extends Object
implements RenderedImage, Serializable

SerializableRenderedImage(RenderedImage source)
          Constructs a SerializableRenderedImage wrapper for a RenderedImage source.
SerializableRenderedImage(RenderedImage source, boolean useDeepCopy)
          Constructs a SerializableRenderedImage wrapper for a RenderedImage source.
SerializableRenderedImage(RenderedImage source, boolean useDeepCopy, OperationRegistry registry, String formatName, TileCodecParameterList encodingParam, TileCodecParameterList decodingParam)
          Constructs a SerializableRenderedImage wrapper for a RenderedImage source.

查看JDK的文档可以知道无论 Java 2D 中的 BufferedImage 还是 JAI 中的 PlanarImage 都实现自 RenderedImage 接口,也就是说所有实现自 RenderedImage 接口的对象均可作为参数包装出一个 SerializableRenderedImage 类型对象,将其序列化。

下面是一个简单的例子说明了这个类的使用方法:

import java.io.*;
import javax.media.jai.remote.*;

import java.awt.image.*;

public class SomeSerializableClass
    
implements Serializable {
  
protected transient RenderedImage image;

  
// Fields omitted.

  
public SomeSerializableClass(RenderedImage image) {
    
this.image = image;
  }


  
// Methods omitted.

  
// Serialization method.
  private void writeObject(ObjectOutputStream out) throws IOException {
    out.defaultWriteObject();
    out.writeObject(
new SerializableRenderedImage(image, true));
  }


  
// Deserialization method.
  private void readObject(ObjectInputStream in) throws IOException,
      ClassNotFoundException 
{
    in.defaultReadObject();
    image 
= (RenderedImage) in.readObject();
  }

}

posted @ 2005-10-18 17:36 leon 阅读(2823) | 评论 (1)编辑 收藏

[Image] AWT使用ImageProducer/ImagConsumer模式加载和显示图像的原理

以前写过2篇关于AWT中图像加载显示方法的文章,最近又多了一些对于 ImageProducer / ImagConsumer 模式的一些理解,尝试着用文字总结了一下,接着还想再写一篇介绍 AWT 中图像过滤的原理和方法。你可能认为现在学习 AWT 中的成像方法对于开发中已经没有太大的意义,因为已经有了 Java 2D 和 JAI ,但是我在实际工作中感到还是无法完全离开 AWT,特别是在一些基本的应用上。而且我觉得理解 AWT 的 Producer / Consumer (push) model 对于理解 Java 2D 的 Immediate mode model 和 JAI 的 Pipeline (pull) model 的都是有好处的。

因为水平有限,这方面学习资料相对也不丰富,我也不知道我的理解或想法是否完全正确或者表述清楚,感兴趣的朋友可以当作学习参考,希望能够和我联系进行进一步的讨论。



AWT 使用 ImageProducer / ImagConsumer 模式,支持加载和显示 GIF 图像文件格式和 JPEG 图像文件格式。因为图像的加载和显示是异步方式进行的,所以有大量加载和显示的技术。

在 AWT 中,提供了一个 java.awt.Image 类。java.awt.Image 类代表一个图像对象被作为参数传递给其他用来显示和处理图像的其他 AWT 对象使用。例如,通过调用 Graphics.drawImage(java.awt.Image, int, int, ImageObserver) 方法,可以在组件中画出图像。

java.awt.Image 是一个定义方法的抽象类,它定义的方法提供的对图像信息的访问。而创建和处理图像的基本结构则在 java.awt.image 包中。注意,这里不要和 java.awt.Image 发生混淆。

AWT  加载和显示图像使用的是 ImageProducer / ImagConsumer 模式,我们必须了解3个术语,ImageProducer(图像生产者),ImageConsumer(图像消费者)和ImageObserver(图像观察者)。

ImageProducer 负责生产图像的位,ImagConsumer 接受图像的位,ImageObserver 监视 ImageProducer 的图像生产过程。ImageProducer 生产传递给 ImagConsumer 与图像相关的位。因为图像生产过程是异步进行的,并不是一次性生产所有图像位,所以当 ImageProducer 加载图像时,ImageObserver 用来监视它的进展情况。因为 java.awt.Component 实现了 ImageObserver 接口,所以 AWT 中的每个组件都可以是ImageObserver,当一个给定的 ImageProducer 进行异步操作时,这个 ImageObserver 可以选择是否被更新。java.awt.image 包为 ImageProducer,ImagConsumer 和 ImageObserver 都定义了接口。

ImageProducer
和图像相关的位并不存储在 java.awt.Image 中,每个图像都维护一个和一个 ImageProducer 的关联。这个 ImageProducer 的责任是生产图像的位并将它们传送给 ImagConsumer,用于过滤该图像。

java.awt.image软件包中,FilteredImageSource(被过滤的图像源)和 MemoryImageSource(内存的图像源)实现了 ImageProducer  接口,是 ImageProducer 。


ImagConsumer
java.awt.image软件包中,ImageFilter(图像过滤器)和 PixelGrabber(像素抓取器)实现了 ImagConsumer 接口,是 ImagConsumer。


ImageProducer 和 ImagConsumer 的详细介绍请阅读 使用 ImageProducer  / ImagConsumer 进行图像过滤


ImageObserver
ImageObserver接口中,定义了一个常数集合和一个方法:

public boolean imageUpdate(image img, int flags, int x, int y, int width, int height);

ImageObserver的常数
标志 含义
ABORT 图像加载被中断
ALLBITS 所有的位都已加载给图像
ERROR 在加载过程中发生错误
FRAMEBITS 多帧图像的一个帧被传送,一般用于GIF
HEIGHT 图像的高度已经可用
PROPERTIES 图像的属性已经可用
SOMEBITS 图像的缩放变体的多个位已经可用
WIDTH 图像的宽度已经可用

参数 flags 的作用是通知图像观察者图像生产的进展情况。这些常数代表传递给 ImageObserver.imageUpdate() 的 flags 参数中的位。

当 Component 作为 ImageObserver 时,一旦图像有新的部分被加载,就会调用 Component.imageUpdate() 方法,imageUpdate() 再调用 repaint() 重新绘制图像。repaint() 将先调用 update() 方法清除组件背景,再由 update() 方法调用 paint() 方法绘制图像。我们可以通过重载 imageUpdate() 方法控制组件何时被更新,重载 update() 方法控制是否每次重绘都要清除背景图像(每次重绘都清除背景图像会造成画面闪烁)。


为了更好的理解,下面我们来看几个样例程序:

例1,图像位在需要之前不被生产

import java.net.URL;
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;

public class ImageTestAppletSimple extends Applet{
    
private Image im;
    
    
public void init(){
        URL codebase 
= getCodeBase();
        System.out.println(codebase);
        
        im 
= getImage(codebase,"flower.jpg");
        
        System.out.print(
"Image width = " + im.getWidth(this));
        System.out.println(
" hight = " + im.getHeight(this));
    }

    
    
public void paint(Graphics g){
        g.drawImage(im,
0,0,this);
    }

}

输出结果:
image width = -1 height = -1

图像的高度和宽度只有在图像被完全加载后才是有效的,输出结果说明 java.awt.image 相关的图像位在需要之前不被生产。


例2,图像异步生产

import java.net.URL;
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;

public class ImageTestAppletSimple2 extends Applet{
    
private Image im;
    
    
public void init(){
        im 
= getImage(getCodeBase(),"flower.jpg");
    }

    
    
public void paint(Graphics g){
        System.out.println(
"drawing image...");
        System.out.println(g.drawImage(im,
0,0,this));
    }

}

输出结果:
drawing image...
false
drawing image...
false
drawing image...
false
drawing image...
true

输出结果说明组件作为 ImageObserver ,监视 ImageProducer 异步生产图像,一旦有新的图像位被生产时就重绘图像,图像完全加载后 drawImage() 方法返回 true。


例3,重载 ImageObserver 的 imageUpdate() 方法,在图像完全加载前不调用 repaint()

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;

public class ImageTestAppletWithUpdate extends Applet{
    
private Image im;
    
    
public void init(){
        im 
= getImage(getCodeBase(),"flower.jpg");
        
        System.out.print(
"Image width = " + im.getWidth(this));
        System.out.println(
"hight = " + im.getHeight(this));
    }

    
    
public void paint(Graphics g){
        g.drawImage(im,
0,0,this);
    }

    
    
public boolean imageUpdate(Image image,int flags,int x,int y,int w,int h){
        System.out.println(
"imageUpdate():x=" + x + ",y=" + y + ",w=" + w + ",h=" + h);
        
        
if((flags & ALLBITS) == 0)
            
return true;
        
else
        
{
            repaint();
            
return false;
        }

    }

}



例4,重载  Component.update() 方法,被调用时不清除背景图像,直接调用 paint() 方法绘制图像,消除闪烁

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;

public class ImageTestAppletWithSmoothDynamicUpdate extends Applet{
    
private Image im;
    
    
public void init(){
        im 
= getImage(getCodeBase(),"hl.jpg");
        
        System.out.print(
"Image width = " + im.getWidth(this));
        System.out.println(
"hight = " + im.getHeight(this));
    }

    
    
public void paint(Graphics g){
        g.drawImage(im,
0,0,this);
    }

    
    
public boolean imageUpdate(Image image,int flags,int x,int y,int w,int h){
        System.out.println(
"imageUpdate():x=" + x + ",y=" + y + ",w=" + w + ",h=" + h);
        
        repaint();
        
        
if((flags & ALLBITS) == 0)
            
return true;
        
else
            
return false;
    }

    
    
public void update(Graphics g){
        paint(g);
    }

}

 

posted @ 2005-10-11 10:35 leon 阅读(2612) | 评论 (3)编辑 收藏

[Download] Java 2D API 程序员指南

Programmer's Guide to the JavaTM 2D API 中文版

http://www.blogjava.net/Files/leon/Java2DAPI程序员指南.rar

posted @ 2005-09-13 17:09 leon 阅读(2276) | 评论 (5)编辑 收藏

导航

统计

公告

DSC_0106.jpg
本博客已经搬家到CSDN
http://blog.csdn.net/chenweionline




常用链接

留言簿(5)

随笔分类

随笔档案

About Technology

My Favorite Website

搜索

积分与排名

最新评论

  • 1. re: 胃痉挛
  • 兄弟们你们都做胃镜了吗开的啥药?有什么养胃秘方啊?请赐教啊!
  • --我也进来了
  • 2. re: 胃痉挛
  • @痛啊
    我感觉比生孩子还疼,生孩子还能有意识呢!这种疼还叫不出来连说话的力气都没了
  • --我也进来了
  • 3. re: 胃痉挛
  • 评论内容较长,点击标题查看
  • --我也进来了
  • 4. re: 胃痉挛
  • 我都周期性的发作,算来有4年了 。每年最少一次,一次最少2天。吃了好多药就差没去做胃镜了。 刚刚发作就随便煮了点姜汤喝下就好了些,不知道还会不会发作了。
  • --许家洛
  • 5. re: 胃痉挛
  • 我昨晚也疼的要死。。上次疼的直接120送医院了,一上120我竟然就不疼了,医院里掉了瓶盐水就放回家了。这次正好国外旅游中,几乎疼了一整晚,整个在床上翻滚状态了。今天不疼了,就是整个人难受。。。求助阿
  • --胃疼
  • 6. re: [Swing]在 JFileChooser 中进行文件验证的小技巧
  • 输入*还是会有问题
  • --ngh
  • 7. re: 胃痉挛[未登录]
  • 昨晚一夜的身不如死的感觉,胃痉挛兄不要来了吧 ,求你了
  • --李飞
  • 8. re: 胃痉挛
  • 评论内容较长,点击标题查看
  • --daidai
  • 9. re: 胃痉挛
  • 评论内容较长,点击标题查看
  • --痛啊
  • 10. re: 胃痉挛
  • 妈啊 痛的快死了~!第一次感觉过这样的痛啊~!和女的生孩子有的一比了吧~!哭哭哭~!
  • --痛啊

阅读排行榜