您的位置:首页 > 其它

如何使用 LumaQQ 核心 API

2008-01-16 18:39 501 查看

如何使用 LumaQQ 核心 API

第2部分:处理QQ事件

摘要
在第1部分中,我向你演示了一个最简单的QQ程序,在那个程序里,我使用了Thread.sleep()这样的方式来等待操作的完成,显然这种方式只能拿来做演示,在本部分中,我会更进一步,为你介绍LumaQQ中的事件处理方法,并且会实现一个LumaQQ Applet,于是你在网页里面也可以使用LumaQQ了。
Luma,清华大学
更新时间:2005/03/13

由于QQ的操作需要一定的时间,因为我们不能再继续用Thread.sleep()去傻等了,LumaQQ自身的异步事件机制可以让你获知一个操作何时成功,何时失败,然后再做出相应的处理。通过学习本部分,你基本上就可以用LumaQQ核心API去实现你自己的QQ程序了,你可以在你能想到的情况下使用它们,比如Applet,那么我们今天的Demo就给你奉献一个LumaQQ Applet,以便你加深了解。Demo的代码可以通过CVS获得,其位于edu.tsinghua.lumaqq.demo.demo2包中。

概述

LumaQQ定义了很多QQ的事件常量,它们都包含在QQEvent类中,为了监听QQ事件,你必须实现IQQListener接口,QQClient类有一个addIQQListener()方法,可以让你添加自己的IQQListener。而IQQListener只包含了一个方法qqEvent(),所以你需要使用条件判断来筛选出自己想处理的事件。对于这些概念,实在是相当简单,无需多言,就让我们开始一步步实现一个Applet吧。

第1步:创建Applet子类

关于Applet的概念,如果你不了解,可以先找些资料看看,我不会在此多废话。下面是我们的类声明:
public class Demo2 extends JApplet implements IQQListener {
...
}

我们继承了JApplet,更重要的是,我们声明自己的Applet会实现IQQListener接口。对于Applet的界面代码,我就不详细列出了,运行起来之后,这个Applet有如下的界面:



图1. Applet界面
为了发送一条消息,你必须提供你的QQ号,你的密码,和消息接收者的QQ号。消息可以在第四个文本框中输入,要发送时,点击Send按钮即可。在最底部,还有一个提示标签,在某个事件发生后,将会设置提示信息,这是为了向你更好的演示事件处理的功能。

第2步:为按钮加上监听器

很显然,我们需要给Send按钮加上一个监听器,如下:
btnSend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send();
}
});

那么我们看到,按钮按下时,我们调用了send()方法,这个方法的代码如下:
protected void send() {
// 得到所有参数
int yourQQ = 0;
try {
yourQQ = Integer.parseInt(textQQ.getText());
friendQQ = Integer.parseInt(textFriendQQ.getText());
} catch (NumberFormatException e) {
lblHint.setText("The format of QQ number is invalid.");
return;
}
String yourPassword = textPassword.getText();

// 开始创建各种对象,登录,然后发送消息,登出,注意我们不再使用sleep来等待操作完成
// 创建QQClient和QQUser
client = new QQClient();
QQUser user = new QQUser(yourQQ, yourPassword);
// 把自己添加成为IQQListener
client.addIQQListener(this);
// 设置参数
user.setUdp(true);
client.setUser(user);
client.setLoginServer("sz.tencent.com");
client.setAutoGetFriend(false);
try {
// 登录
lblHint.setText("Logining...");
client.login();
} catch (Exception e1) {
e1.printStackTrace();
}
}

send()方法的一开始,我们先把参数得到,这没有什么可说的。得到参数后,我们开始创建各种对象,然后登录,这里和第1部分的Demo有两处不同,首先,我把Applet做为一个IQQListener添加到了QQClient中,其次,send()方法只运行到login()为止,而且没有包含任何Thread.sleep()。很显然,在登录成功之前,我们无法做任何事,所以send()只能到这里为止,由于我们已经注册了IQQListener,现在我们就可以来实现事件处理的代码了。

第3步:实现IQQListener

理所当然的,我们首先想到的就是处理登录成功事件,所以,我们可以这样来实现qqEvent方法:
public void qqEvent(QQEvent e) {
switch(e.type) {
case QQEvent.QQ_LOGIN_SUCCESS:
processLoginSuccess();
break;
}
}

登录成功事件对应的常量为QQ_LOGIN_SUCCESS,如果你想看看都有哪些事件可以用,可以看看QQEvent的代码,里面的常量名意义都是明显的,我想你应该会明白。QQEvent类有一个type字段说明了事件的类型,我们判断type的值就可以了,这应该是非常的简单明了吧。在这里,我们声明了processLoginSuccess()方法来处理登录成功事件,出于演示的目的,这些事件处理函数都是非常的简单,一般只是设置一下提示信息:
private void processLoginSuccess() {
if(!client.getUser().isLoggedIn()) {
lblHint.setText("Login successful, wait for status changed...");
}
}

