loading ...

Q网志

my web and me.
来源:兽族的荣耀

在侃侃而谈OO,侃侃而谈设计模式,侃侃而谈面向对象的诸多原则之前,我们首先应该掌握一点:封装。掌握好封装的原则和技巧之后,就算使用的不是OO语言,也能构造出框架优美的程序。将这些原则用在程序之外,也能得到出奇的效果。《设计规则-模块化的力量》将封装与模块化放在神坛的高位,它们配得上这个位置。这是我们解决复杂性问题的最基本的方法(没有之一)。

程序是一种复杂性系统。“道生一,一生二,二生三,三生(四,四生…)万物”。若将复杂性的根源当作“道”的化,那么这个“一”必然是封装。不同的程序语言以及由这些程序语言衍生的方法,则处于“二”的地位,比如 OO 设计范式、FP(函数编程)范式、分层的原则等等。OO设计准则,什么里氏替换原则,什么组合优先于继承,这些处于“三”的地位,具体的设计模式什么之类的处于“三”之后“四”的地位。

本人愚笨,至今尚记不清那些原则,如里氏替换原则是什么,那些这个模式那个模式怎么实现。设计模式中,俺只对策略模式感兴趣,对其它模式兴趣索然。实质上这些模式也好、准则也好,只是给我们提供了一种方法、一种工具去更好的实现封装。

复制和粘帖是封装的大敌,是丑陋代码的最大的坏味道。复制一份,就相当于增加了至少一个可变点,复制两份就相当于增加了至少两个可变点。为什么说“ 至少”呢,因为模块之间存在关联关系,导致一个地方的变化会导致其它的多个地方也必须随之变化。如果假定S为系统本身,M为对系统本身的一个测量,C为系统S中模块的平均复制份数(C>1),则这个M与C的关系应该是一个指数的关系: M正比于C的N次方(N>1)。

指数关系已经很可怕了,更可怕的是,当系统中的模块出现变化时,如果该模块在系统中有多个副本,我们可能偷懒,只改变了其中的一个副本,而不是全部副本都进行修改,这样就导致模块的分裂,由一个模块分裂成几个类似而又不同的模块,大大的增加系统的复杂度,最终导致系统的腐烂。直觉上,一个设计很烂的系统,它的复杂度大致是模块数量的阶乘关系甚至是幂指关系,这是比指数关系更恐怖的关系。

所以,复制和粘帖是一种非常邪恶的编码方式。在编码时,需要千方百计的去想办法减少复制和粘帖。这是在编码时就应该注意的问题,而不是放在重构阶段去做的事情。至于使用什么方法,使用什么手段,使用什么模式则是细节问题。

坚持不复制和粘帖,坚持下来,收益会非常大,写出来的代码质量高、含金量高。看见别人的系统,能马上分辨出这个系统的优点是什么,缺点是什么。什么设计模式也好,接口的正交性也好,设计原则也好,也许你从没刻意的去学过,却最终发现殊途同归,冥冥之中与国外大牛有一种心意相通的感觉。会自发的去组合、去改良这些大牛们的思想和方法,甚至去创造新方法新手段。直接由一入手,一生二,二生三生四,而非教条的、顶礼膜拜的去学这个三,学这个四。或许那个时候,你已经忘记什么是对象了。

之所以发这些牢骚,是因为昨天至今天,正在重构一个模块。这个模块M1的核心部件是一个包装自RTF的layout规则编辑器。设计这个核心部件的哥们以RichTextBox为中心设计了一个控件A,然后将这个控件的部分规则逻辑抽出来放在类B和类C的静态方法之中,更神奇的是这个类B是在另一个模块M2之中,类C倒是在模块M1之中。这个控件在M1中被三个地方给用到:D、E、F,这D、E、F每个地方都要为这个空间A注册七八个事件,然后在事件的回调函数中调用模块M2中的类B的静态方法及模块M1中的类C的静态方法去实现一些逻辑。现在呢,我要写一个控件G,这个G也要用到控件A,在这种情况下,我必需为G注册一堆A的事件及回调函数,然后在回调函数中弄一堆逻辑,至少得200行代码。为了写这些回调函数,我必须得搞清这个A控件及类B,类 C的内部运行机制。也就是说,为了吃猪肉必须得亲自去杀猪。当然,也可以从D、E或F 中Copy代码过来改吧改吧来节省时间。

问题严重的地方在于,这个控件A本身存在逻辑错误,存在功能不完善的地方,需要对它动手术。因为到处复制,牵一发而动全身,给A动手术必须也要给 B、C、D、E、F五个类动手术。在给A动手术时,为了编译通过,我将B、C、D、E、F中与A相关的代码全给注释掉了,前后注释了1500行代码左右。实质上这1500行代码真正有价值的代码也就在200行左右,其它的代码全是复制、粘帖,然后改改变量名完成的。

为什么会出现这样的问题呢?因为复制和粘帖。复制和粘帖省事啊,Copy过去改几个词就能用了,不用花费心思的去想封装。而实际情况是,要引用那个控件A,得写200-300行代码,多引用几处,就得写1000多行代码,复制和粘帖的话倒不费事,但如果发现这个A存在错误,或者需要扩展,在改A的同时,同时也要动这1000多行代码,这1000多行代码中可能会牵扯到更多的代码,最终导致必须修改更多的代码,这便是代码的腐烂。

其实这个A是很好封装的,它不需要其它的类对它输入任何输入数据,其它的类只需要从A控件中获得一个最终的规则结果,一个List。封装的好的话,调用A,获得结果,两三句代码就可以实现。

之所以不封装是因为习惯了复制和粘帖,或者懒于去封装,或者头脑中根本没封装这根弦。

很多新程序员或者不新的程序员,尤其是Web开发程序员老抱怨工作的技术含量低,老是想学更多的东西。实质上,他们所作的工作是非常有技术含量的东西,就看怎么看待。

如果只将自己的工作看作简单的复制、粘帖、抄袭、改代码的话,自然技术含量低了。如果将自己的工作看作如何消除复制和粘帖、如何提高质量、进度,消除工作中的不必要事情,消除各种浪费,那么这个工作的技术含量是极其高的。不要膜拜大师,当你这么做的时候,你做的正是大师的工作。不要膜拜新技术,当你这么做的时候,你的工作可能正是新新一代技术的萌芽。一点一滴、一色一香,全在心中。青青翠竹、尽是法身,郁郁黄花、无非般若。

...... [阅读全文]

来源:JavaEye
相关演示下载
原本以为google首页的动画是动画图片,后来发现是用js写的。
好奇,就仿着google首页的动画用jquery试着写了个。

难点就在切图和定位上。

下面讲一下这两个难点。

切图 :

a :

这里我拉了些参考线,便于看得更清楚些。每个方框里的宽度高度都相同。然后用setTimeout延时,间隔相等的时间去改变背景图片的位置,连贯起来看起来就像是个小flash动画

for(var i=0; i<5; i++){
setTimeout("navScrollBg(" + i + "," + index +","+flag+")",40 * i);
}

这里的i<5是看这个动画有几步,如上图是5步。

b :mourseover和mourseout的动画顺序刚好相反,利用数组排序

