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