应该很好理解,我判断现在的状态是否是已登录,然后显示一条提示信息,如果登录成功的话,界面就是这样子:



图2. 登录成功后的提示信息
不过你可能会奇怪,为什么没有开始发送消息,而是说等待什么状态改变,这是因为QQ并不是登录了之后就可以发消息,而是要把自己的上线状态设置了之后才能发送消息。所以,我们这里还要等待状态设置完成,这个你不用担心,设置状态是LumaQQ核心层自动完成的,你只需要监听状态完成的事件就可以了。于是我们要加一个事件:
public void qqEvent(QQEvent e) {
switch(e.type) {
case QQEvent.QQ_LOGIN_SUCCESS:
processLoginSuccess();
break;
case QQEvent.QQ_CHANGE_STATUS_SUCCESS:
processChangeStatusSuccess();
break;
}
}

我们添加了QQ_CHANGE_STATUS_SUCCESS事件,它的处理方法如下:
private void processChangeStatusSuccess() {
lblHint.setText("Status changes successful, begin sending message...");
client.sendMessage(textMessage.getText(), friendQQ, "宋体");
}

由于在状态设置成功之后我们才能发消息,所以发送消息的代码被放到了这个方法里,很简单吧?我实在是想不出有什么可解释的,这还看不明白就惨了。接下来,我们要在消息发送成功之后登出。所以,我们再加一个事件:
public void qqEvent(QQEvent e) {
switch(e.type) {
case QQEvent.QQ_LOGIN_SUCCESS:
processLoginSuccess();
break;
case QQEvent.QQ_SEND_IM_SUCCESS:
processSendIMSuccess();
break;
case QQEvent.QQ_CHANGE_STATUS_SUCCESS:
processChangeStatusSuccess();
break;
}
}

processSendIMSuccess()的代码如下:
private void processSendIMSuccess() {
lblHint.setText("Message is sent successfully, client now logout.");
client.logout();
}

如此,我们在发送成功之后,就退出登录了,于是系统又回到了起点,你可以继续发送其他消息了。

第4步:差错处理

做完了前三步其实也够了,但是你如果要把你的软件拿给别人用,那就还远远不够,差错处理对于产品来说是非常重要的,LumaQQ不仅定义了成功的事件,也照样定义了失败的事件,所以,我们需要加上对登录失败的处理,加上对状态设置失败的处理,加上发送消息失败的处理,尤其是登录失败的处理,其又有很多情况,呵呵,所以,我们最终的qqEvent()方法是这样的:
public void qqEvent(QQEvent e) {
switch(e.type) {
case QQEvent.QQ_LOGIN_SUCCESS:
processLoginSuccess();
break;
case QQEvent.QQ_LOGIN_PASSWROD_ERROR:
processLoginPasswordError();
break;
case QQEvent.QQ_LOGIN_UNKNOWN_ERROR:
processLoginUnknownError();
break;
case QQEvent.QQ_SEND_IM_SUCCESS:
processSendIMSuccess();
break;
case QQEvent.QQ_CHANGE_STATUS_SUCCESS:
processChangeStatusSuccess();
break;
case QQEvent.QQ_CHANGE_STATUS_FAIL:
processChangeStatusFail();
break;
case QQEvent.QQ_OPERATION_TIMEOUT:
if(e.operation == QQ.QQ_CMD_SEND_IM)
processSendIMFail();
break;
}
}

我们又添加了4个事件(黑体部分)来处理错误,当然,我们这里的错误处理都很简单,就是打印一条消息而已:
private void processLoginPasswordError() {
lblHint.setText("Password error, login failed!");
}
private void processLoginUnknownError() {
lblHint.setText("Unknown error, login failed!");
}
private void processChangeStatusFail() {
lblHint.setText("Failed to change status, message can't be sent, client is logout");
client.logout();
}
private void processSendIMFail() {
lblHint.setText("Failed to send message, client now logout.");
client.logout();
}

只是在后面两个方法中,我们还要调用一下logout(),前面两个是处理登录错误的,我们不需要调用logout(),因为那个时候肯定没有登录成功。这些方法都简单易懂,不过对于发送消息失败的处理稍微有点不一样,我们并没有添加什么QQ_SEND_IM_FAIL事件,事实上,这个事件也不存在,我们添加的是QQ_OPERATION_TIMEOUT事件,然后再去判断到底是什么操作超时了。为什么呢? 因为服务器并不会为发送消息返回一个什么应答码来告诉你发送失败了(至少在目前已知的协议中是不会的),所以,消息只有可能发不出去,也就是超时。当然,有些操作即可能超时,也可能是失败,那你就要处理两个情况了。

总结

如此如此,是不是还是很简单呢?当然了,实际的事件数非常之多,我这个Demo才处理了7个而已,如果你真要实现一个很完善的客户端,那确实是非常繁琐的。今天我们就说到这里,如果我想起还有什么要告诉你的,就写第三部分吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: