[rcp系列]用RCP實現MSN風格的登錄窗口 (轉)

需要以下的對象:
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(null2552550);

    
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);
            }
        });
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章