来源:http://www.blogjava.net/xilaile/archive/2007/04/10/109547.html
因为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(); } }