这篇说说GUI方面,就以打开种子文件这个窗口为例,我对其代码进行了精简,拿出了一个基本的骨架。
首先来看基本的消息主循环部分:
final
Display display
=
new
Display();
invoke( null ); // 创建窗口的主代码
while (stTorrentWindow != null && ! stTorrentWindow.bClosed)
{ // 窗口创建完成且没有关闭
if ( ! display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
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);
}
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(); // 显示窗口
}
{
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;
}
}
{
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;
}
}
{
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;
}
}