loading ...

Q网志

my web and me.
作者: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,和它关联的按钮也自动变成灰色不可点击的状态:

0 评论

发表评论

博客订阅

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

标签云集

Heartnn@饭否

日志归档

最新日志

最新评论

我的收藏夹

门户
技术
游戏

关注者