天天看点

Azureus源码剖析(五)

 这篇说说GUI方面,就以打开种子文件这个窗口为例,我对其代码进行了精简,拿出了一个基本的骨架。

首先来看基本的消息主循环部分:

复制代码

    final Display display = new Display();

        invoke(null);//创建窗口的主代码

        while (stTorrentWindow != null && !stTorrentWindow.bClosed)

        {//窗口创建完成且没有关闭

            if (!display.readAndDispatch())

            {

                display.sleep();

            }

        }

        display.dispose();

这里运用了单例模式来表示窗口,考虑到线程同步性,在静态工厂方法中使用了synchronized 关键字

private static TorrentWindow stTorrentWindow = null;

    public synchronized static final void invoke(Shell parent)

    {

        if (stTorrentWindow == null)

        {//第一次创建窗口

            stTorrentWindow = new TorrentWindow(parent);

        else

        {//激活已经创建的窗口

            if (stTorrentWindow.shell != null)

                stTorrentWindow.shell.forceActive();

    }

    private TorrentWindow(final Shell parent)

        openWindow(parent);

      真正的窗口创建工作是在openWindow方法中完成的,下面给出部分核心代码:

private void openWindow(Shell parent)

        GridData gridData;

        shell = ShellFactory.createShell(parent, SWT.RESIZE | SWT.DIALOG_TRIM);

        shell.setText("打开 Torrent");

        GridLayout layout = new GridLayout();

        shell.setLayout(layout);

        shell.addListener(SWT.Resize, new Listener()

        {

            public void handleEvent(Event e) {

        });

        // Torrents

        // ========

        Composite cButtons = new Composite(shell, SWT.NONE);

        RowLayout rLayout = new RowLayout(SWT.HORIZONTAL);

        rLayout.marginBottom = 0;

        rLayout.marginLeft = 0;

        rLayout.marginRight = 0;

        rLayout.marginTop = 0;

        cButtons.setLayout(rLayout);

        // Buttons for tableTorrents

        Button browseTorrent = new Button(cButtons, SWT.PUSH);

        browseTorrent.setText("添加文件");

        browseTorrent.addListener(SWT.Selection, new Listener(){

            public void handleEvent(Event arg0) {

                FileDialog fDialog = new FileDialog(shell, SWT.OPEN | SWT.MULTI);

                fDialog.setFilterExtensions(new String[]{

                        "*.torrent",

                        "*.tor",

                        FILE_WILDCARD

                });

                fDialog.setFilterNames(new String[]{

                fDialog.setText("选择 Torrent文件");

                String fileName = fDialog.open();

                if (fileName != null)

                {

                    //addTorrents(fDialog.getFilterPath(), fDialog.getFileNames());

                }

        setGridData(cButtons, GridData.FILL_HORIZONTAL, browseTorrent, MIN_BUTTON_HEIGHT);

        Button browseURL = new Button(cButtons, SWT.PUSH);

        browseURL.setText("从URL添加");

        browseURL.addListener(SWT.Selection, new Listener(){

                browseURL();

        Button browseFolder = new Button(cButtons, SWT.PUSH);

        browseFolder.setText("从文件夹添加");

        browseFolder.addListener(SWT.Selection, new Listener(){

            public void handleEvent(Event e)

                DirectoryDialog fDialog = new DirectoryDialog(shell, SWT.NULL);

                fDialog.setMessage("选择 Torrent 文件所在目录");

                String path = fDialog.open();

                if (path != null)

                    addTorrents(path, null);

        Group gTorrentsArea = new Group(shell, SWT.NONE);

        gridData = new GridData(GridData.FILL_HORIZONTAL);

        gTorrentsArea.setLayoutData(gridData);

        layout = new GridLayout();

        gTorrentsArea.setLayout(layout);

        gTorrentsArea.setText("Torrent文件");

        Composite cTorrentList = new Composite(gTorrentsArea, SWT.NONE);

        cTorrentList.setLayoutData(gridData);

        createTorrentListArea(cTorrentList);

        //关闭窗口

        shell.addDisposeListener(new DisposeListener() 

            public void widgetDisposed(DisposeEvent e)

                if (!bClosed)

                    close(false, true);

        shell.addListener(SWT.Traverse, new Listener() 

            public void handleEvent(Event e) 

                if (e.detail == SWT.TRAVERSE_ESCAPE) 

                    close(true, true);

        shell.open();//显示窗口

这里最重要的如何创建Shell的:

shell = ShellFactory.createShell(parent, SWT.RESIZE | SWT.DIALOG_TRIM);

下面就来看看ShellFactory的代码,主要是在ShellManager中加入新创建的Shell,如果此Shell已经创建过,则不再次加入

public final class ShellFactory 

{

    public static Shell createShell(final Shell parent, final int styles)

        return getRegistedShell(new Shell(parent, styles));

    private static Shell getRegistedShell(final Shell toRegister)

        if (null == toRegister)

            return null;

        ShellManager.sharedManager().addWindow(toRegister);

        return toRegister;

}

      最后来看ShellManager是如何管理Shell的:

public class ShellManager

    private static ShellManager instance;

    private final Collection shells = new ArrayList();//被管理的Shell

    private final List addHandlers = new LinkedList();//加入Shell时调用

    private final List removeHandlers = new LinkedList();//删除Shell时调用

    static

        instance = new ShellManager();

    /**

     * <p>Gets the application's shared shell manager</p>

     * <p>This ShellManager has no bearing on other ShellManager instances</p>

     * <p><b>Note</b>: This method must be invoked by the SWT display thread</p>

     * @return

     */

    public static final ShellManager sharedManager()

    {//静态工厂方法

        return instance;

    public static boolean verifyShellRect(Shell shell, boolean bAdjustIfInvalid) 

    {//验证窗口矩阵的合法性

        boolean bMetricsOk;

        try {

            bMetricsOk = false;

            Point ptTopLeft = shell.getLocation();

            Monitor[] monitors = shell.getDisplay().getMonitors();

            for (int j = 0; j < monitors.length && !bMetricsOk; j++) {

                Rectangle bounds = monitors[j].getBounds();

                bMetricsOk = bounds.contains(ptTopLeft);

        } catch (NoSuchMethodError e) {

            Rectangle bounds = shell.getDisplay().getBounds();

            bMetricsOk = shell.getBounds().intersects(bounds);

        if (!bMetricsOk && bAdjustIfInvalid) {

            centreWindow(shell);

        return bMetricsOk;

    public static void centreWindow(Shell shell)

    {//窗口居中

        Rectangle displayArea; // area to center in

            displayArea = shell.getMonitor().getClientArea();

            displayArea = shell.getDisplay().getClientArea();

        Rectangle shellRect = shell.getBounds();

        if (shellRect.height > displayArea.height) {

            shellRect.height = displayArea.height;

        if (shellRect.width > displayArea.width - 50) {

            shellRect.width = displayArea.width;

        shellRect.x = displayArea.x + (displayArea.width - shellRect.width) / 2;

        shellRect.y = displayArea.y + (displayArea.height - shellRect.height) / 2;

        shell.setBounds(shellRect);

     * Adds a shell to the shell manager. If the shell is already managed, it is not added again.

     * @param shell A SWT Shell

    public final void addWindow(final Shell shell)

    {//加入新窗口

        //Debug.out("Invoked by thread " + Thread.currentThread().getName());

        if(shells.contains(shell)) {return;}

        shells.add(shell);

        notifyAddListeners(shell);

        shell.addDisposeListener(new DisposeListener()

            public void widgetDisposed(DisposeEvent event)

                try 

                    removeWindow(shell);

                } 

                catch (Exception e)

                    //Logger.log(new LogEvent(LogIDs.GUI, "removeWindow", e));

        shell.addListener(SWT.Show, new Listener() 

            public void handleEvent(Event event) 

                verifyShellRect(shell, false);

     * Removes a shell from the shell manager

    public final void removeWindow(Shell shell)

    {//删除窗口

        shells.remove(shell);

        notifyRemoveListeners(shell);

     * <p>Gets the shells managed by the manager as an Iterator</p>

     * <p>The order in which the shells were added are retained.</p>

     * @return The iterator

    public final Iterator getWindows()

        return shells.iterator();

     * Gets whether the ShellManager manages no shells

     * @return True if ShellManager is empty

    public final boolean isEmpty()

        return shells.isEmpty();

     * Gets the number of shells the ShellManager manages

     * @return The number

    public final int getSize()

        return shells.size();

     * <p>Invokes the handleEvent method specified by the SWT listener for each managed shell</p>

     * <p>The event's widget is set to the reference of the shell invoking it</p>

     * @param command A command implemented as a SWT Listener

    public final void performForShells(final Listener command)

        Iterator iter = shells.iterator();

        for(int i = 0; i < shells.size(); i++)

            Shell aShell = (Shell)iter.next();

            Event evt = new Event();

            evt.widget = aShell;

            evt.data = this;

            command.handleEvent(evt);

     * Gets the set of managed shells

     * @return The set

    protected final Collection getManagedShellSet()

        return shells;

    // events

     * <p>Adds a listener that will be invoked when a shell has been added to the ShellManager</p>

     * <p>The listener and the shell will automatically be removed when the shell is disposed</p>

     * @param listener A SWT Listener

    public final void addWindowAddedListener(Listener listener)

        addHandlers.add(listener);

     * Removes a listener that will be invoked when a shell has been added to the ShellManager

    public final void removeWindowAddedListener(Listener listener)

        addHandlers.remove(listener);

     * Adds a listener that will be invoked when a shell has been removed from the ShellManager

    public final void addWindowRemovedListener(Listener listener)

        removeHandlers.add(listener);

     * Removes a listener that will be invoked when a shell has been removed from the ShellManager

    public final void removeWindowRemovedListener(Listener listener)

        removeHandlers.remove(listener);

     * Notifies the WindowAddedListener handlers

     * @param sender A SWT shell that "sends" the events

    protected final void notifyAddListeners(Shell sender)

        Iterator iter = addHandlers.iterator();

        for(int i = 0; i < addHandlers.size(); i++)

            ((Listener)iter.next()).handleEvent(getSWTEvent(sender));

     * Notifies the WindowRemovedListener handlers

    protected final void notifyRemoveListeners(Shell sender)

        Iterator iter = removeHandlers.iterator();

        for(int i = 0; i < removeHandlers.size(); i++)

     * <p>Gets a generated SWT Event based on the shell</p>

     * <p>The widget field of the event should be set to the shell</p>

     * @return The event

    protected Event getSWTEvent(Shell shell)

        Event e = new Event();

        e.widget = shell;

        e.item = shell;

        return e;

本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2009/05/13/1455756.html,如需转载请自行联系原作者