アイコンをその場で合成しながらアニメーション
SWTを使ったアプリケーションでアニメーションをさせるためのコード片を公開しておきます。(ほとんど自分のためにですが。)肝はThread#sleep()でフレーム秒間を調整したらだめで、Display#timerExec(int,Runnable)を使って再帰的に画像合成と描画を行うようにしておくことです。この考え方はDraw2dを使ったアプリケーションでももちろん有効です。
private static final class AnimationListener implements Listener { // WindowsとLinuxで画像の位置が変なので、調整するための定数を宣言 private static final int PLATFORM_DELTA_X; private static final int PLATFORM_DELTA_Y; static { if("gtk".equals(SWT.getPlatform())){ PLATFORM_DELTA_X = 1; PLATFORM_DELTA_Y = 3; }else{ PLATFORM_DELTA_X = 0; PLATFORM_DELTA_Y = 0; } } private int animationIndex = 0; private ImageData[] animationImages; protected int per10msec; private Control control; private AnimationListener(Control control) { this.control = control; // アニメーションの画像をロードする ImageLoader loader = new ImageLoader(); InputStream stream = this.getClass().getResourceAsStream("loading.gif"); animationImages = loader.load(stream); } public void handleEvent(final Event event) { if (event.item instanceof TreeItem) { TreeItem item = (TreeItem) event.item; Rectangle rect = item.getImageBounds(0); // elementはアニメーションの終了条件を判断する。 // SWTでは各Controlはdata領域にモデルを格納できる。SWTプラットフォームからはdata領域は触らない。 Object element = item.getData(); if (element instanceof INotificationService) { INotificationService service = (INotificationService) element; Image image = item.getImage(); doAnimation(control, item, rect, image, service); // 終了後の画像描画 if(image != null && !event.gc.isDisposed()) { event.gc.drawImage(image, rect.x + PLATFORM_DELTA_X,rect.y + PLATFORM_DELTA_Y); } } } } private void doAnimation(final Control tree, final TreeItem item, final Rectangle rect, final Image image,final INotificationService service) { // アニメーション用のRunnableインスタンス Runnable animation = new Runnable() { public void run() { if(item.isDisposed()) return; GC imageGc = new GC(tree); final Image animationImage = getAnimationImage(image.getImageData()); if(animationImage != null) { imageGc.drawImage(animationImage, rect.x + PLATFORM_DELTA_X,rect.y + PLATFORM_DELTA_Y); animationImage.dispose(); } if(service.isLoading()){ // ここが肝。再帰的にRunnableを呼び出す tree.getDisplay().timerExec(per10msec,this); }else{ imageGc.drawImage(image,rect.x + PLATFORM_DELTA_X,rect.y + PLATFORM_DELTA_Y); } imageGc.dispose(); } }; if(service.isLoading()){ tree.getDisplay().asyncExec(animation); }else{ GC imageGc = new GC(tree); imageGc.drawImage(image,rect.x + PLATFORM_DELTA_X,rect.y + PLATFORM_DELTA_Y); imageGc.dispose(); } } private Image getAnimationImage(final ImageData baseImage){ //画像合成のためのクラス。めんどいので匿名に。 CompositeImageDescriptor icon = new CompositeImageDescriptor(){ @Override protected void drawCompositeImage(int width, int height) { // 合成するための元の画像を書き出す drawImage(baseImage,0,0); // 合成するアニメーションの画像を取得する ImageData imageData = animationImages[animationIndex]; animationIndex = animationIndex == animationImages.length - 1 ? 0 : animationIndex + 1; drawImage(imageData, 0, 0); // アニメーションのフレーム秒間を計算する per10msec = imageData.delayTime * 10; } @Override protected Point getSize() { return new Point(16,16); } }; return icon.createImage(); } } ViewLabelProvider(TreeViewer viewer){ Control tree = viewer.getControl(); // 描画時のListenerとして登録する tree.addListener(SWT.PaintItem, new AnimationListener(tree)); }