var a=[0,52,104,156,208];
var spans = $("#info_" + index).find("span");
if(flag == 0){
spans.css("background-position",(0 - a[i]) + "px" + " " + (0-((index-1)*37)) +"px");
}
else{
a.sort(function(b,c){return c-b;});
spans.css("background-position",(0 - a[i]) + "px" + " " + (0-((index-1)*37)) +"px");
}

当flag=0,var a=[0,52,104,156,208];
当flag=1,var a=[208,156,104,52,0];

定位 :

对于(上图)icon上方的文字描述的圆角背景框

1.如果圆角框做成背景图就没什么难的

2.如果用css写个圆角框,还是个比较新鲜的尝试(平时做圆角框都是切图的,因为切图简单些)。

google首页的圆角框是用css写的,为了练一下技术,我也用css尝试了下,无非就是要多加几个标签。如下:

<style type="text/css">
div.text{text-align:center;position:absolute;left:0;top:0;cursor:pointer;display:none;}
div.text div.border{white-space:nowrap;padding:2px;line-height:14px;display:block;_padding-top:4px;}
div.text div.leftright{height:1px;overflow:hidden;clear:both;}
div.text div.leftright .left{width:1px;height:1px;float:left;}
div.text div.leftright .right{width:1px;height:1px;float:right;}
div.text div.topline{margin:0 1px;height:1px;overflow:hidden;}
div.text div.arrow{background:url(images/google_icons.jpg) no-repeat -260px 0;width:8px;height:4px;margin:0 auto;position:relative;top:-1px;overflow:hidden;}

div.text1 div.border{border-left:1px solid #54a70d;border-right:1px solid #54a70d;}
div.text1 div.leftright .left{background-color:#54a70d;}
div.text1 div.leftright .right{background-color:#54a70d;}
div.text1 div.topline{background-color:#54a70d;}
div.text1 div.arrow{background-position:-260px 0;}
</style>
<div class="text text1">
<div class="topline"></div>
<div class="leftright">
<div class="left"></div>
<div class="right"></div>
</div>
<div class="border">
<span>搜索热门网络视频</span>
</div>
<div class="leftright">
<div class="left"></div>
<div class="right"></div>
</div>
<div class="topline"></div>
<div class="arrow"></div>
</div>

这里我提了个text公用样式出来了,text1,text2....只是加了不同的颜色,代码上精减了不少。

对于icon上方的文字描述的定位,我必须始终让它的中心和icon的中心在一条垂直直线上。

a 那么首先我要对包文字描述的div(以下简称div)绝对定位。

b 然后取到div内包文字描述的span的宽度,加上左右的padding值(例子中取的值是10px),赋给div的宽度(以下简称textWidth)。

这样不管我文字描述有多长,div的宽度都会动态的获取

var textWidth = $("div.text"+index).show().find("span").width() + 14;
$("div.text"+index).width(textWidth);

c 最后用getBoundingClientRect()取到包icon和标签的a(以下简称a)在浏览器中距左上角的left(以下简称elementLeft)和top(以下简称elementTop)值;
div绝对定位的top值:elementTop-适当值; left值:elementLeft+icon宽度-div的宽度/2


var elementLeft = $("li#info_" +index +" a").get(0).getBoundingClientRect().left;
var elementTop = $("li#info_" +index +" a").get(0).getBoundingClientRect().top;
var textLeft = elementLeft + 24 - parseInt(textWidth) / 2;
var textTop = elementTop - 32;
$("div.text"+index).css({"left":textLeft+"px","top":textTop+"px"});

...... [阅读全文]

来源:Linux宝库

  CVS 是RCS的前端工具,它是用于多用户并行开发的版本控制工具,它的最大特点是使用了"copy-modify-merge"机制而不是"lock- modify-unlock"。通过使用CVS生成一个存储文件的仓库(repository),存储在仓库中的每个目录叫做模块(module),在修改时将相应的模块检出到工作目录中(working directory)生成对应的目录,所有的修改都在工作目录中完成,修改完成后再提交到仓库中生成新的版本号,并加以保存。

  1. CVS初始化

  (1) 创建CVSROOT根目录

  编辑有关的环境变量,加入CVSROOT的定义(比如在 /etc/bashrc 文件中加入下面两行):
  CVSROOT=/usr/local/cvsroot
  export CVSROOT

  然后在相应位置开始创建CVSROOT
  $cd /usr/local/
  $mkdir cvsroot
  $cvs –d /usr/local/cvsroot init

  这时就会产生/usr/local/cvsroot/CVSROOT 目录,这下面放着有关CVS的配置文件。同时/usr/local/cvsroot/也作为文件仓库存放所有的文件。

  (2) 创建开发项目

  如果从头开始一个新的项目,就需要创建一个单独的目录,并把所有要使用的文件做一个有效的组织。而如果在开始使用源文件的目录之前就有了,则只需进入该目录就行了。
  $cd /work/tang
  $ls cvstest
  . .. c/
  $cd cvstest

  然后,就可以输入源文件目录:
  $cvs import –m "Create Source Dir" cvstest/c tang cvstest

  这样会生成 $CVSROOT/cvstest/c 目录。 其中 -m 用来指定注释信息,如果后面在命令行不指定注释信息,则会启动缺省编辑器(vi)要求输入注释信息。 tang, cvstest分别标识了厂商和发行标识。

  注意,使用import命令会把当前目录下的所有文件和目录(包括子目录)引入到文件仓库中指定模块(目录)下。

  2. 命令简介

  (1) 检出源文件
  
cvs checkout [-r rev][-D date][-d dir][-j merg1] [-j merg2] modules

  -r 检出指定版本的模块
  -D 检出指定日期的模块
  -d 检出指定目录而不是模块
  -j 合并当前版本和指定版本

  使用下面的命令会检出刚才生成的模块,并在当前目录下生成与文件仓库中完全一样的目录结构:
  
$cvs checkout cvstest/c

  对于目录结构比较复杂的模块可以在 $CVSROOT/CVSROOT/modules中加以指定:

  1) $cvs checkout CVSROOT/modules
  2) 在modules文件中加入下面一行:
  
SOURCE cvstest/c

  3) 然后执行:
  
$cvs commit –m "Add SOURCE"

  以后就可以使用下面的命令在当前路径下生成 cvstest/c 目录
  
$cvs checkout SOURCE

  在当前路径下生成的这个目录就被称为工作目录,对源文件的所有修改都应该在这个目录下完成,而绝对不允许去改动在 文件仓库中$CVSROOT 目录下的文件。

  (2) 删除、增加、重命名文件和目录

  
cvs add [-k kflags][-m message] files...

  -k 指定以后该文件的缺省检出目录
  -m 对文件的描述

  上述命令会加入一个新的文件到文件仓库里,但直到使用了提交命令它才会真正更新文件仓库。
  
cvs remove [options] files

  上述命令会从文件仓库中删除文件,但也要到提交之后才有作用。

  例1:增加文件
  $cvs checkout SOURCE
  $cd cvstest/c
  $touch test.c
  $cvs add test.c
  $cvs commit –m "add test.c"

  例2:删除文件
  $cvs checkout SOURCE
  $cd cvstest/c
  $rm test.c
  $cvs remove test.c

  使用 –f 选项能上面两步合做一步。
  
$cvs remove –f test.c

  如果在提交之前想恢复刚才删除的文件,可以如下:
  
$cvs add test.c

  如果只执行了第一步删除(rm),则可以用下面的方法恢复:
  
$cvs update test.c

  对于重命名的文件,可以先删除再添加。

  对于目录的修改(重命名),可能需要修改cvs 管理文件,一般应该遵循以下步骤:

  1) 确认所有有关的修改都已经提交;
  2) 进入文件仓库中要修改的模块目录,对相应的目录进行修改(重命名或删除)
  $cd $CVSROOT/modules
  $mv old_dir new_dir

  3) 如果有必要,修改管理文件,比如modules 文件

  如果要删除目录,则应该先对目录中每个文件都进行了删除(包括使用cvs remove )处理之后再执行上面的第2步。

  (3) 提交源文件
  
