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[]{
                        "*.torrent",
                        "*.tor",
                        FILE_WILDCARD
                });
                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(){
            public void handleEvent(Event e) {
                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);
        gridData = new GridData(GridData.FILL_HORIZONTAL);
        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
        try {
            displayArea = shell.getMonitor().getClientArea();
        } catch (NoSuchMethodError e) {
            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.
     * <p><b>Note</b>: This method must be invoked by the SWT display thread</p>
     * @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
     * <p><b>Note</b>: This method must be invoked by the SWT display thread</p>
     * @param shell A SWT Shell
     */
    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>
     * <p><b>Note</b>: This method must be invoked by the SWT display thread</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
     * @param listener A SWT Listener
     */
    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
     * @param listener A SWT Listener
     */
    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
     * @param listener A SWT Listener
     */
    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
     * @param sender A SWT shell that "sends" the events
     */
    protected final void notifyRemoveListeners(Shell sender)
    {
        Iterator iter = removeHandlers.iterator();
        for(int i = 0; i < removeHandlers.size(); i++)
        {
            ((Listener)iter.next()).handleEvent(getSWTEvent(sender));
        }
    }
    /**
     * <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>
     * @param shell A SWT Shell
     * @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,如需转载请自行联系原作者

目录
相关文章
|
6月前
AQS源码解读之一
AQS源码解读之一
23 0
|
9月前
|
存储 机器学习/深度学习 算法
源码剖析之ConcurrentHashMap
​ JDK8中ConcurrentHashMap的结构是:数组+链表+红黑树。 ​ 因为在hash冲突严重的情况下,链表的查询效率是O(n),所以jdk8中改成了单个链表的个数大于8时,数组长度小于64就扩容,数组长度大于等于64,则链表会转换为红黑树,这样以空间换时间,查询效率会变O(nlogn)。 ​ 红黑树在Node数组内部存储的不是一个TreeNode对象,而是一个TreeBin对象,TreeBin内部维持着一个红黑树。 ​ 在JDK8中ConcurrentHashMap最经点的实现是使用CAS+synchronized+volatile 来保证并发安全
82 0
源码剖析之ConcurrentHashMap
|
存储 Java
并发编程(十)线程池核心原理与源码剖析
并发编程(十)线程池核心原理与源码剖析
81 0
|
Java 开发者
手撕源码!线程池核心组件源码剖析
看源码之前,先了解一下该组件 最主要的几个 接口、抽象类和实现类的结构关系。
134 0
手撕源码!线程池核心组件源码剖析