GIF animé dans le tableau SWT / arbre cellule de spectateur
Question
http://www.java2s.com/Code /Java/SWT-JFace-Eclipse/DisplayananimatedGIF.htm décrit comment afficher un GIF animé dans SWT - en général. Alors que le code fonctionne et est facilement compréhensible que je suis confronté à de sérieux problèmes d'affichage d'un GIF animé dans une SWT / JFace Table / arbre cellule de spectateur avec cette technique. -> tout le code ci-dessous
Pour l'essentiel, j'ai mis mon propre OwnerDrawLabelProvider qui crée un ImageLoader dans la peinture (événement, objet) et démarre un fil d'animation. La méthode problème semble être que ce fil d'animation est pas le fil de l'interface utilisateur et je ne sais pas quelle GC ou l'affichage par exemple à utiliser dans sa course ().
J'ai essayé de créer une instance distincte de GC dans le constructeur du fil - dérivé de event.gc - mais le fil échoue à écrire que GC, dès que je sors du 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 à l'href="http://www.eclipse.org/forums/index.php?t=tree&th=160398" rel="nofollow noreferrer"> newsgroup SWT
La solution
Après de nombreuses heures de frustration d'essais et d'erreur d'un collègue est venu avec une solution réalisable. Mes premières démarches pour que cette mise en œuvre dans un environnement totalement autonome LabelProvider a lamentablement échoué.
Une approche qui n'a pas fonctionné a été de passer outre LabelProvider # update () et appeler timerExec (100, nouvelle Runnable () {... viewer.update () ... à partir de cette méthode. La "vie" -cycle de difficile à contrôler et il utilise trop de cycles CPU (10% sur mon MacBook).
L'une des idées du collègue était de mettre en œuvre un TableEditor personnalisé: une étiquette avec une image (une image du GIF animé), mais aucun texte. Chaque instance TableEditor commencerait son propre thread dans lequel il met à jour l'image de l'étiquette. Cela fonctionne très bien, mais il y a un fil « animation » pour chaque icône animée. De plus, ce fut un tueur de performance, la consommation CPU de 25% sur mon MacBook.
L'approche finale a trois blocs de construction
- un OwnerDrawLabelProvider qui peint soit une image statique ou la trame d'une image GIF animée
- un fil d'animation (le pacemaker), il appelle redessiner () pour la colonne qui contient les fichiers GIF animés et il appelle également la mise à jour ()
- et le fournisseur de contenu du spectateur qui contrôle le fil d'animation.
Détails sur mon blog http://www.frightanic.com/2010/02/09/animated-gif-in-swt-tabletree-viewer-cell/ .
Autres conseils
Tu ne peux pas laisser un LabelProvider retourner différentes images, puis appelez viewer.update (...) sur les éléments que vous souhaitez animer. Vous pouvez utiliser Display.timerExec pour obtenir un rappel au lieu d'avoir un thread séparé.
Voir ma réponse la façon dont vous pouvez changer les couleurs. Vous devriez être en mesure de faire quelque chose de similaire avec des images.