4

http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/DisplayananimatedGIF.htmは、アニメーションGIFをSWTで表示する方法を説明しています-一般的に。コードは機能し、簡単に理解できますが、その手法を使用してSWT/JFaceテーブル/ツリービューアセルにアニメーションGIFを表示する際に深刻な問題に直面しています。->以下のすべてのコード

基本的に、paint(Event、Object)でImageLoaderを作成し、アニメーションスレッドを開始する独自のOwnerDrawLabelProviderを実装しました。問題は、このアニメーションスレッドがUIスレッドではなく、run()メソッドで使用するGCまたはDisplayインスタンスがわからないことであるようです。

スレッドのコンストラクター(event.gcから派生)で別のGCインスタンスを作成しようとしましたが、デバッガーから出るとすぐにスレッドはそのGCへの書き込みに失敗します...

1月9日土曜日22:11:57192.168.1.6.local.homejava [25387]:CGContextConcatCTM:無効なコンテキスト0x0
2010-01-09 22:12:18.356 java [25387:17b03] [NSGraphicsContext currentContext]がnilの場合、画像を描画しても意味がありません。これはプログラミングエラーです。デバッグするには、_NSWarnForDrawingImageWithNoCurrentContextで中断します。これは1回だけログに記録されます。これは将来壊れるかもしれません。
1月9日土曜日22:12:41192.168.1.6.local.homejava [25387]:CGContextConcatCTM:無効なコンテキスト0x0

この状況にどのように対処する必要がありますか?
以下は、関連するコードセクションです。

/ * paint(Event、Object)によって呼び出されます。* /
private void paintAnimated(final Event event、final ImageLoader imageLoader){
    if(imageLoader == null || ArrayUtils.isEmpty(imageLoader.data)){
      戻る;
    }
    最終スレッドanimateThread=new AnimationThread(event、imageLoader);
    animateThread.setDaemon(true);
    animateThread.start();
  }

  プライベートクラスAnimationThreadはThread{を拡張します

    プライベートディスプレイディスプレイ;

    プライベートGCgc;

    プライベートImageLoaderimageLoader;

    プライベートカラーの背景;

    public AnimationThread(最終イベントイベント、最終ImageLoader imageLoader){
      super( "アニメーション");
      this.display = event.display;
      / *
       *単にevent.gcを参照すると、使用されるまでにリセット/空になります。
       * run()内。
       * /
      this.gc = new GC(event.gc.getDevice());
      this.imageLoader = imageLoader;
      this.background = getBackground(event.item、event.index);
    }

    @オーバーライド
    public void run(){
      / *
       *描画するオフスクリーン画像を作成し、シェルの背景で塗りつぶします。
       * /
      最終画像offScreenImage=
          新しい画像(this.display、this.imageLoader.logicalScreenWidth、
              this.imageLoader.logicalScreenHeight);
      最終的なGCoffScreenImageGC= new GC(offScreenImage);
      offScreenImageGC.setBackground(this.background);
      offScreenImageGC.fillRectangle(0、0、this.imageLoader.logicalScreenWidth、
          this.imageLoader.logicalScreenHeight);
      画像画像=null;
      試す {
        / *最初の画像を作成し、画面外の画像に描画します。* /
        int imageDataIndex = 0;
        ImageData imageData = this.imageLoader.data [imageDataIndex];
        image = new Image(this.display、imageData);
        offScreenImageGC.drawImage(image、0、0、imageData.width、imageData.height、imageData.x、
            imageData.y、imageData.width、imageData.height);

        / *
         *画像をループして、前に画面外の画像にそれぞれを作成して描画します
         *シェルに描画します。
         * /
        int repeatCount = this.imageLoader.repeatCount;
        while(this.imageLoader.repeatCount == 0 || repeatCount> 0){
          スイッチ(imageData.disposalMethod){
            ケースSWT.DM_FILL_BACKGROUND:
              /*描画する前に背景色を塗りつぶします。* /
              offScreenImageGC.setBackground(this.background);
              offScreenImageGC.fillRectangle(imageData.x、imageData.y、imageData.width、
                  imageData.height);
              壊す;
            ケースSWT.DM_FILL_PREVIOUS:
              //描画する前に前の画像を復元します。
              offScreenImageGC.drawImage(image、0、0、imageData.width、imageData.height、
                  imageData.x、imageData.y、imageData.width、imageData.height);
              壊す;
          }

          imageDataIndex =(imageDataIndex + 1)%this.imageLoader.data.length;
          imageData = this.imageLoader.data [imageDataIndex];
          image.dispose();
          image = new Image(this.display、imageData);
          offScreenImageGC.drawImage(image、0、0、imageData.width、imageData.height、imageData.x、
              imageData.y、imageData.width、imageData.height);

          //画面外の画像を描画します。
          this.gc.drawImage(offScreenImage、0、0);

          / *
           *指定された遅延時間スリープします(一般的に使用されるスローダウンファッジファクターを追加します)。
           * /
          試す {
            int ms = imageData.delayTime * 10;
            if(ms

同じ問題をSWTニュースグループhttp://www.eclipse.org/forums/index.php?t=tree&th=160398に投稿しました

4

2 に答える 2

2

何時間にもわたる試行錯誤の末、同僚は実行可能な解決策を思いつきました。これを完全に自己完結型のLabelProviderに実装するという私の最初のアプローチは、惨めに失敗しました。

うまくいかなかったアプローチの1つは、LabelProvider#update()をオーバーライドし、そのメソッド内からtimerExec(100、new Runnable(){... viewer.update()...を呼び出すことでした。これは制御が難しく、CPUサイクルが多すぎます(私のMacBookでは10%)。

同僚のアイデアの1つは、カスタムTableEditorを実装することでした。画像(アニメーションGIFの1フレーム)はあるがテキストはないラベルです。各TableEditorインスタンスは、ラベルの画像を更新する独自のスレッドを開始します。これは非常にうまく機能しますが、アニメーションアイコンごとに個別の「アニメーション」スレッドがあります。また、これはパフォーマンスキラーであり、私のMacBookで25%のCPUを消費しました。

ファイナルアプローチには3つのビルディングブロックがあります

  • 静止画像またはアニメーションGIFのフレームのいずれかをペイントするOwnerDrawLabelProvider
  • アニメーションスレッド(ペースメーカー)。アニメーションGIFを含む列に対してredraw()を呼び出し、update()も呼び出します。
  • アニメーションスレッドを制御するビューアのコンテンツプロバイダー。

私のブログの詳細http://www.frightanic.com/2010/02/09/animated-gif-in-swt-tabletree-viewer-cell/

于 2010-02-09T20:50:59.177 に答える
1

LabelProviderに別の画像を返させてから、アニメーション化する要素に対してviewer.update(...)を呼び出すことはできません。別のスレッドを使用する代わりに、Display.timerExecを使用してコールバックを取得できます。

色を変更する方法については、こちらの私の回答を参照してください。あなたは画像で同じようなことをすることができるはずです。

于 2010-01-11T17:43:57.060 に答える