cvs commit [-Rl][-m mesg] files

  -R 连子目录一起提交
  -l 只提交本地目录(不提交子目录)
  -m 注释信息

  在检出源文件之后,在工作目录中对源文件进行的所有修改都必须在提交之后才能对文件仓库中的源文件起作用,并且新的文件才能够被分配一个新的版本号。

  (4) 释放工作目录
  
cvs release –d SOURCE

  这个命令会删除工作目录 cvstest/c (建议在提交了修改的模块后执行这一步), 它比使用 rm –rf cvstest 要好。

  3. 多用户开发

  在多用户的情况下,如果不同用户修改的是同一个文件的不同部分,则使用下面的命令就能进行版本合并(把检出的文件与当前的最新版本合并):
  
$cvs update

  (1) 冲突解决

  在有多个用户对同一个文件进行修改时,如果修改了其中的相同部分,而修改后的内容如果有不同的话,出现冲突是不可避免的。如果在CVS 文件仓库中有一个文件 test.c ,它的版本是 1.4, 用户A 先检出该文件进行修改,而稍后有用户B 检出该文件进行修改,并提前提交成 1.5, 而在用户A再提交时就会出现冲突(如果文件内容不同的话),这时CVS会提示需要手工解决。

  文件仓库中的版本1.4:

#include stdio.h
main()
{
int i;
for(i = 0; i < 100; i++)
printf("Count: %d", i);
}

  用户B 1.5:

#include stdio.h
main()
{
int i;
for(i = 0; i < 10; i++)
printf("Count: %d", i);
printf("Over");
}

  用户A :

#include stdio.h
main()
{
int i;
for(i = 0; i < 50; i++)
printf("Count: %d", i);
return;
}

  提交时会提示有冲突,需要手工编辑,这时运行了$cvs update 之后再编辑test.c, 会看到:

#include stdio.h
main()
{
int i;
  <<<<<<< test.c
  for(i = 0; i < 50; i++)
  =======
   for(i = 0; i < 10; i++)
   >>>>>>> 1.5
   printf("Count: %d", i);
   <<<<<<< test.c
   return;
  =======
  printf("Over");
  >>>>>>> 1.5
}

  (2) 文件版本管理

  
cvs log [-lR][-r rev][-d date][-w login][files…]

  -l 不处理子目录
  -R 对子目录做同样处理
  -r 指定版本号
  -d 指定时间
  -w 指定登录名

  使用上面的命令可以参看当前模块或指定文件的所有历史版本信息。
  
cvs annotate [-lR][-r rev|-D date] files

  -l 不处理子目录
  -R 对子目录做同样处理
  -r 指定版本号

  使用上面的命令可以参看指定文件(检出之后)的所有修改信息。

  例:
  
$cvs annotate cvstest/c/test.c

  输出:
  版本 修改人 修改时间 源代码

  1.1 (tang 18-Jan-00): #include stdio.h
  1.1 (tang 18-Jan-00): #include string.h
  1.1 (tang 18-Jan-00):
  1.1 (tang 18-Jan-00): main()
  1.1 (tang 18-Jan-00): {
  1.1 (tang 18-Jan-00): int i = 0 ;
  1.1 (tang 18-Jan-00):
  1.1 (tang 18-Jan-00): for(i = 0; i < 20; i++)
  1.1 (tang 18-Jan-00): printf("Count: %d", i);
  1.1 (tang 18-Jan-00):
  1.3 (tang 18-Jan-00): printf("222222");
  1.4 (tang 18-Jan-00): printf("333333");
  1.1 (tang 18-Jan-00): }

  使用下面的命令可以生成相对于一个指定主版本的分支版本:
  
cvs rtag –b –r rev_root rev_branch file_name

  -b 指定生成一个分支版本
  -r 指定该分支的主干节点版本号
  rev_root 主干版本号
  rev_branch 分支版本号
  file_name 指定文件,使用"."表示当前目录下所有文件

  使用上面的命令可以生成一个对应版本号的分支版本,由于CVS 版本号是用数字表示的,而且在同一个模块下不同文件的版本完全可能是不同的,所以使用标识会更方便。

  例:
  
$cvs rtag –b –r 1.2 tlb-1 SOURCE

  以后要访问该分支版本,可以使用"-r" 选项
  
$cvs checkout –r tlb-1 SOURCE

  从当前检出的版本切换到一个分支版本:
  
$cvs update –r tlb-1 SOURCE

  使用下面的命令可以看版本信息:
  
cvs status [–vlR] files

  -v 显示所有信息
  -l 不显示子目录信息
  -R 显示子目录信息

  
cvs update –j rev module

  把当前所做的修改与指定版本的文件进行合并。
  主干 1.1   1.2   1.3   1.4   1.5   1.6
  ↓
  分支tlb-1   1.2.2.1   1.2.2.2   1.2.2.3

  如果要合并分支tlb-1上的版本:
  
$cvs update –j 1.2.2.3 –j tlb-1 test.c

  其中1.2.2.3可以通过tag命令生成一个容易记忆的标识。

  如果要合并分支tlb-1到主干上1.2 :
  
$cvs update –j tlb-1 test.c

  如果要合并主干上的不同版本(注意顺序很重要,同时在指定版本之间的所有修改将被丢弃):
  
$cvs update –j 1.5 –j 1.2 test.c

  如果在不同版本之间模块的文件有增减,则可以:
  $cvs update –A
  $cvs updata –jbranch_name


  4. 在远程机器上使用CVS

  通过网络使用CVS 有很多种方式,但在这里只介绍比较简单的一种:通过rsh 执行cvs 命令。

  1) 在远程机器的.rhosts中加入对本地机的访问许可:
  
tom tang

  2) 使用下面的命令检出模块ESMSTRG
  
$cvs –d :ext:tang@esmpro:/work/cvsroot checkout SOURCE

  其中, ext 指明了连接方式为 rsh, tang 指明了本地用户, esmpro 指明了远地主机,/work/cvsroot 指明了在远地主机上的$CVSROOT路径,可以在本地设置CVS_SERVER环境变量指明这个目录。

...... [阅读全文]

来源:小橙子的第一播

該手機是LINUX平臺的手機,所以,對搞電腦的使用者來講,可以說是“透明”的。雖然,MOTO在製作該LINUX時作了許多的限制。可,一方面其配置文件我們是可以“隨意”改變的;另一方面,這些限制一般情況下難不住真正的高手。偶不是高手,只是手機玩家,這裏談自己的一點心得。

