2005年05月10日

WOW也就是魔兽世界啦,今天终于从好友老麦那搞到一个帐号,进去体验了一把。



刚进去就吃了个闭门羹,好游戏就是火,我等

此主题相关图片





终于踏入了WOW的处女脚,我靠,我来了WOW

此主题相关图片





赶快拍照留念,清风到此一游

此主题相关图片





突然!最烦你们丫这些打劫的了,一点技术含量都没有

此主题相关图片





打不起我还躲不起吗我!

此主题相关图片





:)总体来说游戏还是不错的,简单易上手,但似乎也没玩出什么新意?也许是刚刚开始玩吧,还有谁在玩WOW?

失望呀失望,今天一天都没能正常打开,今天先转移一部分,明天继续转移。

我把程序分为两种,有趣的和无趣的,最近做了几个有趣的项目,其中一个,应当就算是摄像头拍照程序了:),用于现场拍照,生成照片,主要用到Java Media Framework(JMF)

首先到SUN下载最新的JMF,然后安装。http://java.sun.com/products/java-media/jmf/index.jsp

然后,说一下需求

1.  用摄像头拍照

2.  在文本框输入文件名

3.  按下拍照按钮,获取摄像头内的图像

4.  在拍下的照片上有一红框截取固定大小的照片。

5.  保存为本地图像为jpg格式,不得压缩画质

 

技术关键,相信也是大家最感兴趣的部分也就是如何让一个摄像头工作,并拍下一张照片了。

利用JMF,代码很简单:

//利用这三个类分别获取摄像头驱动,和获取摄像头内的图像流,获取到的图像流是一个SwingComponent组件类

public static Player player = null;

private CaptureDeviceInfo di = null;

private MediaLocator ml = null;

 

//文档中提供的驱动写法,为何这么写我也不知:)

String str1 = "vfw:Logitech USB Video Camera:0";

        String str2 = "vfw:Microsoft WDM Image Capture (Win32):0";

        di = CaptureDeviceManager.getDevice(str2);

        ml = di.getLocator();

        try

        {

            player = Manager.createRealizedPlayer(ml);

            player.start();

            Component comp;

            if ((comp = player.getVisualComponent()) != null)

            {

                add(comp, BorderLayout.NORTH);

            }

}

        catch (Exception e)

        {

            e.printStackTrace();

        }

 


接下来就是点击拍照,获取摄像头内的当前图像。

代码也是很简单:

private JButton capture;

private Buffer buf = null;

private BufferToImage btoi = null;

private ImagePanel imgpanel = null;

private Image img = null;

private ImagePanel imgpanel = null;

 

JComponent c = (JComponent) e.getSource();

        if (c == capture)//如果按下的是拍照按钮

        {

            FrameGrabbingControl fgc =

                (FrameGrabbingControl) player.getControl(

                    "javax.media.control.FrameGrabbingControl");

            buf = fgc.grabFrame(); // 获取当前祯并存入Buffer

            btoi = new BufferToImage((VideoFormat) buf.getFormat());

            img = btoi.createImage(buf); // show the image    

            imgpanel.setImage(img);

        }

 

保存图像的就不多说了,以下为示例代码

BufferedImage bi = (BufferedImage) createImage(imgWidth, imgHeight);

        Graphics2D g2 = bi.createGraphics();

        g2.drawImage(img, null, null);

 

FileOutputStream out = null;

        try

        {

            out = new FileOutputStream(s);

        }

        catch (java.io.FileNotFoundException io)

        {

            System.out.println("File Not Found");

        }

        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);

        JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi);

        param.setQuality(1f, false);//不压缩图像

        encoder.setJPEGEncodeParam(param);

        try

        {

            encoder.encode(bi);

            out.close();

        }

        catch (java.io.IOException io)

        {

            System.out.println("IOException");

        }

 

已经申请将JWebCam建立为一个开源项目,放到GRO,大家发挥自己的想象力加入自己的代码吧,比如拍摄视频,添加图像处理功能,等等。如果有改的很Cool的,记得发给我看看:)

用Javascript实现Agent(实现右键菜单)

既然是显示右键菜单,那么我们就要截获对精灵按右键时的事件oncontextmenu

然后将右键菜单的html封装到一个函数,一上来这个菜单层是隐藏的

