Domanda

http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/DisplayananimatedGIF.htm descrive come visualizzare una GIF animata in SWT - in generale.Anche se il codice funziona ed è facilmente comprensibile, sto affrontando seri problemi nella visualizzazione di una GIF animata in una cella di visualizzazione di tabelle/alberi SWT/JFace con quella tecnica.-> tutto il codice qui sotto

Essenzialmente, ho implementato il mio OwnerDrawLabelProvider che crea un ImageLoader in paint(Event, Object) e avvia un thread di animazione.Il problema sembra essere che questo thread di animazione lo sia non il thread dell'interfaccia utente e non so quale istanza GC o Display utilizzare nel suo metodo run().

Ho provato a creare un'istanza GC separata nel costruttore del thread, derivata da event.gc, ma il thread non riesce a scrivere su quel GC non appena esco dal debugger...

Sat Jan  9 22:11:57 192.168.1.6.local.home java[25387] : CGContextConcatCTM: invalid context 0x0
2010-01-09 22:12:18.356 java[25387:17b03] It does not make sense to draw an image when [NSGraphicsContext currentContext] is nil.  This is a programming error. Break on _NSWarnForDrawingImageWithNoCurrentContext to debug.  This will be logged only once.  This may break in the future.
Sat Jan  9 22:12:41 192.168.1.6.local.home java[25387] : CGContextConcatCTM: invalid context 0x0 

Come devo gestire questa situazione?
Di seguito sono riportate le sezioni di codice pertinenti:

/* Called by paint(Event, Object). */
private void paintAnimated(final Event event, final ImageLoader imageLoader) {
    if (imageLoader == null || ArrayUtils.isEmpty(imageLoader.data)) {
      return;
    }
    final Thread animateThread = new AnimationThread(event, imageLoader);
    animateThread.setDaemon(true);
    animateThread.start();
  }

  private class AnimationThread extends Thread {

    private Display display;

    private GC gc;

    private ImageLoader imageLoader;

    private Color background;

    public AnimationThread(final Event event, final ImageLoader imageLoader) {
      super("Animation");
      this.display = event.display;
      /*
       * If we were to simply reference event.gc it would be reset/empty by the time it's being used
       * in run().
       */
      this.gc = new GC(event.gc.getDevice());
      this.imageLoader = imageLoader;
      this.background = getBackground(event.item, event.index);
    }

    @Override
    public void run() {
      /*
       * Create an off-screen image to draw on, and fill it with the shell background.
       */
      final Image offScreenImage =
          new Image(this.display, this.imageLoader.logicalScreenWidth,
              this.imageLoader.logicalScreenHeight);
      final GC offScreenImageGC = new GC(offScreenImage);
      offScreenImageGC.setBackground(this.background);
      offScreenImageGC.fillRectangle(0, 0, this.imageLoader.logicalScreenWidth,
          this.imageLoader.logicalScreenHeight);
      Image image = null;
      try {
        /* Create the first image and draw it on the off-screen image. */
        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);

        /*
         * Now loop through the images, creating and drawing each one on the off-screen image before
         * drawing it on the shell.
         */
        int repeatCount = this.imageLoader.repeatCount;
        while (this.imageLoader.repeatCount == 0 || repeatCount > 0) {
          switch (imageData.disposalMethod) {
            case SWT.DM_FILL_BACKGROUND:
              /* Fill with the background color before drawing. */
              offScreenImageGC.setBackground(this.background);
              offScreenImageGC.fillRectangle(imageData.x, imageData.y, imageData.width,
                  imageData.height);
              break;
            case SWT.DM_FILL_PREVIOUS:
              // Restore the previous image before drawing.
              offScreenImageGC.drawImage(image, 0, 0, imageData.width, imageData.height,
                  imageData.x, imageData.y, imageData.width, imageData.height);
              break;
          }

          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);

          // Draw the off-screen image.
          this.gc.drawImage(offScreenImage, 0, 0);

          /*
           * Sleeps for the specified delay time (adding commonly-used slow-down fudge factors).
           */
          try {
            int ms = imageData.delayTime * 10;
            if (ms 

Ho inviato lo stesso problema al newsgroup SWT http://www.eclipse.org/forums/index.php?t=tree&th=160398

È stato utile?

Soluzione

Dopo molte ore di frustranti tentativi ed errori, un collega ha trovato una soluzione fattibile.I miei approcci iniziali per implementarlo in un LabelProvider totalmente autonomo hanno fallito miseramente.

Un approccio che non ha funzionato è stato sovrascrivere LabelProvider#update() e chiamare timerExec(100, new Runnable() {...viewer.update()...dall'interno di quel metodo.Il suo ciclo di "vita" è difficile da controllare e utilizza troppi cicli della CPU (10% sul mio MacBook).

Una delle idee del collega era quella di implementare un TableEditor personalizzato:un'etichetta con un'immagine (un fotogramma della GIF animata) ma senza testo.Ogni istanza di TableEditor inizierà il proprio thread in cui aggiorna l'immagine dell'etichetta.Funziona abbastanza bene, ma c'è un thread di "animazione" separato per ogni icona animata.Inoltre, questo era un killer delle prestazioni, consumava il 25% della CPU sul mio MacBook.

L’approccio finale ha tre elementi costitutivi

  • un OwnerDrawLabelProvider che dipinge un'immagine statica o il fotogramma di una GIF animata
  • un thread di animazione (il pace maker), chiama redraw() per la colonna che contiene le GIF animate e chiama anche update()
  • e il fornitore di contenuti dello spettatore che controlla il thread di animazione.

Dettagli nel mio blog http://www.frightanic.com/2010/02/09/animated-gif-in-swt-tabletree-viewer-cell/.

Altri suggerimenti

Non puoi lasciare che restituisce un LabelProvider immagini diverse e quindi chiamare viewer.update (...) sugli elementi da animare. È possibile utilizzare Display.timerExec per ottenere un callback, invece di avere un thread separato.

Vedere la mia risposta qui per come è possibile cambiare i colori. Si dovrebbe essere in grado di fare qualcosa di simile con le immagini.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top