星期五, 三月 23, 2007

使用JACOB控制Powerpoint

什么是JACOB?

JACOB是一个JAVA和COM之间的桥接口。它使得你可以在Java中自动控制COM组件。它使用JNI实现本地调用COM和Win32程序接口。

除了JACOB,还需要什么?

要实现控制powerpoint除了了解JACOB怎么使用外,还需要了解powerpoint对象模型和powerpoint提供的接口。具体这方面的信息可以在MSDN上查找到。

简单实例

我实现了一个打开powerpoint程序并播放一个幻灯片的小程序,仅供大家参考。

/*

* PPTTest.java

* * Created on 2007年3月23日, 下午1:34

* * To change this template, choose Tools Template Manager

* and open the template in the editor.

*/
package jacobdemo;


import com.jacob.activeX.ActiveXComponent;

import com.jacob.com.ComThread;

import com.jacob.com.Dispatch;

import com.jacob.com.Variant;


/**

* * @author Xiaofeng Wang

*/

public class PPTTest {

private static final String PPT_FILE = "D:\\ajax.ppt";

/**

* @param args the command line arguments

*/

public static void main(String[] args) {

// 新建一个powerpoint程序实例

ActiveXComponent ppt = new ActiveXComponent("PowerPoint.Application");

// 设置程序界面是否可见

ppt.setProperty("Visible", new Variant(true));

ActiveXComponent presentations

= ppt.getPropertyAsComponent("Presentations");

// 打开一个现有的 Presentation 对象

ActiveXComponent presentation =

presentations.invokeGetComponent("Open",new Variant(PPT_FILE),

new Variant(true));

// powerpoint幻灯展示设置对象

ActiveXComponent setting = presentation.getPropertyAsComponent("SlideShowSettings");

// 调用该对象的run函数实现全屏播放

setting.invoke("Run");

// 释放控制线程

ComThread.Release();

}

}

相关资料

星期四, 三月 22, 2007

Vi指令大全[转]

进入vi的命令
vi filename: 打开或新建文件,并将光标置于第一行首
vi +n filename: 打开文件,并将光标置于第n行首
vi + filename: 打开文件,并将光标置于最后一行首
vi +/pattern filename: 打开文件,并将光标置于第一个与pattern匹配的串处
vi -r filename: 在上次正用vi编辑时发生系统崩溃,恢复filename
vi filename....filename: 打开多个文件,依次进行编辑