function getMenuHtml()
{
 var menuHtml ="<div id=menu style=\"text-align: left;position: absolute; visibility: hidden; width: 85px; z-index: 200;padding:1px\">";
 menuHtml += "<table border=1 width=100 height=100>";
 menuHtml += "<tr>";
 menuHtml += "<td>";
 menuHtml += "Menu1";
 menuHtml += "</td>";
 menuHtml += "</tr>";
 menuHtml += "</table>";
 menuHtml += "</div>";
 return menuHtml;

实现右键菜单,我们需要精灵截获oncontextmenu事件,需要对昨天的run函数进行一点小的修改

Agent.prototype.run=function()
{
 var agentHtml = "";
 agentHtml += "<img src="+this.imgAgent;
 agentHtml += " id=\"agent1\"";
 agentHtml += " style=\"position:absolute;left:"+this.agentLeft+";top:"+this.agentTop+";cursor:move\"";
 agentHtml += " onselectstart=\"return false\"";
 agentHtml += " onmousedown=\"mousedown(this)\"";
 agentHtml += " onmouseup=\"mouseup()\"";
 agentHtml += " onmousemove=\"mousemove()\"";
 agentHtml += " oncontextmenu=\"return showRightMenu()\"";
 agentHtml += ">";
 agentHtml += getMenuHtml();
 return document.write(agentHtml);
}

可以看出oncontextmenu调用的是showRightMenu函数,这个函数使菜单层可见,并且显示位置随着鼠标的位置而显示

注解:

scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离
scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离
event.clientX:鼠标点击的x轴位置
event.clientY:鼠标点击的y轴位置

/*
* 右键菜单 v1.0
* author: 清风
*/
function showRightMenu()
{
 menu.style.left=document.body.scrollLeft+event.clientX
 menu.style.top=document.body.scrollTop+event.clientY
 menu.style.visibility="visible";
 return false;
}

菜单现在可以显示了,如何使其消失呢?应当是用户点击任意位置就可消失

document.onclick=click
function click()
{
 menu.style.visibility="hidden";
}

今天的效果如下:



明天美化一下菜单,实现动态添加菜单内容

一直觉得Agent是用来做网站导航和帮助的不错选择,可惜MS Agent只有IE支持,而且好像加载速度不是很快,分析了一下觉得用
Javascript绝对可以做到,以前对Javascript都是抄来抄去,趁此机会也彻底学一学。OK,Let’s Begin

Javascript既然是基于对象的语言,那么大体上我们也可以按照OO的思路来设计自己的Agent

我们希望客户端简单调用一下就OK了,应当是如下的形式。

<script src="agent.js"></script>

<script language="JavaScript">
<!–
var agent = new Agent();
agent.run();
//–>
</script>

那么首先我们就来创建一个agent.js,js创建一个对象很简单只需要提供一个构造函数就OK了

function Agent()
{
 this.imgAgent = "images/agent.gif";
}

那么,接下来的任务就是让这个对象拥有一个run方法,这个方法应当仅仅就是输出最后拼凑好的html,我们先简单实现一下。

Agent.prototype.run=function()
{
 var agentHtml = "<img src="+this.imgAgent;
 agentHtml += " id=\"agent1\"";
 agentHtml += " style=\"position:absolute;left:50;top:50;cursor:move\"";
 agentHtml += " onselectstart=\"return false\"";
 agentHtml += " onmousedown=\"mousedown(this)\"";
 agentHtml += " onmouseup=\"mouseup()\"";
 agentHtml += " onmousemove=\"mousemove()\"";
 agentHtml += ">";
 return document.write(agentHtml);
}

从上面代码可以看出,我们实现的第一个精灵效果就是可以拖动精灵到界面任意一个地方,只需实现一下onmousedown,onmousemove,onmousemove三个事件即可

var currentMoveObj = null;        //当前拖动对象

this.setImage=function(img)
{
 imgAgent = img;
}
function dblclick(obj)
{
 obj.src= "images/chaosai.gif";
}
function mousedown(obj)
{
 currentMoveObj = obj;               //当对象被按下时,记录该对象
 //查了一下资料setCapture的意思是:
 //捕捉触发事件时的焦点对象并使鼠标焦点始终绑定该对象。
 //很关键不然灵敏度会很低
 currentMoveObj.setCapture()
 relLeft = event.x - currentMoveObj.style.pixelLeft;
 relTop = event.y - currentMoveObj.style.pixelTop;
}
function mouseup()
{
 if(currentMoveObj!=null)
 {
  currentMoveObj.releaseCapture();
  currentMoveObj=null;
 }
}
function mousemove()
{
 if(currentMoveObj != null)
 {
  currentMoveObj.style.pixelLeft=event.x-relLeft;
  currentMoveObj.style.pixelTop=event.y-relTop;
 }
}

主要是为了尝试一下JAVACC,利用编译原理的思路构造自己的语言:)

首先到https://javacc.dev.java.net/ JAVACC的老家下载JAVACC

我们今天的目标就是把from Teacher转化为select * from Teacher

首先编写.jj文件

1.定义要空开的分隔符