一、安裝普通的LINUX程序

這些程序一般是.mpkg的包,可以用 WinRAR 打開看到內容的。如 ivory.mpkg,雙擊、選擇用 WinRAR 打開後,會看一個 ivory 文件。選中文件,再點擊 WinRAR 工具欄的“查看”鈕,就看到該的真面目了,通常是一個目錄,本例子中看到就是 ivory 目錄。

偶比較喜歡自己手動安裝這樣的程序。

好,將 ivory 目錄帶子目錄一塊傳到手機卡的 /mmc/mmca1/.system/ 裏面。

再來修改 /mmc/mmca1/.system/java/PlugCardDB ,先將文件拷貝到電腦中,再用Notepad++/UltraEdit等工具編輯。再後面增加一項:
[AppLinkRecord100000002]
AllPosition = 101
BigIcon =bluetooth.png
Comment =
Directory = ../../../../mmc/mmca1/.system/QTDownLoad/ivory
Exec = ivory.sh
Group = 6
Icon =bluetooth.png
InstalledDate = 2006/5/1
JavaId = -1
MpkgFile =
Name = Ivory
OsVersion =
Position = 2
Rotation =
Shared = 0
Type = 4
uid = 100000002

其中,
Directory 是相對的路徑,相對介面調用者的路徑,這裏可以認為是“系統”調用。
Exec=ivory.sh 是啟動文件,目錄中有。就是說,mpkg 打包的時候,帶有的。
Group=6 是顯示在手機的控制面板的類別,1是辦公、2是娛樂……
Name=BlueZ 是面板中顯示的名稱,如果想使用中文,就要轉換成UTF-8編碼的。
Position=2 是在該組的位置
Type=4 表示是ezx程序“己安裝的QT程序”。

其它的,效仿就可以了。

好了,修改好了,再傳到手機中,覆蓋原文件。回到手機的控制面板,打開安裝時對應的類別,點擊“start”菜單,選擇“更改順序”,不做任何事情,確定即可。就看到顯示已經刷新了。本例中,就是看到一個藍牙的圖標和“Ivory”文字標簽。

呵呵,這樣類型的程序的安裝,大家應該已經不想看的了,介紹得不對的地方,請改正。
好,手機安裝 J2ME 的程序,就複雜多了。

二、手動安裝 J2ME 的程序

只要 .jar 文件就夠。本例用 gpslook 的 GPS 軟件,文件名是 GpsMaps.jar。
用 WinRAR 打開這個 .jar 文件,再打開裏面的 META-INF 目錄,用 Notepad++ / UltraEdit 打開裏面的 MANIFEST.MF 文件。

在 /diska/.system/java/JAMInfo/maxsuiteid 找到當前己安裝的 j2me 的最大序號,本例中是 00510。
修改 /diska/.system/java/JAMInfo/index,修改前先拷貝到電腦,增加一行:
00511||GpsMap||gpslook.net||1.5||/mmc/mmca1/.system/java/DownloadApps/MIDlet00511
再傳回來覆蓋原文件。

到 /mmc/mmca1/.system/java/DownloadApps/,創建 MIDlet00511 子目錄,進入該子目錄,再創建兩個子目錄 Files 和 rms。
注:如果電腦是中文的(含繁體、簡體),不要再資源管理器(檔案總管)中按右鍵那樣創建,用 telnet 進去再創建。

將 GpsMaps.jar 拷貝到 /mmc/mmca1/.system/java/DownloadApps/MIDlet00511/Files 中。也將前面解出來的文件 res\icon.png 拷貝到該目錄。

將 gpslook 提供的 permfile.txt 拷貝到 /mmc/mmca1/.system/java/DownloadApps/MIDlet00511

在電腦中,生成一個 registry.txt 文件,格式是“無BOM的UTF8”,內容是:
Jar-Path: /mmc/mmca1/.system/java/DownloadApps/MIDlet00511/Files/01_GpsMaps.jar
Jad-Path:
Perm-Path: /mmc/mmca1/.system/java/DownloadApps/MIDlet00511/permfile.txt
Suite-Icon: /mmc/mmca1/.system/java/DownloadApps/MIDlet00511/Files/icon.png
DRM-Mode: Forbidden
Is-Trusted: 1
Jar-URL:
Description:
Domain: manufacturer
Signer-Name:
Mot-JavaVM-Heapsize: 1091927588
Delete-Notify:
Num-MIDlets: 1
MIDlet-1: 乐图, /mmc/mmca1/.system/java/DownloadApps/MIDlet00511/Files/icon.png, engine.MainMidlet

再來修改 /mmc/mmca1/.system/java/PlugCardDB,一定要先拷貝到電腦!增加一項:
[AppLinkRecord1014]
AllPosition = 114
BigIcon = Files/icon.png
Directory = /mmc/mmca1/.system/java/DownloadApps/MIDlet00511
Exec =
Group = 5
Icon = Files/icon.png
InstalledDate =
JavaId = 00511
Mime =
MpkgFile =
Name = GpsLook
OsVersion =
Position = 1
Rotation =
Shared = 0
Size = 20K
Type = 3
uid = 1014

回到手機的控制面板,打開安裝時對應的類別,點擊“start”菜單,選擇“更改順序”,不做任何事情,確定即可。就看到顯示已經刷新了。本例中,就是看到一個綠葉的圖標和“GpsLook”文字標簽。

三、補充一個,如何用腳本啟動 j2me 程序

先 telnet 到手機,執行
/usr/SYSjava/kvm -launch 00511

或者,將腳本存成 .lin 文件,放到在手機我的文檔相關目錄,再通過“我的文檔”來執行該文件來 j2me 程序。

要注意的是,操作中,注意文件的格式,手機認識“無BOM的UTF8”格式,不要存成Unicode文件、帶BOM的UTF8文件。

...... [阅读全文]

来源:LinuxSir.Org

1.先在地址栏键入about:config
2.Set "network.http.pipelining" to "true"
3.Set "network.http.proxy.pipelining" to "true"
4.Set "network.http.pipelining.maxrequests" to 30
5.单击右键,选择新建->整数,命名为nglayout.initialpaint.delay,值为0

下面是我的一些实验:

以上的原理就是利用多个线程下载一个页面,30这个数字如果你的机器和网络够好的话,可以适当再加大些,不过不要超过64,如果打开页面很多,这个数字超过64以后硬盘会不停的响,估计对硬盘有点损坏。
还有就是about:config这个参数,不要擅自修改里面的其他参数(除非你的确知道你在干什么),否则Firefox就不能好好工作了。

...... [阅读全文]

作者:杭州思亿欧网络科技有限公司

W3C网页设计标准是一种技术也是一种思想。

现在基本上很多高端的客户都会要求按照W3C标准来设计网站。在今年和去年这两年时间里,国内很多的门户网站都已经按照W3C标准对网站整体进行代码重构。

用W3C标准来设计网站,有个好处:提高用户体验,加快网页下载速度。按照W3C标准设计的网站,用户浏览速度比较快,因为网站的代码比较简洁。

有一部分的朋友说,做好DIV+CSS,网站优化就等于做好了80%的工作。思亿欧并不赞同这个观点。

在传统的表格与DVI+CSS对于排名的影响两者比较,思亿欧并没有觉得后者有什么优势可言。因为实际上用DIV+CSS来设计的网站,也并没有因此得到搜索引擎的特别的照顾。

但是使用DIV+CSS来设计网站,确实能够对SEO起到一些帮助。

例如:

一、减少使用表格

表格层层嵌套,确实对SEO与用户体验有不利的影响,这同时也影响网页的下载速度。

二、降低网页体积

上百K的网页,不利于SEO,不利于搜索引擎的蜘蛛爬行。DIV+CSS设计网页,能够让精简网页HTML代码,让网页体积变得更小。

三、重要信息优先让搜索引擎蜘蛛爬取

通过DIV+CSS对网页的布局,可以让一些重要的链接、文字信息,优先让搜索引擎蜘蛛爬取。这对于SEO也有帮助。

思亿欧的建议:对于是用DIV+CSS设计网站还是用表格来设计网站,可以根据自己的技术实力来决定。DIV+CSS设计的网站,这个和域名一样,并没有多少先天性的优势。

提升网站价值,重点是在于后天的培养。

...... [阅读全文]

作者:galeki

目录


(一) :插件的基本结构
(二) :用XUL创建窗口控件
(三) :排列窗口控件
(四) :更多的窗口控件
(五) :驱动XUL界面
(六) :关于event对象
(七) :键盘快捷键
(八) :控件激活
(九) :command元素

(一) : 扩展的基本结构