移动光标类命令
h: 光标左移一个字符
l: 光标右移一个字符
space: 光标右移一个字符
Backspace: 光标左移一个字符
k或Ctrl+p: 光标上移一行
j或Ctrl+n: 光标下移一行
Enter: 光标下移一行
w或W : 光标右移一个字至字首
b或B : 光标左移一个字至字首
e或E : 光标右移一个字至字尾
): 光标移至句尾
(: 光标移至句首
}: 光标移至段落开头
{: 光标移至段落结尾
nG: 光标移至第n行首
n+: 光标下移n行
n-: 光标上移n行
n$: 光标移至第n行尾
H: 光标移至屏幕顶行
M: 光标移至屏幕中间行
L: 光标移至屏幕最后行
0: 光标移至当前行首
$: 光标移至当前行尾

屏幕翻滚类命令
Ctrl+u: 向文件首翻半屏
Ctrl+d: 向文件尾翻半屏
Ctrl+f: 向文件尾翻一屏
Ctrl+b: 向文件首翻一屏
nz: 将第n行滚至屏幕顶部,不指定n时将当前行滚至屏幕顶部。

插入文本类命令
i: 在光标前
I: 在当前行首
a: 光标后
A: 在当前行尾
o: 在当前行之下新开一行
O: 在当前行之上新开一行
r: 替换当前字符
R: 替换当前字符及其后的字符,直至按ESC键
s: 从当前光标位置处开始,以输入的文本替代指定数目的字符
S: 删除指定数目的行,并以所输入文本代替之
ncw或nCW: 修改指定数目的字
nCC: 修改指定数目的行

删除命令
ndw或ndW: 删除光标处开始及其后的n-1个字
do: 删至行首
d$: 删至行尾
ndd: 删除当前行及其后n-1行
x或X: 删除一个字符,x删除光标后的,而X删除光标前的
Ctrl+u: 删除输入方式下所输入的文本

搜索及替换命令/pattern: 从光标开始处向文件尾搜索pattern
?pattern: 从光标开始处向文件首搜索pattern
n: 在同一方向重复上一次搜索命令
N: 在反方向上重复上一次搜索命令
:s/p1/p2/g: 将当前行中所有p1均用p2替代
:n1,n2s/p1/p2/g: 将第n1至n2行中所有p1均用p2替代
:g/p1/s//p2/g: 将文件中所有p1均用p2替换

选项设置
all: 列出所有选项设置情况
term: 设置终端类型
ignorance: 在搜索中忽略大小写
list: 显示制表位(Ctrl+I)和行尾标志($)
number: 显示行号
report: 显示由面向行的命令修改过的数目
terse: 显示简短的警告信息
warn: 在转到别的文件时若没保存当前文件则显示NO write信息
nomagic: 允许在搜索模式中,使用前面不带“\”的特殊字符
nowrapscan: 禁止vi在搜索到达文件两端时,又从另一端开始
mesg: 允许vi显示其他用户用write写到自己终端上的信息

最后行方式命令:n1,n2 co n3: 将n1行到n2行之间的内容拷贝到第n3行下
:n1,n2 m n3:将n1行到n2行之间的内容移至到第n3行下
:n1,n2 d: 将 n1行到n2行之间的内容删除
:w: 保存当前文件
:e filename: 打开文件filename进行编辑
:x: 保存当前文件并退出
:q: 退出vi
:q!: 不保存文件并退出vi
:!command: 执行shell命令command
:n1,n2 w!command: 将文件中n1行至n2行的内容作为command的输入并执行之, 若不指定n1,n2,则表示将整个文件内容作为command的输入
:r!command: 将命令command的输出结果放到当前行

寄存器操作
"?nyy: 将当前行及其下n行的内容保存到寄存器?中,其中?为一个字母,n为一个数字
"?nyw: 将当前行及其下n个字保存到寄存器?中,其中?为一个字母,n为一个数字
"?nyl: 将当前行及其下n个字符保存到寄存器?中,其中?为一个字母,n为一个数字
"?p: 取出寄存器?中的内容并将其放到光标位置处。这里?可以是一个字母,也可以是一个数字
ndd: 将当前行及其下共n行文本删除,并将所删内容放到1号删除寄存器中

星期五, 三月 16, 2007

增强了Java的功能的Cool APIs

一篇比较旧的文章
2001年6月8号,Java保持在内容和功能的增强。Java公社(JCP)的参与者们又一次构造和提交了一些新的API。事实上,在今年的JavaOne会议上,JCP组织扮演了重要的角色。在每个会议上,演讲人都提及Java请求规范(JSR),提交规范,以及列举他们组织的参与者。Sun的人员拿走了首要荣誉,但大家清楚地知道是全世界的组织捐赠出了JCP的成就。
在这篇文章中,我将介绍3个最酷的在会议上讨论的API:
  • Java打印服务(JPS)
  • 无线设备连接(Bluetooth)
  • 远程客户端加载(Java Web Start)

Java打印服务(JPS)

尽管Java早就支持打印API了,但他们注重通过图形来设置页面。如果你是个图形方面的天才,那不成问题,但对于普通人来说太难使用了。JDK1.4出现了一个新包javax.print,使得查找打印机和向打印机发送文档相当的简单。

这个API是基于Xerox提交的JSR,它提供了基于打印机的名称、地址或性能来查找打印机。它也提供了机制用于指定打印的份数,需要单面还是双面打印,及纸张大小。Java打印服务接口支持所有国际标准的纸张大小,包括European A4,US letter,和Asian B5。

在JPS中,数据格式使用MIME类型指定,例如:image/jpeg,text/plain,及text/html。最棒的是这个API包含一个能识别HTML的格式引擎,它需要一个实现Printable或Pageable接口的文档,并且生成PostScript。HTML格式化引擎对于流行的XML数据存储具有很大的价值。你只需要设置一个XSLT(可扩展样式表语言转换)样式表,使用它把XML数据转换成HTML,然后把结果发送给打印机就可以了。

尽管打印接口包含了PostScript格式化引擎,但它没有实现PDF格式生成器。然而,提供了相应的说明,我估计实现PDF输出已经不远了。

这个打印接口还有很多缺陷使得它不够完整得像一个商业产品,没有一个独立软件提供商愿意去生产它。例如:缺乏打印预览功能及在打印过程中转换托盘。

托盘转换是很重要的,当你想要指定信纸上打印一行时,当在打印普通纸张时停顿一下时。你当然也需要打印预览,当你想要使用户看到打印后的效果。

自从2D图形包提供了打印预览功能,及托盘转换是一个简单精致的接口,很可能将来在一些打印机上实现。然而,现在并没有这方面的计划。

尽管优雅的商业应用程序仍然缺乏他们需要的功能,实用程序的开发人员可以使用他们需要的打印功能了。事实上使用得java打印接口成为了受欢迎的新功能。

无线设备互联(Bluetooth)

Java版的蓝牙接口仍处于初级阶段,但是他们在继续完善。

蓝牙致力于近距离的动态设备互联--大概30英尺左右。它运行在相当廉价的硬件上,并在一个微型系统上,因此它可以被用在PDA和手机上就像笔记本电脑和有线设备上。

蓝牙是个平台不可知的协议,所以java不一定需要使用它。但是java版的蓝牙接口保证在支持java的设备上可以使用它。

使用蓝牙,键盘、鼠标、或者游戏杆不用通过物理线缆连接电脑。这对于桌面系统很好,但是它更大的价值在于便携式电脑上。

类似的,一旦你进入你的汽车,你的耳机就可以和你的手机一起工作,不需要插上插头。同样的耳机可以和你电视或收音机一起工作--任何一个刚好开着的设备。

在商业会议上,蓝牙可以允许你和所有出席的人创建一个ad hoc网络,不用线就可以分享文件、展示幻灯片。在你的办公室,同样的动态构建网络可以通过你的基站提供存取打印机、登陆Inernet,或者同步目录。

蓝牙规范的领导者,Motorola的C. Bala Kumar提出像这样的ad hoc网络同样可以用在买票、在旅馆登记、返还租用的车、或者登记航班。

总之,java蓝牙接口保证允许我们更紧密的联系在一起。

远程客户端加载(Java Web Start)

坦白的说,我很惊讶Java Web Start没有赢得2001 JavaWorld最具创新产品编辑选择奖。Tomcat3.2,拿到了这个也该拿到的奖。但是谈论创新:Java Web Start可以使你的程序拥有打印和I/O能力,这是运行在安全沙盒里的applet所不具有,这将是浏览器不兼容不成为一个问题。这很优雅和很酷。不过在JavaOne上,架构师Rene Schmidt还是列举了这个API的先进功能。

Schmidt展示了将一个应用程序分割成几个jar文件,及使用它们需要的附加库将它们重新联系起来。紧接着他展示了怎么设置一个应用程序描述文件去指定赖加载程序片断,这样用户不用一下下载整个应用程序。

他还指出当程序调用一个功能时,可以使用DownloadService接口。例如:如果帮助系统被调用,程序可以在初始化操作前让DownloadService去得到适合的jar文件。

如果功能已经下载完成,DownloadService当然变成了一个空操作。但是如果jar需要去获取,那么一个默认的进度对话框会提示用户,显示进度条,和提供取消操作。(你可以使用自己定义的对话框,但默认比较简单)。

Schmidt也讲述了创建jardiff文件的过程--jar文件包含递增的更新。他也示范了Java Web Start如何自动下载适合的递增更新,依赖于用户当前安装的版本。

Schmidt讨论了其他功能API的变化,包括文件保存、打开文件、及存取剪切板。操作只在用户接受的情况下执行。在那之后,将来的剪切板存取不出现提示框。换而言之,Java Web Start提供动态的、用户干预的安全管理,不需要用户设置策略文件。

最后,当虚拟机用户选择需要运行的程序,Java Web Start负责下载和安装。这要靠Java Web Start具有一个方便、有效的机制来分发强大的应用程序像部署applet一样简单。

原文链接

为Java ME程序添加蓝牙文本协议

这篇文章的副标题是:学习如何通过蓝牙PAN共享信息和事件。
移动设备在通讯和游戏工业持续的火爆,就像软件倾向于Ad Hoc和点对点网络一样,能处理不同种类设备的能力成为了网络应用程序(不论是游戏、生产还是信息共享)的一个很大优势。在这篇文章中,学习怎样在你的程序中使用和集成蓝牙API(通过JSR82,已经引入了Java 2 平台微型版[j2me]中)。这里,你将会找到完整的蓝牙设备发现,配对,和消息通讯的实现。

被作为一种创新在移动设备领域持续扩展,及越来越多的公司将芯片集成到他们更多的客户设备上(这不是传统意义上的计算关联),将这些设备连接起来组成一个智能环境的机会在增长。在这篇文章你会看到基于蓝牙Java API的软件包如何使这些设备交换任意的基于文本的消息,以及简单的使用,对于客户端程序有用的API。

为什么是蓝牙?
蓝牙在构造个人区域网络,低数率连接设备,已经是一项成熟技术,廉价而且是无线的。蓝牙以多种方式(或类型)存在,以适应不同的电源和范围要求。这些特点才使得在移动设备之间和联网的静态设备之间建造Ad Hoc的点对点网络的想法出现,就像消费电子的客厅。

为什么使用PANs?
PANs相对于LANs、WANs、和WWW,解决不同问题;PAN的问题通常由方便的方式驱动。多半被技术倾媚的是手机听筒和无键的车辆登录系统。也或者这些解决方案需要蓝牙技术或者其它的无线技术,但倘若提供一个划算的方案,使得比标准的好很多,你就可以进入新市场了。

btevent软件包
要将不同厂家的不同设备连接到一起,你需要一个简单的、灵活的通讯方式。像对象交换技术(OBEX)解决了二进制数据的传输问题,这对于很多蓝牙应用程序是至关紧要的,但没有实现简单的消息协议。同样你需要知道设备和服务发现的概念,对是在设备之间建立Ad Hoc点对点连接的关键。这个brevents包提供一种简单、可重用技术在蓝牙设备之间实现文本通讯。
例如,你或许希望你的电视声音在电话响的时候自动调小。代码单1和2展示了如何利用btevents包在客户端程序中开启两个设备之间的通讯,而不需要大量的死板代码。
第一个要看的代码是运行在电话上。
Listing 1. Sample code for a telephone
package bluetooth.livingroom;
import com.ibm.btevents.*;
public class TelephoneMonitor extends MIDlet implements BTEventListener,
PhoneListener {
private BTManager btManager;
public TelephoneMonitor() {
btManager = new BTManager(this);
}
public void incomingCall(PhoneEvent event) {
btManager.sendMessage(
"bluetooth.livingroom.TelevisionMonitor",
"incomingCall:"+event.getCaller()
);
}
public void callEnded(PhoneEvent event) {
btManager.sendMessage(
"bluetooth.livingroom.TelevisionMonitor",
"callEnded:"+event.getDuration()
);
}
public void messageReceived(BTEvent event) {}
public void messageSent(BTEvent event) {}
public void devicesDiscovered(BTEvent event) {}
public void diagnosticMessage(BTEvent event) {}
}

TelevisionMonitor类创建一个BTManager对象并注册一个BTEventListner对象。在这个案例中,电话并不关注蓝牙通讯中发生的事件;例如,在TelephoneMonitor中。在这个类中比较有意思的代码在incomingCall() 和callEnded() 方法中。这些方法是被一个虚构的PhoneEvent时间调用的,这样能使TelevisionMonitor 通过BTManager对象传输消息。

现在,看看另外一边:
Listing 2. Sample code for a television
package bluetooth.livingroom;
import com.ibm.btevents.*;
public class TelevisionMonitor extends MIDlet implements BTEventListener {
private BTManager btManager;
public TelevisionMonitor() {
btManager = new BTManager(this);
}
private void reduceVolume() {
...
}
private void restoreVolume() {
...
}
private void displayMessage() {
...
}

public void messageReceived(BTEvent event) {
String message[] = event.getMessage().split(":");
if (message[0].equals("incomingCall")) {
displayMessage("Incoming call from "+message[1]);
reduceVolume();
} else if (message[1].equals("callEnded")) {
displayMessage("Call ended, lasted "+message[1]);
restoreVolume();
}

public void messageSent(BTEvent event) {}
public void devicesDiscovered(BTEvent event) {}
public void diagnosticMessage(BTEvent event) {}
}

这里客户端代码简单的接受消息。如果接收到了一个incomingCall消息,代码减小声音及在屏幕上显示来了个电话。如果接收到callEnded消息,这个代码恢复声音以及显示电话完成。
在上面的每个代码快里,你需要假想关于设备相关的API和事件机制,例如TelephoneMonitor的PhoneEvent对象和TelevisionMonitor在屏幕上显示消息和控制声音的功能。这些功能与设备特性相关,不可能在各种设备上调和。然而,你可以本地实现这些代码;你不需要让电视意识到,或理解PhoneEvents。你只需要设备生产商承认设备代码之间的逻辑链接。在这个案例中,逻辑链接是电视希望知道用户什么时候在打电话。

接着,看一下brevents如何处理消息。

btevents软件包介绍
btevents包是建立在Java蓝牙接口上的。它使得脱离复杂,在不同设备之间,实现一个简单、基于文本的协议。就像名字所暗示的,信息是靠事件间提交的。因为PANs可能是非常动态的,设备在它的范围进入和出去是没有提示的,使用它的所有软件必须遵从异步设计原则以防止暂停核挂起,并通过GUI提示用户。Java语言的事件机制对于这个环境是一个完美的工具。

Figure 1 展示了btevents包的实现。

Figure 1. Package overview

TelephoneMonitor和TelevisionMonitor类都在他们的构造函数中创建了一个BTManager类的实例,因此你应该从研究BTManager类做了什么开始(列表3)。

Listing 3. The BTManager class
package com.ibm.btevents;
public class BTManager {
private BTTransmitter transmitter;
private BTReceiver receiver;
private BTDiscoverer discoverer;

public BTManager(BTEventListener listener) {
transmitter = new BTTransmitter();
transmitter.addBTEventListener(listener);
transmitter.start();
receiver = new BTReceiver();
receiver.addBTEventListener(listener);
receiver.start();
discoverer = new BTDiscoverer();
discoverer.addBTEventListener(listener);
discoverer.start();
}
public void startDiscovery() {
discoverer.searchForDevices();
}
public void sendMessage(String remoteName, String message)
throws DeviceNotFoundException {
transmitter.sendMessage(remoteName, message);
}
}
就像你所看到的,这个类创建和开始3个单独的线程,每个都有个不同的任务。在线程内部实现这些功能,消除了客户端程序在一个链接发送消息是被锁住的可能。

3个线程中的每个都实现了部分使两边能够通讯,就像设备和服务的发现。

BTDiscoverer

现在研究一下BTDiscoverer线程。这个线程允许客户端程序请求本地查找端点,使用BTEvent使得查找结果异步的返回。其中最重要的代码是初始化查找会话:

localDevice.getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC, this);

这个API调用自身的事件集,需要BTDiscoverer类实现DiscoveryListener接口。为了保持btevents接口干净和兼容,这些事件在内部处理。任何与发现相关的事件需要扩展到BTEvents并通过BTDiscover启动。

BTReceiver

BTReceiver类是使用工作者线程模式设计的服务器,扮演着熟客的角色。它创建一个StreamConnectionNotifier 对象并监听,是否有连接进入。当BTReceiver发现一个连接,就通过StreamConnection对象离开工作者线程去处理输入和发出一个收到消息BTEvent给所有的注册的BTEventListeners。

在两个蓝牙设备之间建立连接,StreamConnection不是唯一的选择。事实上有3种不同的连接方式,如下表

Table 1. Types of bluetooth connections
连接标志 具体名称

btgoep 通用对象交换
btl2cap 逻辑链路和适配层协议
btspp 模拟串口

第一个,btgoep传输二进制数据,所以他不适合基于字符串的通讯。btl2cap需要开发人员做低级的操作,配置最大消息单元。然而,btspp为开发人员隐藏了这些复杂性,因此选择逻辑连接是为了使开发人员的操作简单化。

连接URL通过javax.microedition.io.Connector.open(connURL) 调用的格式:

protected static final String BT_PROTOCOL = "btspp";protected static final String BT_ID = "1234";server = (StreamConnectionNotifier)Connector.open( BT_PROTOCOL + "://localhost:" + BT_ID);

对localhost的引用是很重要的,它告诉open()去创建一个服务器连接。如果你使用远程地址,你就创建了一个客户端连接。

BTTransmitter

BTTransmitter类,就像名字所暗示的,负责传输消息到远程设备。客户端程序能通过BTManager类提交消息。这是通过BTTransmitter类并添加到一个消息队列。BTTransmitter 线程监控这个队列并使用Connector类发送所有消息。要做到这个,它必须找到远程目标上的服务。这个过程很像设备发现。

localDevice.getDiscoveryAgent().searchServices( null, filter, message.getRemote(), this);

在查找完成后,你才能使用ServiceRecord去创建一个OoutputStream,接着可以写入一个消息:

out = Connector.openOutputStream( record.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false));out.write(message.getMessage().getBytes());fireMessageSentEvent(message.getMessage());

