Анимированный GIF в ячейке таблицы / дерева просмотра SWT - PullRequest
4 голосов
/ 10 января 2010

http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/DisplayananimatedGIF.htm описывает, как отображать анимированный GIF в SWT - в общем. Хотя код работает и его легко понять, я сталкиваюсь с серьезными проблемами при отображении анимированного GIF в ячейке просмотра таблицы / дерева SWT / JFace с помощью этой техники. -> весь код ниже

По сути, я реализовал свой собственный OwnerDrawLabelProvider, который создает ImageLoader в paint (Event, Object) и запускает анимационный поток. Кажется, проблема в том, что этот поток анимации является , а не потоком пользовательского интерфейса, и я не знаю, какой экземпляр GC или Display использовать в методе run ().

Я пытался создать отдельный экземпляр GC в конструкторе потока - производном от event.gc - но поток не записывает в этот GC, как только я выхожу из отладчика ...

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 

Как мне справиться с этой ситуацией?
Ниже приведены соответствующие разделы кода:

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

Я отправил ту же проблему в группу новостей SWT http://www.eclipse.org/forums/index.php?t=tree&th=160398

Ответы [ 2 ]

2 голосов
/ 09 февраля 2010

После долгих часов проб и ошибок коллега придумал выполнимое решение. Мои первоначальные подходы к реализации этого в полностью автономном LabelProvider с треском провалились.

Один из подходов, который не работал, состоял в том, чтобы переопределить LabelProvider # update () и вызвать timerExec (100, new Runnable () {... viewer.update () ... из этого метода. Этот цикл трудно контролировать, и он использует слишком много циклов ЦП (10% на моем MacBook).

Одна из идей коллеги состояла в том, чтобы реализовать собственный TableEditor: метку с изображением (один кадр анимированного GIF), но без текста. Каждый экземпляр TableEditor запускает собственный поток, в котором он обновляет изображение метки. Это работает довольно хорошо, но для каждой анимированной иконки есть отдельный поток анимации. Кроме того, это было убийство производительности, потребляющее 25% CPU на моем MacBook.

Финальный подход состоит из трех строительных блоков

  • OwnerDrawLabelProvider, который рисует либо статическое изображение, либо рамку анимированного GIF
  • поток анимации (производитель темпа), он вызывает redraw () для столбца, который содержит анимированные GIF-файлы, и также вызывает update ()
  • и поставщик контента зрителя, который управляет потоком анимации.

Подробности в моем блоге http://www.frightanic.com/2010/02/09/animated-gif-in-swt-tabletree-viewer-cell/.

1 голос
/ 11 января 2010

Разве вы не можете позволить LabelProvider возвращать разные изображения и затем вызывать viewer.update (...) для элементов, которые вы хотите анимировать. Вы можете использовать Display.timerExec для получения обратного вызова вместо отдельного потока.

Смотрите мой ответ здесь о том, как вы можете изменить цвета. Вы должны быть в состоянии сделать что-то подобное с изображениями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...