需要以下的对象:
LoginDialog,用于展示状态,
LoginListener,用于监听登录状态,并根据不同的情况改变LoginDialog的显示
LoginAction,用于执行登录的业务逻辑,并且根据不同的结果来fire不同的动作。
状态一共有以下几种:
1。登录中
2。登录成功
3。登录失败
3.1 连接失败
3.2 用户名密码错误
3.3 .....
4。用户取消登录
下面是代码片段:
Application;
public class Application implements IPlatformRunnable {
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IPlatformRunnable#run(java.lang.Object)
*/
public Object run(Object args) throws Exception {
try {
TestLoginDialog dialog = new TestLoginDialog(Display.getCurrent()
.getActiveShell());
LoginListener loginListener = new LoginListenerImpl(dialog);
LoginAction action = new LoginAction("login");
action.addLoginListener(loginListener);
dialog.setLoginAction(action);
if (dialog.open() != Window.OK) {
return IPlatformRunnable.EXIT_OK;
}
int returnCode = PlatformUI.createAndRunWorkbench(display,
new ApplicationWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART) {
return IPlatformRunnable.EXIT_RESTART;
}
return IPlatformRunnable.EXIT_OK;
} finally {
display.dispose();
}
}
}
LoginListener:
public interface LoginListener extends EventListener{
public void loginError(String message);
public void loginComplete();
public void loginCanceled();
public void loginStarted();
}
LoginAction:这里要用到Job,因为登录的逻辑处理必须要在异步线程中来做,否则UI就会停住的。
public class LoginAction extends Job {
private LoginListener loginListener;
private Session session = Session.getInstance();
public LoginAction(String name) {
super(name);
}
public void addLoginListener(LoginListener listener) {
this.loginListener = listener;
}
public void fireLoginComplete() {
loginListener.loginComplete();
}
public void fireLoginStarted() {
loginListener.loginStarted();
}
public void fireLoginError(String message) {
loginListener.loginError(message);
}
public void fireLoginCanceled() {
//write cancel login logic here
loginListener.loginCanceled();
}
@Override
protected IStatus run(IProgressMonitor monitor) {
login();
return Status.OK_STATUS;
}
public boolean login() {
fireLoginStarted();
if (//网络连接失败) {
fireLoginError(Messages.getString("Session.connectionFailed"));
} else {
if (//登录失败) {
fireLoginError(Messages.getString("Session.loginFailed"));
} else {
session.setAuthenticated(true);
fireLoginComplete();
//处理登录动作
}
}
return session.isAuthenticated();
}
}
LoginDialog:
这里用到了StackLayout,因为在登录的过程中,需要在显示用户名/密码的位置上,显示gif动画,所以在createDialogArea的时候,要创建一个主Composite,然后将其layout设置为StackLayout,然后创建两个Composite,将其parent都设置为主Composite,新创建的两个我将其命名为loginInfoComposite和loginAnimaComposite,顾名思义,一个用来显示登录信息,一个用来显示登录动画。
关于如何显示gif,我在这里就不多说了,因为SWT Snippet和Eclipse的SWT Example里面都有对应的例子,我在这里推荐大家去参考一下SWT Example,因为那里面是用Canvas来绘图的,这也是我们所需要的。
在使用StackLayout的时候要注意,当我们使用stackLayout.topControl = xxx的时候,还要调用stackLayout.layout()方法,否则会不起作用。
还有就是因为在登录的过程中,按钮栏应该是不可见的,但是Dialog的getButtonBar方法是protected的,所以就重写了这个方法,声明为public,返回super.getButtonBar(),虽然源码的注释中写着这个方法不应该重写,但是我想,这样子应该没问题吧。
另外,在绘制gif的下方添加一个按钮,并且addSelectionListener,当SelectionEvent发生的时候,就去触发loginAction的fireCancel方法就可以了。
细节就不描述了,下面是一些个人认为比较关键的代码片段:
/*
* to create login button
*/
public static int LOGIN_ID = 9527;
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, LOGIN_ID, Messages
.getString("LoginDialog.loginbutton"), true); ]
createButton(parent, IDialogConstants.CANCEL_ID, Messages
.getString("LoginDialog.cancelbutton"), false);
}
@Override
protected void buttonPressed(int buttonId) {
if (buttonId == LOGIN_ID) {
loginPressed();
}
super.buttonPressed(buttonId);
}
protected void loginPressed() {
//...
loginAction.schedule();
}
然后是LoginListener的实现类:
public class LoginListenerImpl implements LoginListener {
private Display display;
//login dialog
private TestLoginDialog dialog;
//image to show on login failed
private Image errorMessageImage = AbstractUIPlugin
.imageDescriptorFromPlugin(Application.PLUGIN_ID,
IImageKeys.crodoTitleImage).createImage();
//error message area background
private Color errorMessageBackground = new Color(null, 255, 255, 0);
public LoginListenerImpl(TestLoginDialog dialog) {
this.dialog = dialog;
display = Display.getCurrent();
}
//因为这里需要在非UI线程中更新UI,所以要用display.syncExec()方法。
public void loginCanceled() {
display.syncExec(new Runnable() {
public void run() {
dialog.getStackLayout().topControl = dialog
.getLoginInfoComposite();
dialog.getStackLayoutComposite().layout();
dialog.animate();
dialog.getButtonBar().setVisible(true);
}
});
}
public void loginComplete() {
display.syncExec(new Runnable() {
@SuppressWarnings("deprecation")
public void run() {
//我知道Thread.stop()方法已经被废弃,但是暂时没想到什么方法来中止
//就暂时这样子用了,还请大家指教!
dialog.getAnimateThread().stop();
dialog.okPressed();
}
});
}
public void loginError(final String message) {
display.syncExec(new Runnable() {
public void run() {
dialog.getErrorMessageLabel().setText(message);
dialog.getErrorMessageLabel().setImage(errorMessageImage);
dialog.getErrorMessageLabel().setBackground(
errorMessageBackground);
dialog.getStackLayout().topControl = dialog
.getLoginInfoComposite();
dialog.getStackLayoutComposite().layout();
dialog.animate();
dialog.getButtonBar().setVisible(true);
}
});
}
public void loginStarted() {
display.syncExec(new Runnable() {
public void run() {
dialog.getStackLayout().topControl = dialog
.getLoginAnimaComposite();
dialog.getStackLayoutComposite().layout();
dialog.animate();
dialog.getButtonBar().setVisible(false);
}
});
}