代码发送消息后,他会引发事件到监听器上。

应付PANs不可靠的天性,BTTransmitter线程将有限次重发发送失败的消息。在5次尝试后,就假设设备已经不在范围内了并丢弃消息--这是ad hoc 网络的天性。

使用这个开发包

现在回到感兴趣的工作:使设备相互交谈!你只需要很少的代码,就可以连接设备,运行brevents包。列表4展示了简单的伪代码。

Listing 4. Using the btevents package
import com.ibm.btevents.*;
public class MyBTClass implements BTEventListener {

...
private BTManager manager;

public MyBTClass() {
...
manager = new BTManager();
manager.addBTEventListener(this);
...
}
public void messageReceived(BTEvent event) {
...
}
public void messageSent(BTEvent event) {
...
}
public void devicesDiscovered(BTEvent event) {
...
}
public void diagnosticMessage(BTEvent event) {
...
}
public void errorMessage(BTEvent event) {
...
}
}

提供的软件包中包含一个简单的类com.ibm.btevents.ut.BTTestsMIDlet,它实现了一个简单的MIDlet。

结论

在这篇文章中,你已经知道如何在客户端程序中添加蓝牙传输层而不需要大量的样板代码和考虑异步消息的问题。你可以完成一个清晰的功能,并能使代码开发简单而且可维护。

原文链接

星期三, 三月 14, 2007

Java中实现鼠标模拟与键盘映射

Java SDK 1.3以后实现了Robot类。此类用于为测试自动化、自运行演示程序和其他需要控制鼠标和键盘的应用程序生成本机系统输入事件。Robot 的主要目的是便于 Java 平台实现自动测试。
使用该类生成输入事件与将事件发送到 AWT 事件队列或 AWT 组件的区别在于:事件是在平台的本机输入队列中生成的。例如,Robot.mouseMove 将实际移动鼠标光标,而不是只生成鼠标移动事件。
Robot中主要的鼠标和键盘控制方法有:

  • void keyPress(int keycode) 按下给定的键。
  • void keyRelease(int keycode) 释放给定的键。
  • void mouseMove(int x, int y) 将鼠标指针移动到给定屏幕坐标。
  • void mousePress(int buttons) 按下一个或多个鼠标按钮。
  • void mouseRelease(int buttons) 释放一个或多个鼠标按钮。
  • void mouseWheel(int wheelAmt) 在配有滚轮的鼠标上旋转滚轮。

下面就让我们来实战鼠标控制,实现一个简单的鼠标控制程序MouseController。程序功能很简单:随机移动鼠标并点击左键。

代码如下:

import java.awt.AWTException;

