因为SWT的ImageLoader支持读写以上所有格式的图片,所以实现起来比较简单。主要解决了两个问题。第一个问题是播放GIF动画,通过ImageLoader读入GIF的所有帧以及间隔时间,然后用Display.timerExec实现Timer播放。第二个问题是对图片的Scrollbar支持以及pack支持。SWT.H_SCROLL和SWT.V_SCROLL 虽然加上了滚动条,但是不起作用,需要监听滚动条的SWT.Selection事件。另外,加上滚动条后,pack无法得到大小,不能正确的pack。需要重载computeSize。
/**
* 负责显示各种格式的图片
*
*
@author
喜来乐哈哈
*/
public
class
ImageViewer
extends
Canvas {
protected
Point origin
=
new
Point(
0
,
0
);
protected
Image image;
protected
ImageData[] imageDatas;
protected
Image[] images;
protected
int
current;
private
int
repeatCount;
private
Runnable animationTimer;
private
ScrollBar hBar;
private
ScrollBar vBar;
private
Color bg;
private
Display display;
public
ImageViewer(Composite parent) {
super
(parent, SWT.NO_BACKGROUND
|
SWT.NO_REDRAW_RESIZE
|
SWT.V_SCROLL
|
SWT.H_SCROLL);
hBar
=
getHorizontalBar();
vBar
=
getVerticalBar();
bg
=
getBackground();
display
=
getDisplay();
addListeners();
}
public
void
setImage(ImageData imageData) {
checkWidget();
stopAnimationTimer();
this
.image
=
new
Image(display, imageData);
this
.imageDatas
=
null
;
this
.images
=
null
;
redraw();
}
/**
*
@param
repeatCount 0 forever
*/
public
void
setImages(ImageData[] imageDatas,
int
repeatCount) {
checkWidget();
this
.image
=
null
;
this
.imageDatas
=
imageDatas;
this
.repeatCount
=
repeatCount;
convertImageDatasToImages();
startAnimationTimer();
redraw();
}
@Override
public
Point computeSize(
int
wHint,
int
hHint,
boolean
changed) {
checkWidget();
Image image
=
getCurrentImage();
if
(image
!=
null
) {
Rectangle rect
=
image.getBounds();
Rectangle trim
=
computeTrim(
0
,
0
, rect.width, rect.height);
return
new
Point(trim.width, trim.height);
}
return
new
Point(wHint, hHint);
}
@Override
public
void
dispose() {
if
(image
!=
null
)
image.dispose();
if
(images
!=
null
)
for
(
int
i
=
0
; i
<
images.length; i
++
)
images[i].dispose();
super
.dispose();
}
protected
void
paint(Event e) {
Image image
=
getCurrentImage();
if
(image
==
null
)
return
;
GC gc
=
e.gc;
gc.drawImage(image, origin.x, origin.y);
gc.setBackground(bg);
Rectangle rect
=
image.getBounds();
Rectangle client
=
getClientArea();
int
marginWidth
=
client.width
-
rect.width;
if
(marginWidth
>
0
) {
gc.fillRectangle(rect.width,
0
, marginWidth, client.height);
}
int
marginHeight
=
client.height
-
rect.height;
if
(marginHeight
>
0
) {
gc.fillRectangle(
0
, rect.height, client.width, marginHeight);
}
}
void
addListeners() {
hBar.addListener(SWT.Selection,
new
Listener() {
public
void
handleEvent(Event arg0) {
hscroll();
}
});
vBar.addListener(SWT.Selection,
new
Listener() {
public
void
handleEvent(Event arg0) {
vscroll();
}
});
addListener(SWT.Resize,
new
Listener() {
public
void
handleEvent(Event e) {
resize();
}
});
addListener(SWT.Paint,
new
Listener() {
public
void
handleEvent(Event e) {
paint(e);
}
});
}
void
hscroll() {
Image image
=
getCurrentImage();
if
(image
!=
null
) {
int
hSelection
=
hBar.getSelection();
int
destX
=
-
hSelection
-
origin.x;
Rectangle rect
=
image.getBounds();
scroll(destX,
0
,
0
,
0
, rect.width, rect.height,
false
);
origin.x
=
-
hSelection;
}
}
void
vscroll() {
Image image
=
getCurrentImage();
if
(image
!=
null
) {
int
vSelection
=
vBar.getSelection();
int
destY
=
-
vSelection
-
origin.y;
Rectangle rect
=
image.getBounds();
scroll(
0
, destY,
0
,
0
, rect.width, rect.height,
false
);
origin.y
=
-
vSelection;
}
}
void
resize() {
Image image
=
getCurrentImage();
if
(image
==
null
)
return
;
Rectangle rect
=
image.getBounds();
Rectangle client
=
getClientArea();
hBar.setMaximum(rect.width);
vBar.setMaximum(rect.height);
hBar.setThumb(Math.min(rect.width, client.width));
vBar.setThumb(Math.min(rect.height, client.height));
int
hPage
=
rect.width
-
client.width;
int
vPage
=
rect.height
-
client.height;
int
hSelection
=
hBar.getSelection();
int
vSelection
=
vBar.getSelection();
if
(hSelection
>=
hPage) {
if
(hPage
<=
0
)
hSelection
=
0
;
origin.x
=
-
hSelection;
}
if
(vSelection
>=
vPage) {
if
(vPage
<=
0
)
vSelection
=
0
;
origin.y
=
-
vSelection;
}
redraw();
}
void
convertImageDatasToImages() {
images
=
new
Image[imageDatas.length];
//
Step 1: Determine the size of the resulting images.
int
width
=
imageDatas[
0
].width;
int
height
=
imageDatas[
0
].height;
//
Step 2: Construct each image.
int
transition
=
SWT.DM_FILL_BACKGROUND;
for
(
int
i
=
0
; i
<
imageDatas.length; i
++
) {
ImageData id
=
imageDatas[i];
images[i]
=
new
Image(display, width, height);
GC gc
=
new
GC(images[i]);
//
Do the transition from the previous image.
switch
(transition) {
case
SWT.DM_FILL_NONE:
case
SWT.DM_UNSPECIFIED:
//
Start from last image.
gc.drawImage(images[i
-
1
],
0
,
0
);
break
;
case
SWT.DM_FILL_PREVIOUS:
//
Start from second last image.
gc.drawImage(images[i
-
2
],
0
,
0
);
break
;
default
:
//
DM_FILL_BACKGROUND or anything else,
//
just fill with default background.
gc.setBackground(bg);
gc.fillRectangle(
0
,
0
, width, height);
break
;
}
//
Draw the current image and clean up.
Image img
=
new
Image(display, id);
gc.drawImage(img,
0
,
0
, id.width, id.height, id.x, id.y, id.width,
id.height);
img.dispose();
gc.dispose();
//
Compute the next transition.
//
Special case: Can't do DM_FILL_PREVIOUS on the
//
second image since there is no "second last"
//
image to use.
transition
=
id.disposalMethod;
if
(i
==
0
&&
transition
==
SWT.DM_FILL_PREVIOUS)
transition
=
SWT.DM_FILL_NONE;
}
}
Image getCurrentImage() {
if
(image
!=
null
)
return
image;
if
(images
==
null
)
return
null
;
return
images[current];
}
void
startAnimationTimer() {
if
(images
==
null
||
images.length
<
2
)
return
;
final
int
delay
=
imageDatas[current].delayTime
*
10
;
display.timerExec(delay, animationTimer
=
new
Runnable() {
public
void
run() {
if
(isDisposed())
return
;
current
=
(current
+
1
)
%
images.length;
redraw();
if
(current
+
1
==
images.length
&&
repeatCount
!=
0
&&
--
repeatCount
<=
0
)
return
;
display.timerExec(delay,
this
);
}
});
}
void
stopAnimationTimer() {
if
(animationTimer
!=
null
)
display.timerExec(
-
1
, animationTimer);
}
}
测试程序
public
class
ImageCanvasTest {
public
static
void
main(String[] args) {
Display display
=
new
Display();
final
Shell shell
=
new
Shell(display);
ImageViewer ic
=
new
ImageViewer(shell);
shell.setLayout(
new
FillLayout());
FileDialog dialog
=
new
FileDialog(shell, SWT.OPEN);
dialog.setText(
"
Open an image file or cancel
"
);
String string
=
dialog.open();
ImageLoader loader
=
new
ImageLoader();
ImageData[] imageDatas
=
loader.load(string);
if
(imageDatas.length
==
0
)
return
;
else
if
(imageDatas.length
==
1
) {
ic.setImage(imageDatas[
0
]);
}
else
{
ic.setImages(imageDatas, loader.repeatCount);
}
ic.pack();
shell.pack();
shell.open();
while
(
!
shell.isDisposed()) {
if
(
!
display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
在对GIF图片的支持上,Swing要做的好很多,一句label.setIcon(new ImageIcon(name))就搞定GIF动画了。
转载请保留 http://www.blogjava.net/xilaile/archive/2007/04/10/109547.html