用过firefox的人肯定要安装firefox的扩展,这样才能发挥火狐的全部实力。一般扩展是一个后缀为.xpi的文件,其实这个文件就是zip格式的压缩包,压缩了一个扩展所需要的所有目录和文件,基本的目录结构如下:
extension.xpi:
/install.rdf
/components/*
/components/cmdline.js
/defaults/
/defaults/preferences/*.js
/plugins/*
/chrome.manifest
/chrome/icons/default/*
/chrome/
/chrome/content/

看似很复杂,让我们从最重要的文件开始介绍起:

1. install.rdf

从名字可以看出,这个文件描述了扩展安装所需要的信息,包括了扩展的标识、版本、适用的应用程序、作者等等等等。本身是一个rdf文件。

基本的install.rdf示例:

<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">

<!-- 标识和版本 -->
<Description about="urn:mozilla:install-manifest">
<em:id>galeki@linuxge.org</em:id>
<em:version>1.0</em:version>
<em:type>2</em:type>

<!-- 针对的应用程序 -->
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>1.5</em:minVersion>
<em:maxVersion>2.0.0.*</em:maxVersion>
</Description>
</em:targetApplication>

<!-- 名称、介绍、作者和网站地址 -->
<em:name>Hello</em:name>
<em:description>扩展测试</em:description>
<em:creator>galeki</em:creator>
<em:homepageURL>http://blog.linuxgem.org/galeki</em:homepageURL>
</Description>
</RDF>

8~10行是标识信息,第8行的<em:id>段是此软件包唯一的标识,可以是作者的email,目的是唯一标识此软件包。第9行是目前的版本。第10行的<em:type>,值为2代表"我是扩展",4代表"我是主题",这里是扩展,所以值为2。

14~20行的<em:targetApplication>段描述了软件包针对的应用程序,16行那段古怪的<em:id>表明此扩展是针对firefox的,而不是thunderbird、sunbird,所以,只要是针对firefox的扩展,此id的值都不变。17~18行描述了此扩展适用的firefox版本。

23~26行描述了扩展的基本信息,从标签的名称上就可以看出意思,扩展管理器中显示的扩展信息,就是来源于这里。

2. chrome目录

chrome是扩展最重要的一个目录,所有描述扩展的文件,称为chrome。

chrome一般包括3类文件,content、locale、skin:

content:描述扩展界面、外观的定义文件,比如按钮布局,对话框,通过XUL文件和js文件来设定,后面我们可以看到XUL的介绍。
locale: 描述多语言信息的文件,一般是xml的dtd文件。
skin: 定义界面样式的css文件和所需要的图片文件。

一个典型(并不绝对)的chrome目录下包含这么几个子目录:
/chrome
content/
locale/
skin/

三个子文件夹存放了扩展对应的content、locale和skn类型的文件。

3.chrome.manifest文件

接下来,得让fierfox找到扩展的content、locale、skin文件在哪里,chrome.manifest就是这个作用。

这个文件让firefox知道扩展的content、locale、skin等文件在哪里,例如:
content hello chrome/content/

简单来说,就是指明,hello这个扩展的content类型文件,在chrome目录的content子目录下。

locale的定义稍有区别:
locale hello zh-CN chrome/locale/zh-CN/

指明hello这个扩展的zh-CN,也就是中文的locale,在chrome/locale/zh-CN/目录下。

skin的定义和locale相似:
skin hello classic/1.0 chrome/skin/classv1/

指明hello这个扩展,名叫classic/1.0的skin,在chrome/skin/classv1/目录下。

通过chrome.manifest文件的指定,firefox就可以找到对应的文件。在firefox中,引用web服务器上的文件是用的 “http://”前缀,引用硬盘上的文件是用的“file://"前缀,引用扩展中的文件有单独的引用前缀,就是“chrome://“,比如:
chrome://hello/content/about.xul

引用了hello扩展content类型文件中的about.xul文件。这样一来,不管在硬盘上扩展的content、locale、skin是在什么地方,只要chrome.manifest文件配置好,就可以让firefox通过“chrome://”引用到特定的文件了。

FireFTP的例子:

由上图的地址栏可以看出,打开FireFTP这个扩展,实际上就是打开了fireftp的content类型文件中的fireftp.xul文件。

(二):用XUL创建窗口控件


在Firefox中,所有的界面都是基于XUL文件描述的,XUL本身是一个XML文件。就连Firefox本身,也是基于XUL的,不信的话,可以在firefox的地址栏中敲入: chrome://browser/content/browser.xul,看看会出现什么情况吧。

1.创建一个简单的窗口

多说无益,让我们看一个简单的XUL文件示例:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

</window>

把上述的代码保存为test.xul,然后在firefox的“文件” --> “打开文件” 中打开这个文件,就可以看到(下图)。

哎,怎么啥都没有? 因为我们还没有往窗口中加入任何东西,所以除了标题栏之外,是一片空白。实际上,上面的XUL文件,是每个窗口的基本框架。

第1行是XML文件的基本表示,第2行引用渲染窗口控件的样式表文件,这里我们先跳过对这行的解释,只要知道“chrome://global/skin/” 引用的是firefox全局默认的样式表即可。

第3行的<window>元素,就是窗口的根元素,你可以把它想象成HTML中的<html>元素。属性id的值可以随便取,和HTML中的id属性相同,必须要保证全局唯一,因为之后我们要通过id来引用每个窗口。title属性就是窗口的标题,xmlns是名称空间,说明之下的内容是XUL。

窗口中所有的内容,都要放在<window>和</window>之间,就像HTML中所有的元素必须放在<html>和</html>之间一样。

2.让我们往窗口里添点东西吧

所有一般程序具有的窗口控件(按钮、单选复选框、文本输入框、下拉菜单……),在firefox的窗口中都可以实现,只不过,不同的窗口控件在XUL中变成了不同的XML标签,控件的属性(大小、文本、排列方式……)变成了标签的属性值而已。

2.1按钮

我们先来添加个按钮,打开test.xul,添加下面的代码:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<button label="普通的按钮"/>

</window>

按钮在XUL中就是<button>这个标签,label属性为按钮上显示的文字。

2.2文字

在窗口上显示的文字,用<label>标签来显示:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<label value="下面是一个普通的按钮:)"/>
<button label="普通的按钮"/>

</window>


2.3文本输入框

文本输入框,为<textbox>标签。让我们清除刚才添加的代码,下面的代码显示了<textbox>的几种用法。

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<label value="用户名"/>
<textbox id="username"/>
<label value="密码"/>
<textbox id="password" type="password" maxlength="10"/>

<label value="个人简介"/>
<textbox multiline="true"
value="在这里填入你的个人简介。"/>

</window>

第11行,密码输入框要设置type属性为"password";第13行,如果需要多行的输入框,需要指定multiline为"true"。

2.4单选和复选框

单选框为<radio>,复选为<checkbox>。

单选框的分组,只要把单选框标签包含在<radiogroup>中即可。看代码:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<label value="用户名"/>
<textbox id="username"/>
<label value="密码"/>
<textbox id="password" type="password" maxlength="10"/>
<label value="你喜欢的颜色"/>
<radiogroup>
<radio id="blue" label="蓝色"/>
<radio id="yellow" selected="true" label="黄色"/>
<radio id="red" label="红色"/>
</radiogroup>
<checkbox label="保存我的信息"/>
<label value="个人简介"/>
<textbox multiline="true"
value="在这里填入你的个人简介。"/>

</window>


2.5下拉选项

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<menulist>
<menupopup>
<menuitem label="红色"/>
<menuitem label="蓝色"/>
<menuitem label="黄色" selected="true"/>
</menupopup>
</menulist>

</window>

每个选项包含在<menuitem>中,<menuitem>再被包含在<menupopup>和<menulist>中。

2.6进度条

用<progressmeter>表示。进度条分为两类,一种是有明确完成进度的,一种是没有完成进度的,通过设置mode="determined"和
mode="undetermined"来实现。

看一下效果就明白了:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<progressmeter
id="progress1"
mode="determined"
value="60%"/>
<progressmeter
id="progress2"
mode="undetermined"/>

</window>


至此,我们介绍了用XUL创建出一个窗口所具备的基本控件的方法,但是这些空间只能按照次序从上到下的显示,而且,每个元素将占满窗口的整个宽度,接下来,我们要看一下怎么布局窗口中众多的控件。

(三) : 排列窗口控件


上一篇我们讲到了用XUL创建基本的窗口控件(按钮、输入框、单选复选框……),现在我们来讲一下如何排列他们。

盒子:<hbox>与<vbox>

XUL中主要的布局元素成为"盒子",分为两种,水平盒子和垂直盒子,也就是<hbox>和<vbox>,说白了就是把包含在盒子内的空间水平或者垂直排列,如果你熟悉GTK+编程的话,一定对这两种布局方式非常的熟悉。

上一篇的控件,只能按照顺序垂直分布在窗口中,因为这是窗口默认的排列控件的方式,要想改变,就要把控件放在盒子中:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<vbox>
<hbox>
<label value="用户名:"/>
<textbox id="login"/>
</hbox>
<hbox>
<label value="密码:"/>
<textbox id="pass"/>
</hbox>
<button id="ok" label="登录"/>
<button id="cancel" label="取消"/>
</vbox>
</window>

和上一篇一样,把上述文件保存为test.xul,并用firefox打开。

运行得不错,不过,“密码:”旁边的输入框似乎靠的太近了些,我们可以把两个文字标签、两个输入框,分别放在两个个<vbox>中,这样就解决了对齐问题:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<vbox>
<hbox>
<vbox>
<label value="用户名:"/>
<label value="密码:"/>
</vbox>
<vbox>
<textbox id="login"/>
<textbox id="pass"/>
</vbox>
</hbox>
<button id="ok" label="登录"/>
<button id="cancel" label="取消"/>
</vbox>
</window>

显示效果:

盒子内的布局

当我们把上面的窗口拖大,窗口控件还是停留在窗口的左边,留下右边一大片空白,这似乎不是我们想要的效果:

我们可以在<vbox>或<hbox>中的pack属性来控制,pack有3种值:

1. start:对vbox来说,是盒内全部靠上,对hbox,就是盒内全部靠左。
2. center:盒内居中。
3. end:vbox是靠下,hbox是靠右。

这里,我们还要介绍一个flex属性,默认情况下,盒子的大小是不变的,等于盒内元素的总大小,但是当flex属性为"1"时,盒子的大小是随着窗口的增大而增大,这样才能通过设置pack属性控制盒内的布局:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<vbox>
<hbox pack="center" flex="1">
<vbox>
<label value="用户名:"/>
<label value="密码:"/>
</vbox>
<vbox>
<textbox id="login"/>
<textbox id="pass"/>
</vbox>
</hbox>
<hbox pack="center" flex="1">
<button id="ok" label="登录" />
<button id="cancel" label="取消" />
</hbox>
</vbox>
</window>

这样就实现了居中:

分组窗口控件

有的时候,窗口中一部分空间是相互关联的,为了表示出这种关联关系,要用到<groupbox>:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<groupbox>
<caption label="9月20日是……?"/>
<label value="植树节"/>
<label value="爱牙日"/>
<label value="中秋节"/>
<label value="元宵节"/>
</groupbox>
</window>

显示效果:

<caption>的值,就是分组标签标题的值,<caption>甚至可以包含其他的控件:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<groupbox>
<caption>
<checkbox label="Enable Backups"/>
</caption>
<hbox>
<label control="dir" value="Directory:"/>
<textbox id="dir"/>
</hbox>
<checkbox label="Compress archived files"/>
</groupbox>
</window>

显示效果:


(四) : 更多的窗口控件


标签盒子

标签盒子是啥?大家都见过,就是分页标签:

对应的代码:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<tabbox>
<tabs>
<tab label="第一个标签标题"/>
<tab label="第二个标签标题"/>
</tabs>
<tabpanels>
<tabpanel id="firsttab">
<label value="第一个标签的内容"/>
</tabpanel>
<tabpanel id="secondtab">
<label value="第二个标签的内容"/>
</tabpanel>
</tabpanels>
</tabbox>
</window>

每个标签盒子中的内容被包含在<tabbox>中,<tabs>下的<tab>包含标签标题,<tabpanels>下的<tabpanel>包含每个标签的内容,按顺序和标签标题<tab>对应。

iframe

<iframe>这个标签在HTML里再熟悉不过了,在XUL中,作用和用法HTML一样,可以用来在窗口中嵌套一个网页,只要设置<iframe>的src属性即可:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<label value="以下为GemBlog首页…………"/>
<iframe id="content" src="http://blog.linuxgem.org" flex="1"/>
</window>

效果:

工具栏

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<toolbox>
<toolbar>
<toolbarbutton label="&lt; 后退"/>
<toolbarbutton label="前进 &gt;"/>
<textbox id="url"/>
</toolbar>
</toolbox>
</window>

<toolbox>包含<toolbar>,<toolbar>包含工具栏中的元素,<toolbarbutton>表示工具栏按钮:

菜单栏

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<menubar>
<menu label="文件">
<menupopup>
<menuitem label="新建"/>
<menuitem label="打开"/>
<menuitem label="保存"/>
<menuseparator/>
<menuitem label="退出"/>
</menupopup>
</menu>
<menu label="编辑">
<menupopup>
<menuitem label="拷贝"/>
<menuitem label="粘贴"/>
</menupopup>
</menu>
</menubar>
</window>

<menubar>为一个菜单栏的顶极标签,菜单栏中的每一项为一个<menu>,每一个菜单项下面的子项目,为<menupopup>下的<menuitem>,<menuseparator>为分隔符。

效果:(不知咋的,打开菜单的状态下没法抓图 :( )


(五) : 驱动XUL界面


前面几节,讨论了怎么用XUL创建窗口控件,这样我们就能创建出漂亮的程序界面,但是现在点击窗口中的控件,却什么也不会发生,接下来我们来看看怎样驱动界面中的控件。

大家都知道,在HTML中,同样也有简单的控件,比如按钮、单选、复选框,主要用HTML中的<input>标签来实现,HTML中是怎样驱动这些控件的呢?一般是通过诸如onclick、onfocus、onmouseover等等事件属性,通过事件驱动,再配合javascript 来完成,比如:
<input type="button" onclick="alert('我被点击了!')" />

如上代码在HTML中创建一个普通的按钮,点击它时,弹出“我被点击了!”的对话框。

在XUL中,驱动控件的方法和HTML基本相同,并且,也是通过javascript来完成,在XUL里,最有用的事件属性是oncommand,当控件被激活时就会出发这个事件,比如按钮被点击,单选复选框被点击,菜单项被点击等等,比如:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<label value="下面是一个普通的按钮:)"/>
<button label="普通的按钮" oncommand="alert('我被点击了!')"/>

</window>

点击按钮,和HTML中一样,弹出窗口显示:

通过javascript的事件冒泡,可以在上层元素中捕获下层元素的事件信息,并进行识别处理:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<vbox oncommand="alert(event.target.tagName + ' 被点击');">
<button label="普通的按钮"/>
<checkbox label="我是单选框"/>
</vbox>

</window>

当事件被激活,event.target中包含了被激活对象的信息,其中tagName就是对象标签的名称,可以通过它识别事件实在哪个标签(也就是控件)上被激活的。效果如下:

在XUL中,负责事件处理的javascript代码,可以像上面那样内联在xml标签中,也可以像HTML那样,从外部的js文件中引用:
button.js 文件:

function show_ok()
{
alert("我被点击了!");
}

在XUL文件中,用<script>标签引用外部的js文件:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<script src="button.js" />
<label value="下面是一个普通的按钮:)"/>
<button label="普通的按钮" oncommand="show_ok()"/>

</window>

效果和第一张图片一样。

你也可以通过熟悉的getElementById函数取得想要的对象,然后再用addEventListener函数动态的为元素添加事件处理函数,这样的好处就是完全分开了XUL和javascript,负责不同功能的两种语言不再纠缠在一起:
my_button.js 文件:

function show_ok()
{
alert("我被点击了!");
}
var button = document.getElementById("my_button");
button.addEventListener('command', show_ok, true);
/*
* 参数1为事件名称,oncommand即为command
* 参数2为事件处理函数
* 参数3为true 表示不捕捉冒泡消息
*/