import java.awt.Dimension;

import java.awt.Robot;

import java.awt.Toolkit;

import java.awt.event.InputEvent;

import java.util.Random;


/**

*

* @author Xiaofeng Wang

*/

public class MouseController implements Runnable {

private Dimension dim;

private Random rand;

private Robot robot;

private volatile boolean stop = false;

/** Creates a new instance of Main */

public MouseController() {

dim = Toolkit.getDefaultToolkit().getScreenSize();

rand = new Random();

try {

robot = new Robot();

} catch (AWTException ex) {

ex.printStackTrace();

}

}


public void run() {

while(!stop) {

int x = rand.nextInt(dim.width);

int y = rand.nextInt(dim.height);

robot.mouseMove(x, y);

robot.mousePress(InputEvent.BUTTON1_MASK);

try {

Thread.sleep(3000);

} catch (InterruptedException ex) {

ex.printStackTrace();

}

}

}

public synchronized void stop() {

stop = true;

}

/** * @param args the command line arguments */

public static void main(String[] args) {

MouseController mc = new MouseController();

Thread mcThread = new Thread(mc);

System.out.println("Mouse Controller start");

mcThread.start();

try {

Thread.sleep(60000);

} catch (InterruptedException ex) {

ex.printStackTrace();

}

mc.stop();

System.out.println("Mouse Controller stoped");

}

}