SKIP :
{
  " "
| "\t"
| "\n"
| "\r"
| "\f"
}

2.定义关键字。from 为HQL的关键字,Teacher是用户输入的类名,应当是一个任意由字母和数字组成的单词,我们可以用正则表达式:["A"-"Z","a"-"z","0"-"9"]来表示。

TOKEN: /*RESERVED TOKENS FOR UQL */
{
    <FROM:"from">
   | <FROM_OBJECT:(["A"-"Z","a"-"z","0"-"9"])+ >
}

 

3.接下来定义一下输入的顺序与规范

void expression() :
{
 Token tTable;
}
{
 (
  <FROM>
  tTable = <FROM_OBJECT>
 )
 {
  sqlSB.append("SELECT *");
  sqlSB.append(" FROM ").append(tTable.image);
 }
}

 

最后就是写解析代码,以便生成java代码

PARSER_BEGIN(HQLParser)

import java.lang.StringBuffer;
import java.io.StringReader;
import java.io.Reader;

public class HQLParser {

    private static StringBuffer sqlSB;

/**  
  A String based constructor for ease of use.
  **/
    public HQLParser(String s) 
    {
        this((Reader)(new StringReader(s)));
 sqlSB = new StringBuffer();
    }

    public String getSQL()
    {
        return sqlSB.toString();
    }
       
    public static void main(String args[])
    {
        try
        {
              String query = args[0];
              HQLParser parser = new HQLParser(query);
       parser.parse();
              System.out.println("SQL:"+parser.getSQL());
        }
        catch(Exception e)
        {
              e.printStackTrace();
        }
    }

    public void parse()
    {
 try
 {
     expression();
 }
 catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}
PARSER_END(HQLParser)

接下来到dos下输入:

javacc -debug_parser test.jj

-debug_parser:用来输出语法树

这时候会生成7个java文件,每个文件的作用以后会详细说明

这时候只需要

javac *.java即可编译全部的java文件

然后执行java HQLParser “from Teacher“

这时候屏幕上就会显示出“select * from Teacher“

xDoclet是一种通过读取JAVA源文件中的特定标签,然后生成指定文件的工具。xDoclet标签本身已经提供了一些常用的标签,例如@ejb,@hibernate,@web等等,但是仍然不能满足我们的需求。
例如我们最新的项目中引用了一个Javascript验证框架,通过配置特定的xml配置文件,即可完成客户端表单验证,但是不想开发人员再去学习一套框架,于是想让开发人员在源代码中写@javascript这样的标签,然后生成其配置文件。
Javascript客户端验证一直是web开发中一个比较头疼的问题,经常是每一个页面中充斥着许多类似甚至相同的验证代码,如何统一有效的管理这些代码,以及如何做到代码页面的分离一直没有太好的解决方法。

运用这个验证框架那么客户端开发就变成了配置validation-config.xml这个文件如此轻松了,本文并不打算详细讲述如何使用JSValidation框架,有兴趣的朋友可以去http://www.cosoft.org.cn/projects/jsvalidation JSValidation的官方网站自己去学习。

虽然运用这框架已经可以很好的完成客户端验证代码的编写,并且提供了dtd文件进行xml文件的,但是手动编写xml文件还是很容易出错,效率比较低,而且新的开发人员还要掌握一个全新的框架,不宜于开发人员入门。
像Struts
或JSF这样的框架大都需要为表单写一个类似FormBean的东西,以JSF为例,假如表单内有一文本框<input type=”text”
 name=”txtUsername” />,那么对应的Page类或叫FormBean类就应有如下代码:
private HtmlInputText txtUsername = new HtmlInputText();
/**
* @return 用户名
*/
public HtmlInputText getTxtUsername ()
{
    return txtUsername;
}
/**
 * @param text
 */
public void setTxtTeaName(HtmlInputText text)
{
    txtTeaName = text;
}
如果可以利用xDoclet,那么,就可以自动生成JSValidation的配置文件了,而且还利于培训新的开发人员,再加入ant task还可以形成每日构建。想象的代码应该是下面这个样子:
/**
 * @javascript.field
 * name="frmZBAddGlobalPage:txtTeaName"
 * display-name="用户名"
 * 
 * @javascript.depend
 * name="required"
 *
 * @return用户名
 */
 public HtmlInputText getTxtUsername()
 {
     return txtUsername;
 }
通过分析xDoclet自带的一些标签包,发现只需要提供三个文件即可实现自定义xDoclet标签:一个继承于XmlSubTask的类,一个继承于DocletTask的类(用于ant),一个xdt的模板语言文件即可。

在XmlSubTask类中,首先,定义模板文件名:
private static String DEFAULT_TEMPLATE_FILE =
        "resources/validation-config.xdt";
定义dtd文件名:
private final static String DTD_FILE_NAME_20 =
        "resources/validation-config.dtd";
定义要生成的配置文件名:
private static String GENERATED_FILE_NAME = "validation-config.xml";

然后只需将三个文件组合起来既可,详细代码如下:
public JavascriptSubTask()
    {
        setTemplateURL(getClass().getResource(DEFAULT_TEMPLATE_FILE));
        setDestinationFile(GENERATED_FILE_NAME);
    }