<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<label value="下面是一个普通的按钮:)"/>
<button label="普通的按钮" id="my_button"/>
<script src="my_button.js" />

</window>

效果和上面一样。

值得注意的是,首先得在XUL中指定对象的id属性,<script>标签也得在想引用的元素后面出现才可以,因为如果在前面,那时候下面的元素还没有被创建,getElementById也找不到它。

(六) : 关于event对象


上一篇我们看到了如何用javascript驱动界面上的控件,现在我们看看在事件被触发时,如何获得更详细的信息。

每当某个事件被触发(比如控件被点击或激活、鼠标移动到控件上等等),有关这个事件的详细信息都被储存到event对象中,并可以在事件处理函数中进行查看,比如上一篇中的第二个例子,就是通过 event.target.tagName 获得被激活的控件的标签名称,event还有更多的属性,让我们看个例子:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<script>
function ShowMouseXY(event){
var document_xy = "X:" + event.clientX + " Y:" + event.clientY;
var screen_xy = "X:" + event.screenX + " Y:" + event.screenY;
document.getElementById("document").value = "鼠标在文档中的位置: " + document_xy;
document.getElementById("screen").value = "鼠标在屏幕中的位置: " + screen_xy;
}
</script>

<hbox>
<label id="screen"/>
<label id="document"/>
</hbox>
<hbox width="800" height="600" onmousemove="ShowMouseXY(event);"/>

</window>

这里用到了4个event中的属性,clientX、clientY、screenX、screenY,分别是事件触发时,鼠标相对文档的xy坐标值和相对整个屏幕的xy坐标值,第21行在hbox上设置了onmousemove的事件属性,每当鼠标在这个hbox上移动,就会触发函数显示当前鼠标的位置(鼠标没有被抓下来):

上一篇的第二个例子,我们用event.target引用了当前被激活的控件,通过事件冒泡在vbox上识别,与其相对的,还有一个event.currentTarget属性,引用的是事件冒泡最终传递给的控件:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script>
function who_am_i(event)
{
message = "我是" + event.currentTarget.tagName + "。你点击了" + event.target.tagName;
alert(message);
}
</script>
<vbox oncommand="who_am_i(event)">
<button label="OK"/>
<checkbox label="Save backup"/>
</vbox>

</window>

显示效果:

关于event更多的属性,可以参考 http://xulplanet.com/references/

(七) : 键盘快捷键


键盘快捷键是一个应用程序不可缺少的部分,最常见的地方在菜单栏中,在XUL中添加键盘快捷键是很简单的,只需要设置控件的accesskey属性即可:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"

xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<menubar>
<menu id="file-menu" label="文件(F)" accesskey="f">
<menupopup id="file-popup">
<menuitem id="close-command" label="关闭(X)" accesskey="x"/>
</menupopup>
</menu>
</menubar>

</window>

当然,accesskey属性也可以设置在其他控件上(比如按钮)。

如果要设置全局快捷键,这个时候就要用到<key>标签,每个<key>标签设置一个快捷键,最后把所有的<key>标签包含在一个<keyset>标签中即可:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<keyset>
<key id="key1" modifiers="control" key="Q" oncommand="alert('你按了快捷键crtl+Q')"/>
<key id="key2" modifiers="control alt" key="C" oncommand="alert('你按了快捷键crtl+alt+C')"/>
<key id="key3" keycode="VK_F6" oncommand="alert('你按了快捷键F6')"/>
</keyset>

</window>

这里介绍了设置全局快捷键的3种情况:

第9行,设置的快捷键是crtl+q,modifiers就是通常所说的修饰键,modifiers可以取control、alt、meta、shift,分别代表了键盘上的ctrl、alt、meta、shift键。

第10行,设置的快捷键是ctrl+alt+c,演示了如何设置有两个修饰键的情况,只需把他们用空格分开即可。