当然键盘映射也类似,无非是使用void keyPress(int keycode)。

现在实现了控制鼠标和键盘,接下了我们要获取操作后的效果(屏幕截图)。好在Robot类也提供了一个方法:BufferedImage createScreenCapture(Rectangle screenRect);可以直接将全屏幕或某个屏幕区域的像素拷贝到一个BufferedImage对象中。

好,下面实战使用robot截屏,实现Capture程序,每隔1秒截屏一次。

代码如下:

public class Capture extends javax.swing.JFrame implements Runnable {

/** Creates new form Capture */

public Capture() {

initComponents();

try {

robot = new Robot();

} catch (AWTException ex) {

ex.printStackTrace();

}

dim = Toolkit.getDefaultToolkit().getScreenSize(); }

/** This method is called from within the constructor to

* initialize the form.

* WARNING: Do NOT modify this code. The content of this method is

* always regenerated by the Form Editor.

*/

//

private void initComponents() {

screenCanvas = new java.awt.Canvas();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

stop = true;

setResizable(false);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());

getContentPane().setLayout(layout);

layout.setHorizontalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

.addComponent(screenCanvas, javax.swing.GroupLayout.PREFERRED_SIZE, 519, javax.swing.GroupLayout.PREFERRED_SIZE) );

layout.setVerticalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

.addComponent(screenCanvas, javax.swing.GroupLayout.PREFERRED_SIZE, 434, javax.swing.GroupLayout.PREFERRED_SIZE)

);

