这篇说说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;
- }
- }