2010-01-10 7 views
3

http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/DisplayananimatedGIF.htm décrit comment afficher un fichier GIF animé dans SWT - en général. Alors que le code fonctionne et est facilement compréhensible, je suis confronté à de graves problèmes d'affichage d'un fichier GIF animé dans une cellule SWT/JFace table/tree viewer avec cette technique. -> tout le code ci-dessousGIF animé dans la cellule SWT table/tree viewer

Pour l'essentiel, j'ai implémenté ma propre propriété OwnerDrawLabelProvider qui crée un ImageLoader en peinture (Event, Object) et démarre un thread d'animation. Le problème semble être que ce fil d'animation est pas le thread UI et je ne sais pas quelle instance GC ou Display à utiliser dans sa méthode run().

J'ai essayé de créer une instance distincte de GC dans le constructeur de fil - dérivé de event.gc - mais le fil n'écrit que GC dès que je fais un pas sur le débogueur ...

 
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 

Comment dois-je gérer cette situation?
Voici les sections pertinentes du Code:

 
/* 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

J'ai posté le même problème dans le groupe de SWT http://www.eclipse.org/forums/index.php?t=tree&th=160398

Répondre

1

Après de nombreuses heures d'essais et d'erreurs frustrants, un collègue a proposé une solution réalisable. Mes approches initiales pour l'implémenter dans un LabelProvider totalement autonome ont lamentablement échoué. Une approche qui n'a pas fonctionné était de surcharger LabelProvider # update() et d'appeler timerExec (100, new Runnable() {... viewer.update() ... à partir de cette méthode. "-cycle de c'est difficile à contrôler et il utilise trop de cycles CPU (10% sur mon MacBook)

Une des idées du collègue était d'implémenter un TableEditor personnalisé: une étiquette avec une image (une image de la GIF animé) mais pas de texte: chaque instance de TableEditor démarre son propre thread dans lequel elle met à jour l'image du label, ce qui marche plutôt bien, mais il y a un thread "animation" séparé pour chaque icône animée. 25% CPU sur mon MacBook

L'approche finale a trois blocs de construction

  • un OwnerDrawLabelProvider qui peint soit une image statique ou dans le cadre d'un GIF animé
  • un fil d'animation (le pacemaker), il appelle redessiner() pour la colonne qui contient les GIF animés et appelle également update()
  • et le fournisseur de contenu du visualiseur qui contrôle le thread d'animation.

Détails dans mon blog http://www.frightanic.com/2010/02/09/animated-gif-in-swt-tabletree-viewer-cell/.

1

Tu ne peux pas laisser un LabelProvider retourner différentes images, puis appelez viewer.update (...) sur les éléments que vous voulez animer. Vous pouvez utiliser Display.timerExec pour obtenir un rappel au lieu d'avoir un thread séparé.

Voir ma réponse here pour savoir comment vous pouvez changer les couleurs. Vous devriez être capable de faire quelque chose de similaire avec des images.

+0

Merci pour le pointeur, je vais y jeter un coup d'oeil. Juste pour être clair ... vous proposez de mettre en place un LabelProvider "régulier" (c.-à-d.pas OwnerDraw) pour renvoyer des images statiques le cas échéant - sur les lignes contenant des images statiques - et appeler séparément viewer.update (...) pour toutes les lignes contenant des images animées. –

+0

Hhhmmm, c'est bien, mais j'ai encore besoin de trouver les bonnes instances Display et GC pour peindre sur ... –

+0

Vous pouvez simplement obtenir l'affichage à partir du contrôle. GC gc = nouveau GC (myTable.getDisplay()). –