pack();

}//

/** * @param args the command line arguments */

public static void main(String args[]) {

final Capture capture = new Capture();

java.awt.EventQueue.invokeLater(new Runnable() {

public void run() {

capture.setVisible(true);

}

});

Thread cutThread = new Thread(capture);

cutThread.start();

}

public void run() {

stop = false;

while(!stop) {

BufferedImage bImage = robot.createScreenCapture(new Rectangle(dim.width, dim.height));

Graphics g = this.screenCanvas.getGraphics();

g.drawImage(bImage, 0, 0, this);

try {

Thread.sleep(1000);

} catch (InterruptedException ex) {

ex.printStackTrace();

}

}

}

private synchronized void stop() {

stop = true;

}

// 变量声明 - 不进行修改

private java.awt.Canvas screenCanvas;

// 变量声明结束

private volatile boolean stop;

private Robot robot;

private Dimension dim;

}

星期一, 三月 12, 2007

使用MIDPLogger进行在机调试

在进行手机蓝牙远程控制的开发中,需要通过蓝牙控制PC,这个过程无法在模拟器中实现。因此,需要在实际手机上进行调试。比较简单的方式就是通过日志的方式,如下实现:
/*
* GUILogger.java
*
* Created on 2007年2月4日, 上午11:52
*
* To change this template, choose Tools Template Manager
* and open the template in the editor.
*/
package wang.mobile.guanpai;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.MIDlet;

/**
*
* @author Xiaofeng Wang
*/
public class GUILogger implements CommandListener {
private GuanpaiGame parent;
private Form loggerForm;
private Displayable preForm;
private int level;

public final static int DEBUG = 0;
public final static int INFO = 1;

private final Command BACK_CMD = new Command("返回", Command.BACK, 0);

/**
* Creates a new instance of GUILogger
*/
public GUILogger(GuanpaiGame parent, int level) {
this.parent = parent;
this.level = level;

loggerForm = new Form("跟踪日志");
loggerForm.addCommand(BACK_CMD);
loggerForm.setCommandListener(this);
}
public void setLevel(int level) {
this.level = level;
}

public synchronized void log(String message, int level) {
if (level >= this.level) {
switch (level) {
case DEBUG:
loggerForm.append("DEBUG:" + message + "\n");
break;
case INFO:
loggerForm.append("INFO:" + message + "\n");
break;
default:
loggerForm.append("未定义的日志类型\n");
break;
}
}
}

public void showLoggerUI() {
preForm = parent.getDisplay().getCurrent();
parent.getDisplay().setCurrent(loggerForm);
}
public void commandAction(Command command, Displayable displayable) {
if (command == BACK_CMD) {
parent.getDisplay().setCurrent(preForm);
return;
}
}
}

看到Series40...上推荐的是MIDPLogger,别人做好的包,其实自己做个也很简单。
使用也很简单:

  1. 将文件MIDPLogger,MIDPLogViewer导入你的项目
  2. 调用代码如下:

// 新建