第11行,设置的快捷键是F6,值得注意的是,前面两行中指示快捷键的属性是key,直接指出键盘上的字母值,但是碰到像F1、F2这样的功能键,还有TAB和回车这样的按键,就没法通过key属性设置了,这个时候只有通过keycode设置,其实,键盘上的每个键都对应了一个keycode值,这个值一般以“VK_”开头,下面的表格列出了常用的keycode值,对应的按键从后缀就可以看出:
VK_CANCELVK_BACKVK_TABVK_CLEAR
VK_RETURNVK_ENTERVK_SHIFTVK_CONTROL
VK_ALTVK_PAUSEVK_CAPS_LOCKVK_ESCAPE
VK_SPACEVK_PAGE_UPVK_PAGE_DOWNVK_END
VK_HOMEVK_LEFTVK_UPVK_RIGHT
VK_DOWNVK_PRINTSCREENVK_INSERTVK_DELETE
VK_0VK_1VK_2VK_3
VK_4VK_5VK_6VK_7
VK_8VK_9VK_SEMICOLONVK_EQUALS
VK_AVK_BVK_CVK_D
VK_EVK_FVK_GVK_H
VK_IVK_JVK_KVK_L
VK_MVK_NVK_OVK_P
VK_QVK_RVK_SVK_T
VK_UVK_VVK_WVK_X
VK_YVK_ZVK_NUMPAD0VK_NUMPAD1
VK_NUMPAD2VK_NUMPAD3VK_NUMPAD4VK_NUMPAD5
VK_NUMPAD6VK_NUMPAD7VK_NUMPAD8VK_NUMPAD9
VK_MULTIPLYVK_ADDVK_SEPARATORVK_SUBTRACT
VK_DECIMALVK_DIVIDEVK_F1VK_F2
VK_F3VK_F4VK_F5VK_F6
VK_F7VK_F8VK_F9VK_F10
VK_F11VK_F12VK_F13VK_F14
VK_F15VK_F16VK_F17VK_F18
VK_F19VK_F20VK_F21VK_F22
VK_F23VK_F24VK_NUM_LOCKVK_SCROLL_LOCK
VK_COMMAVK_PERIODVK_SLASHVK_BACK_QUOTE
VK_OPEN_BRACKETVK_BACK_SLASHVK_CLOSE_BRACKETVK_QUOTE
VK_HELP

显示效果:


(八) :控件激活


当我们用鼠标点击一个控件,或者用TAB键移动到一个控件上时,我们说这个控件被激活了(focus),离开这个控件时,我们说这个控件失去焦点(blur),熟悉js的人一定知道 onfocus 和 onblur 这两个事件属性,XUL中也是一样,通过这两个属性控制控件在被激活和失去焦点时要做的事情。

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window
id="test-window"
title="测试用的窗口"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script>
function displayFocus(){
var elem=document.getElementById('username');
elem.setAttribute('value','输入你的用户名,只能是英文。');
}
</script>

<label value="用户名:"/>
<textbox id="login" onfocus="displayFocus();"/>
<description id="username" value="" />
</window>

显示效果:

通过设置textbox的onfocus属性,在输入框被激活的时候,在下方显示提示信息。

接下来,我们看看如何获得当前用户激活的控件。

当前被激活的控件保存在 document.commandDispatcher 这个对象中的 focusedElement 属性中(后面的章节会详细介绍),那么如果用户改变了焦点,我们只要重新获取这个值,就可以得到当前激活的控件了。

(五) : 驱动XUL界面中介绍了 addEventListener 这个方法,通过 xxx.addEventListener(...) ,就可以给xxx控件添加事件处理函数,如果直接调用 addEventListener ,就是给全局的某个事件添加事件处理函数,既然我们要在用户激活控件时重新获得focuusedElement属性,那么我们只要处理全局的focus事件即可。

废话不说,看代码:

<window id="focus-example" title="测试窗口"
onload="init();"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<script>
function init(){
addEventListener("focus",setFocusedElement,true);
}

function setFocusedElement(){
var focused = document.commandDispatcher.focusedElement;
document.getElementById("focused").value = "你点了 " + focused.tagName;
}
</script>

<hbox>
<label value="用户名:"/>
<textbox id="username"/>
</hbox>

<button label="我是按钮"/>
<checkbox label="我是复选框"/>

<label id="focused" value="你啥也没点……"/>

</window>

第2行,设置window的onload属性,和在js中设置 window.onload="init();" 一样,在窗口装载完毕执行init()。

那么,我们看看init()执行了什么,第7行,通过addEventListener,将全局的focus事件关联到setFocusedElement() 这个函数上。

在setFocusedElement 函数中,第11行,直接通过 document. commandDispatcher. focusedElement 获得当前被激活的控件对象。

显示效果:


(九) : command元素


何为command元素?从名字来看似乎和执行的命令有关,先来看个简单例子:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window id="example-window" title="测试的窗口"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<command id="cmd_openhelp" oncommand="alert('Help!');"/>
<button label="Help" command="cmd_openhelp"/>
</window>

第7行就是command元素,每个command元素一般有一个id属性,唯一的标识这个command对象,为了不容易和一般元素的id相冲突,在前面加一个cmd_的前缀是个不错的办法;oncommand属性指定了和这个command对象关联的命令动作。

第8行的button元素就引用了command元素关联的命令动作,在原来的章节中,是通过oncommand属性给控件关联动作,现在只需要用command属性,并把对应的command元素id作为属性值,就可以关联到特定的动作。

看样子我们好像是兜了个大圈子,兜这个圈子有什么好处呢?

* 首先,可以把表示命令动作的command元素单独保存在一个文件中,从而实现表示界面和表示显示的代码分离,更加容易管理。
* 另外,如果某些按钮、菜单项、工具栏按钮执行的都是一个动作那么我们主要把他们关联到相同的command元素上即可,而不用重复写好几遍。

而且不仅如此,下面的才是关键:

* 我们可以disable和enable一个command,如果command元素被设置成disable,那么和它关联的动作命令不会得到执行。
* disable和enable某个command元素的同时,和这个command元素关联的控件会被自动设置成disable和enable的状态。

看个了例子:

<window id="focus-example" title="测试窗口"
onload="init();"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<command id="cmd_openhelp" oncommand="alert('这是帮助');"/>
<button label="帮助" command="cmd_openhelp"/>
<button label="还是帮助" command="cmd_openhelp"/>

<button label="禁用帮助"
oncommand="document.getElementById('cmd_openhelp').setAttribute('disabled','true');"/>
<button label="激活帮助"
oncommand="document.getElementById('cmd_openhelp').removeAttribute('disabled');"/>
</window>

我们可以通过setAttribute和removeAttribute这两个方法,来设定某个command元素的disable和 enable,可以看到,如果disable了cmd_openhelp这个command,和它关联的按钮也自动变成灰色不可点击的状态:

...... [阅读全文]

博客订阅

feedsky Technorati Join My Community at MyBloglog!
抓虾 pageflakes
Rojo google reader
netvibes my yahoo
newsgator bloglines
鲜果 哪吒
有道 分享到饭否

标签云集

Heartnn@饭否

日志归档

最新日志

最新评论

我的收藏夹

门户
技术
游戏

关注者