    public void execute() throws XDocletException
    {
        setDtdURL(getClass().getResource(DTD_FILE_NAME_20));
        startProcess();
    }

    protected void engineStarted() throws XDocletException
    {
        System.out.println(
            Translator.getString(
                XDocletMessages.class,
                XDocletMessages.GENERATING_SOMETHING,
                new String[] { getDestinationFile()}));
    }
要想ant可以使用,只需要以下简单的代码:
/*
 * 创建日期 2004-4-26
 */
package paradise.xdoclet.modules.javascript;

import xdoclet.DocletTask;

/**
 * @author 清风
 */
public class JavascriptDocletTask extends DocletTask
{
    public JavascriptDocletTask()
    {
        addSubTask(new JavascriptSubTask());
    }
}
在ant中按如下方式定义:
<target name="javascript" depends="jxdoc_init" description="Generate javascript validation-config">
        <javascriptdoclet destdir="${jsp}/javascript">
            <fileset dir="${src}">
                <include name="**/zaibian/*.java"/>
            </fileset>
        </javascriptdoclet>
</target>

接下来,也是最核心的部分,就是有关xdt模板语言,xdt文件可以说是自定义xDoclet标签的最重要的文件之一,以JavaScriptxDoclet为例,简单介绍一下xdt模板语言:
<XDtClass:forAllClasses>    遍历所有含有标签的类(在ant中指定)
<XDtMethod:forAllMethods>    遍历当前类的所有方法
<XDtMethod:ifHasMethodTag tagName="javascript.form">    如果遍历到的方法中含有指定的标签
<XDtMethod:forAllMethodTags tagName="javascript.depend">    遍历当前方法的所有标签
更多的模板语言,参考xDoclet的.XDT文档,都是很好理解的模板语言。

接下来,开始自定义自己的标签,新建一个xtags.xml文件,加上开头
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE xdoclet PUBLIC "-//XDoclet Team//DTD XDoclet Tags 1.1//EN" "http://xdoclet.sourceforge.net/dtds/xtags_1_1.dtd">
然后写下所有自定义的标签,例如:
<xdoclet>
    <namespace>
        <name>javascript</name>
        <tags>
            <tag>
                <level>method</level>
                <name>javascript.form</name>
                <usage-description>Form</usage-description>
                <condition type="method"/>
                <parameter type="text">
                    <name>id</name>
                    <usage-description>Form id</usage-description>
                    <mandatory>true</mandatory>
                </parameter>
                <parameter type="text">
                    <name>show-error</name>
                    <usage-description>Form Error Display</usage-description>
                    <mandatory>true</mandatory>
                </parameter>
                <parameter type="text">
                    <name>onfail</name>
                    <usage-description>Form Error Run Custom Javascript Function</usage-description>
                    <mandatory>false</mandatory>
                </parameter>
            </tag>
        </tags>
    </namespace>
</xdoclet>
注意几个地方:
“<level> method </level>”代表该标签出现在方法上而不是类之上。例如
/**
*@javascript.form
*name=”test”
*/
public String getXXX()
{
}


最后就是将这些文件打成jar,其放置目录分别是:
根目录
|
|–META-INF/xtags.xml
|
|–源代码
|—-|
|—-|–resources/*.xdt,*.dtd

一直在讲xp!xp!极端编程,但如何能更好的运用发挥极端编程的威力是我比较头疼的事情,如何能够使一个项目组的所有人员更好的参与到项目中来是很项目成败的很关键的问题。

我指的项目组成员包括:

1.客户

2.项目经理

3.开发设计人员

4.测试人员

5.界面设计人员

每个部分的人对项目关心的部分和关心的角度是不同的

例如:客户关心最终的产品是否好用

项目经理关心开发进度

开发人员关心知识的积累和从中获得的成就感

测试人员关心在哪里可以展开自己的测试,可以获得最新的源程序

等等

如何能够通过一个平台展现这多个方面,并且紧紧跟随极端编程的先进思想:)是个很重要的问题。

这次在项目中采用xplanner是一个开始,在此基础上我们可能要组合出一套自己的项目管理平台。

CSDN的Blog实在是太不稳定了,打算把Blog换到这里,希望是一个稳定的空间。第一步先把以前的文章都转移过来