public class MyMidlet extends MIDlet {

public static MIDPLogger logger;

protected void startApp() {

try {

logger = new MIDPLogger(MIDPLogger.DEBUG, false,true);

}catch(Exception ex) {

ex.printStackTrace();

}

protected void destroyApp(boolean unconditional) {

logger.close();
}

}

// 记录日志

MyMidlet.logger.write("log message", MIDPLogger.DEBUG);

3. 通过MIDPLogViewer,察看日志。

星期日, 三月 11, 2007

在测试MIDlet时需要考虑的一些重要方面

在测试MIDlet时需要考虑的一些重要方面:
  • 即使运行环境发生改变(如网络连接断开),MIDlet也应该能够正常工作。它应该恰当地处理产生的错误,或者把这些错误用容易理解的消息呈现给用户。
  • 当不再使用网络时,关闭网络连接。
  • 蓝牙设备和服务搜索应该高效的。如果可行,就采用有限查询访问码(LIAC,Limited Inquiry Access Code)来加速搜寻过程。当长时间不使用蓝牙连接时,应该关闭蓝牙连接。
  • 在RMS操作中,当改写重要数据时,就要通知用户。
  • 应用程序的所有主要功能可以轻松地通过主菜单来访问。
  • 每一项功能都像文档中和应用程序的操作说明部分所描述的那样工作。
  • 每个屏幕只在一段时间内显示,这段时间是阅读信息所必需的时间。
  • 需要在整个应用程序中维持以下这些特性的一致性:术语、布局、颜色(或反色)、软键标签、振动和声音。
  • 菜单按逻辑分组,并且菜单结构的分级不能太深。
  • 可以从主菜单中退出应用程序。
  • 软键标签反映了特殊开发人员平台的用户接口的样式。
  • 与右软键相关联的标签指向返回、放弃、退出、取消、清除或其他“否定/后退”的功能。
  • 中间软键只有肯定的功能性命令。
  • 用户下一步最有可能执行的操作(命令的最高优先级)要映射到中间软键。
  • 每个声音都有独特的含义。
  • 声音的设置不能影响应用程序的使用。

--摘自《Series 40 可扩展应用程序开发》

星期五, 三月 09, 2007

蓝牙技术评介[转]

摘要: 本文对蓝牙技术作了扼要介绍,对蓝牙存在问题作了评论。

一、 蓝牙技术简介

1、 市场目标"今天的因特网可将全世界的计算机连接起来,明天的蓝牙技术可将全世界的信息家电连接起来"。正是这种人类无穷尽的信息欲,使近年来兴起的蓝牙技术在信息界掀起阵阵热潮,企业界普遍认为,又有一个经济增长热点来临了。

所谓蓝牙,实际上就是一种短距离(10~100米)的无线连接技术,把一种微型、廉价的通信模块嵌入各类信息设备中,实现这些设备的无线互联,而不用电缆。它可实现语音、数据无线传输及进入网络。它采用全世界统一的开放性规范,使不同厂家的移动电话、计算机、信息家电互联互通成为可能。这些基本要求如能实现,蓝牙产品将会在许多领域得到应用,会有巨大的市场。

以下是蓝牙的几种典型应用:

(1) 产品把手机、笔记本电脑、打印机、电话机、摄像机、投影机等办公设备用无线方式互联互通,成为一个室内移动办公室。

(2) 国际统一标准的蓝牙产品可把手机、电脑与电话网、综合业务网、ADSL、蜂窝移动网等通信网高速连接,可与LAN、WAN、Internet等计算机网互联,实现网上浏览、资源共享及各种电子业务。

(3) 可把彩色电视、音响、灯光控制设备、微波炉、电冰箱、洗衣机等各种信息家电采用不用电缆的无线连接或遥控监视。

随着蓝牙技术的发展,蓝牙产品不断进入市场,据资料介绍,2000年全球销售为3670万美元,2001年可望达到1.26亿美元,2006年为7亿美元,到2002年可望有1.5亿台信息家电嵌入蓝牙,2005年达到6.7亿台。

2. 发展及现状

环绕建立通用的无线接口、开放性的控制软件两大基本技术目标,蓝牙技术的发展及现状大致如下:

1994年,瑞典Ericsson公司推出蓝牙技术开发计划,其目的是解决移动电话周边设备的无线连接问题。

1997年,Nokia、Intel、IBM和东芝公司加入蓝牙技术开发研究。

1998年,上述五大公司倡导成立蓝牙技术特别兴趣小组,简称SIG。开始系统性研究不需要电缆连接各类信息终端的技术,包括负责制定开放性技术规范,决定专利可向产业界无偿转让。小组成立后,其中有许多是通信、计算机、消费电子产品的知名大企业。蓝牙技术已成为受到工业界广泛支持和关心的技术。全球统一技术规范的原则被确认。

1999年,SIG公布了第一版蓝牙技术规范。

2000年,一些生产手机、计算机的企业宣布它们的一些产品支持蓝牙。如:2000年9月,MOTOROLA公司推出可用于移动电话的蓝牙产品。

同月,东芝美国信息系统公司推出蓝牙PC卡。

同月,MOTOROLA公司宣布它的蓝牙PC卡和USB适配器接受ABI全面认证。

10月,英国Red-M公司推出蓝牙接入服务器,可提供PC机、电话、PDA和WAP实现移动接入,推出第一个蓝牙无线局域网产品。

2000年10月,GCT公司推出第一片蓝牙无线芯片GDM1100。2000年5月,瑞典爱立信公司进行首次蓝牙技术接入系统试验。

2000年10月,Silicom Wave公司宣布它的无线Modem IC第一个得到蓝牙认证。

2001年初,安捷伦、泰瑞达等公司陆续推出可对射频模块与蓝牙芯片进行测试的设备。目前蓝牙部分产品已在许多国家取得了"型号认可",蓝牙模块目前要用3块芯片,价格为8美元,很快将被压缩为一块芯片,价格降到5美元或更低,企业界希望几年后,手机、PC机、音响、TV、微波炉、电冰箱、灯控设备等信息家电能广泛应用蓝牙技术。