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

 

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

 
  1. final Display display = new Display();  
  2.      invoke(null);//创建窗口的主代码  
  3.    
  4.      while (stTorrentWindow != null && !stTorrentWindow.bClosed)  
  5.      {//窗口创建完成且没有关闭  
  6.          if (!display.readAndDispatch())  
  7.          {  
  8.              display.sleep();  
  9.          }  
  10.      }  
  11.      display.dispose();  

 

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

  1. private static TorrentWindow stTorrentWindow = null;  
  2.  
  3.     public synchronized static final void invoke(Shell parent)  
  4.     {  
  5.         if (stTorrentWindow == null)  
  6.         {//第一次创建窗口  
  7.             stTorrentWindow = new TorrentWindow(parent);  
  8.         }  
  9.         else 
  10.         {//激活已经创建的窗口  
  11.             if (stTorrentWindow.shell != null)  
  12.             {  
  13.                 stTorrentWindow.shell.forceActive();  
  14.             }  
  15.         }  
  16.     }  
  17.     private TorrentWindow(final Shell parent)  
  18.     {  
  19.         openWindow(parent);  
  20.     }  
  21.  
  22.    

 

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

  1. private void openWindow(Shell parent)  
  2.     {  
  3.         GridData gridData;  
  4.           
  5.         shell = ShellFactory.createShell(parent, SWT.RESIZE | SWT.DIALOG_TRIM);  
  6.         shell.setText("打开 Torrent");  
  7.           
  8.         GridLayout layout = new GridLayout();  
  9.         shell.setLayout(layout);  
  10.         shell.addListener(SWT.Resize, new Listener()  
  11.         {  
  12.             public void handleEvent(Event e) {  
  13.                       
  14.             }  
  15.         });  
  16.         // Torrents  
  17.         // ========  
  18.  
  19.         Composite cButtons = new Composite(shell, SWT.NONE);  
  20.         RowLayout rLayout = new RowLayout(SWT.HORIZONTAL);  
  21.         rLayout.marginBottom = 0;  
  22.         rLayout.marginLeft = 0;  
  23.         rLayout.marginRight = 0;  
  24.         rLayout.marginTop = 0;  
  25.         cButtons.setLayout(rLayout);  
  26.           
  27.         // Buttons for tableTorrents  
  28.         Button browseTorrent = new Button(cButtons, SWT.PUSH);  
  29.         browseTorrent.setText("添加文件");  
  30.         browseTorrent.addListener(SWT.Selection, new Listener(){  
  31.             public void handleEvent(Event arg0) {  
  32.                 FileDialog fDialog = new FileDialog(shell, SWT.OPEN | SWT.MULTI);  
  33.                 fDialog.setFilterExtensions(new String[]{  
  34.                         "*.torrent",  
  35.                         "*.tor",  
  36.                         FILE_WILDCARD  
  37.                 });  
  38.                 fDialog.setFilterNames(new String[]{  
  39.                         "*.torrent",  
  40.                         "*.tor",  
  41.                         FILE_WILDCARD  
  42.                 });  
  43.                 fDialog.setText("选择 Torrent文件");  
  44.                 String fileName = fDialog.open();  
  45.                 if (fileName != null)  
  46.                 {  
  47.                     //addTorrents(fDialog.getFilterPath(), fDialog.getFileNames());  
  48.                 }  
  49.             }  
  50.         });  
  51.         setGridData(cButtons, GridData.FILL_HORIZONTAL, browseTorrent, MIN_BUTTON_HEIGHT);  
  52.           
  53.         Button browseURL = new Button(cButtons, SWT.PUSH);  
  54.         browseURL.setText("从URL添加");  
  55.         browseURL.addListener(SWT.Selection, new Listener(){  
  56.             public void handleEvent(Event e) {  
  57.                 browseURL();  
  58.             }  
  59.         });  
  60.           
  61.         Button browseFolder = new Button(cButtons, SWT.PUSH);  
  62.         browseFolder.setText("从文件夹添加");  
  63.         browseFolder.addListener(SWT.Selection, new Listener(){  
  64.             public void handleEvent(Event e)  
  65.             {  
  66.                 DirectoryDialog fDialog = new DirectoryDialog(shell, SWT.NULL);  
  67.                 fDialog.setMessage("选择 Torrent 文件所在目录");  
  68.                 String path = fDialog.open();  
  69.                 if (path != null)  
  70.                 {  
  71.                     addTorrents(path, null);  
  72.                 }  
  73.             }  
  74.         });  
  75.           
  76.         Group gTorrentsArea = new Group(shell, SWT.NONE);  
  77.         gridData = new GridData(GridData.FILL_HORIZONTAL);  
  78.         gTorrentsArea.setLayoutData(gridData);  
  79.         layout = new GridLayout();  
  80.         gTorrentsArea.setLayout(layout);  
  81.         gTorrentsArea.setText("Torrent文件");  
  82.           
  83.         Composite cTorrentList = new Composite(gTorrentsArea, SWT.NONE);  
  84.         gridData = new GridData(GridData.FILL_HORIZONTAL);  
  85.         cTorrentList.setLayoutData(gridData);  
  86.         createTorrentListArea(cTorrentList);  
  87.         //关闭窗口  
  88.         shell.addDisposeListener(new DisposeListener()   
  89.         {  
  90.             public void widgetDisposed(DisposeEvent e)  
  91.             {  
  92.                 if (!bClosed)  
  93.                     close(falsetrue);  
  94.             }  
  95.         });  
  96.  
  97.         shell.addListener(SWT.Traverse, new Listener()   
  98.         {  
  99.             public void handleEvent(Event e)   
  100.             {  
  101.                 if (e.detail == SWT.TRAVERSE_ESCAPE)   
  102.                 {  
  103.                     close(truetrue);  
  104.                 }  
  105.             }  
  106.         });  
  107.         shell.open();//显示窗口  
  108.     }  

 

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

 

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

 

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

  1. public final class ShellFactory   
  2. {  
  3.     public static Shell createShell(final Shell parent, final int styles)  
  4.     {  
  5.         return getRegistedShell(new Shell(parent, styles));  
  6.     }  
  7.     private static Shell getRegistedShell(final Shell toRegister)  
  8.     {  
  9.         if (null == toRegister)  
  10.             return null;  
  11.         ShellManager.sharedManager().addWindow(toRegister);  
  12.         return toRegister;  
  13.     }  
  14. }  

 

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

 

  1.  
  2.  
  3. public class ShellManager  
  4. {  
  5.     private static ShellManager instance;  
  6.  
  7.     private final Collection shells = new ArrayList();//被管理的Shell  
  8.     private final List addHandlers = new LinkedList();//加入Shell时调用  
  9.     private final List removeHandlers = new LinkedList();//删除Shell时调用  
  10.  
  11.     static 
  12.     {  
  13.         instance = new ShellManager();  
  14.     }  
  15.  
  16.     /**  
  17.      * <p>Gets the application's shared shell manager</p>  
  18.      * <p>This ShellManager has no bearing on other ShellManager instances</p>  
  19.      * <p><b>Note</b>: This method must be invoked by the SWT display thread</p>  
  20.      * @return  
  21.      */ 
  22.     public static final ShellManager sharedManager()  
  23.     {//静态工厂方法  
  24.         return instance;  
  25.     }  
  26.  
  27.     public static boolean verifyShellRect(Shell shell, boolean bAdjustIfInvalid)   
  28.     {//验证窗口矩阵的合法性  
  29.         boolean bMetricsOk;  
  30.         try {  
  31.             bMetricsOk = false;  
  32.             Point ptTopLeft = shell.getLocation();  
  33.  
  34.             Monitor[] monitors = shell.getDisplay().getMonitors();  
  35.             for (int j = 0; j < monitors.length && !bMetricsOk; j++) {  
  36.                 Rectangle bounds = monitors[j].getBounds();  
  37.                 bMetricsOk = bounds.contains(ptTopLeft);  
  38.             }  
  39.         } catch (NoSuchMethodError e) {  
  40.             Rectangle bounds = shell.getDisplay().getBounds();  
  41.             bMetricsOk = shell.getBounds().intersects(bounds);  
  42.         }  
  43.         if (!bMetricsOk && bAdjustIfInvalid) {  
  44.             centreWindow(shell);  
  45.         }  
  46.         return bMetricsOk;  
  47.     }  
  48.       
  49.     public static void centreWindow(Shell shell)  
  50.     {//窗口居中  
  51.         Rectangle displayArea; // area to center in  
  52.         try {  
  53.             displayArea = shell.getMonitor().getClientArea();  
  54.         } catch (NoSuchMethodError e) {  
  55.             displayArea = shell.getDisplay().getClientArea();  
  56.         }  
  57.  
  58.         Rectangle shellRect = shell.getBounds();  
  59.  
  60.         if (shellRect.height > displayArea.height) {  
  61.             shellRect.height = displayArea.height;  
  62.         }  
  63.         if (shellRect.width > displayArea.width - 50) {  
  64.             shellRect.width = displayArea.width;  
  65.         }  
  66.  
  67.         shellRect.x = displayArea.x + (displayArea.width - shellRect.width) / 2;  
  68.         shellRect.y = displayArea.y + (displayArea.height - shellRect.height) / 2;  
  69.  
  70.         shell.setBounds(shellRect);  
  71.     }  
  72.     /**  
  73.      * Adds a shell to the shell manager. If the shell is already managed, it is not added again.  
  74.      * <p><b>Note</b>: This method must be invoked by the SWT display thread</p>  
  75.      * @param shell A SWT Shell  
  76.      */ 
  77.     public final void addWindow(final Shell shell)  
  78.     {//加入新窗口  
  79.         //Debug.out("Invoked by thread " + Thread.currentThread().getName());  
  80.         if(shells.contains(shell)) {return;}  
  81.  
  82.         shells.add(shell);  
  83.         notifyAddListeners(shell);  
  84.         shell.addDisposeListener(new DisposeListener()  
  85.         {  
  86.             public void widgetDisposed(DisposeEvent event)  
  87.             {  
  88.                 try   
  89.                 {  
  90.                     removeWindow(shell);  
  91.                 }   
  92.                 catch (Exception e)  
  93.                 {  
  94.                     //Logger.log(new LogEvent(LogIDs.GUI, "removeWindow", e));  
  95.                 }  
  96.             }  
  97.         });  
  98.         shell.addListener(SWT.Show, new Listener()   
  99.         {  
  100.             public void handleEvent(Event event)   
  101.             {  
  102.                 verifyShellRect(shell, false);  
  103.             }  
  104.         });  
  105.     }  
  106.  
  107.     /**  
  108.      * Removes a shell from the shell manager  
  109.      * <p><b>Note</b>: This method must be invoked by the SWT display thread</p>  
  110.      * @param shell A SWT Shell  
  111.      */ 
  112.     public final void removeWindow(Shell shell)  
  113.     {//删除窗口  
  114.         shells.remove(shell);  
  115.         notifyRemoveListeners(shell);  
  116.     }  
  117.  
  118.     /**  
  119.      * <p>Gets the shells managed by the manager as an Iterator</p>  
  120.      * <p>The order in which the shells were added are retained.</p>  
  121.      * <p><b>Note</b>: This method must be invoked by the SWT display thread</p>  
  122.      * @return The iterator  
  123.      */ 
  124.     public final Iterator getWindows()  
  125.     {  
  126.         return shells.iterator();  
  127.     }  
  128.  
  129.     /**  
  130.      * Gets whether the ShellManager manages no shells  
  131.      * @return True if ShellManager is empty  
  132.      */ 
  133.     public final boolean isEmpty()  
  134.     {  
  135.         return shells.isEmpty();  
  136.     }  
  137.  
  138.     /**  
  139.      * Gets the number of shells the ShellManager manages  
  140.      * @return The number  
  141.      */ 
  142.     public final int getSize()  
  143.     {  
  144.         return shells.size();  
  145.     }  
  146.  
  147.     /**  
  148.      * <p>Invokes the handleEvent method specified by the SWT listener for each managed shell</p>  
  149.      * <p>The event's widget is set to the reference of the shell invoking it</p>  
  150.      * @param command A command implemented as a SWT Listener  
  151.      */ 
  152.     public final void performForShells(final Listener command)  
  153.     {  
  154.         Iterator iter = shells.iterator();  
  155.         for(int i = 0; i < shells.size(); i++)  
  156.         {  
  157.             Shell aShell = (Shell)iter.next();  
  158.             Event evt = new Event();  
  159.             evt.widget = aShell;  
  160.             evt.data = this;  
  161.             command.handleEvent(evt);  
  162.         }  
  163.     }  
  164.  
  165.     /**  
  166.      * Gets the set of managed shells  
  167.      * @return The set  
  168.      */ 
  169.     protected final Collection getManagedShellSet()  
  170.     {  
  171.         return shells;  
  172.     }  
  173.  
  174.     // events  
  175.  
  176.     /**  
  177.      * <p>Adds a listener that will be invoked when a shell has been added to the ShellManager</p>  
  178.      * <p>The listener and the shell will automatically be removed when the shell is disposed</p>  
  179.      * @param listener A SWT Listener  
  180.      */ 
  181.     public final void addWindowAddedListener(Listener listener)  
  182.     {  
  183.         addHandlers.add(listener);  
  184.     }  
  185.  
  186.     /**  
  187.      * Removes a listener that will be invoked when a shell has been added to the ShellManager  
  188.      * @param listener A SWT Listener  
  189.      */ 
  190.     public final void removeWindowAddedListener(Listener listener)  
  191.     {  
  192.         addHandlers.remove(listener);  
  193.     }  
  194.  
  195.     /**  
  196.      * Adds a listener that will be invoked when a shell has been removed from the ShellManager  
  197.      * @param listener A SWT Listener  
  198.      */ 
  199.     public final void addWindowRemovedListener(Listener listener)  
  200.     {  
  201.         removeHandlers.add(listener);  
  202.     }  
  203.  
  204.     /**  
  205.      * Removes a listener that will be invoked when a shell has been removed from the ShellManager  
  206.      * @param listener A SWT Listener  
  207.      */ 
  208.     public final void removeWindowRemovedListener(Listener listener)  
  209.     {  
  210.         removeHandlers.remove(listener);  
  211.     }  
  212.  
  213.     /**  
  214.      * Notifies the WindowAddedListener handlers  
  215.      * @param sender A SWT shell that "sends" the events  
  216.      */ 
  217.     protected final void notifyAddListeners(Shell sender)  
  218.     {  
  219.         Iterator iter = addHandlers.iterator();  
  220.         for(int i = 0; i < addHandlers.size(); i++)  
  221.         {  
  222.             ((Listener)iter.next()).handleEvent(getSWTEvent(sender));  
  223.         }  
  224.     }  
  225.  
  226.     /**  
  227.      * Notifies the WindowRemovedListener handlers  
  228.      * @param sender A SWT shell that "sends" the events  
  229.      */ 
  230.     protected final void notifyRemoveListeners(Shell sender)  
  231.     {  
  232.         Iterator iter = removeHandlers.iterator();  
  233.         for(int i = 0; i < removeHandlers.size(); i++)  
  234.         {  
  235.             ((Listener)iter.next()).handleEvent(getSWTEvent(sender));  
  236.         }  
  237.     }  
  238.     /**  
  239.      * <p>Gets a generated SWT Event based on the shell</p>  
  240.      * <p>The widget field of the event should be set to the shell</p>  
  241.      * @param shell A SWT Shell  
  242.      * @return The event  
  243.      */ 
  244.     protected Event getSWTEvent(Shell shell)  
  245.     {  
  246.         Event e = new Event();  
  247.         e.widget = shell;  
  248.         e.item = shell;  
  249.         return e;  
  250.     }  
  251. }  
  252.  
  253.