2010-01-10 44 views
3

http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/DisplayananimatedGIF.htm描述了如何在SWT中显示动画GIF - 一般来说。尽管代码有效并且易于理解,但我正面临着使用该技术在SWT/JFace表格/树查看器单元格中显示动画GIF的严重问题。 - >下面的所有代码SWT表/树查看器单元格中的动画GIF

本质上,我实现了我自己的OwnerDrawLabelProvider,它在paint(Event,Object)中创建一个ImageLoader并启动一个动画线程。问题似乎是这个动画线程是而不是 UI线程,我不知道在它的run()方法中使用哪个GC或Display实例。

我试图在创建线程的构造一个单独的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

回答

1

经过许多小时的试错之后,一位同事想出了一个可行的解决方案。我最初的方法是在一个完全独立的LabelProvider中实现这个失败。

一种不起作用的方法是覆盖LabelProvider#update()并从该方法中调用timerExec(100,new Runnable(){... viewer.update()...。 “ - 它的周期很难控制,它使用太多的CPU周期(我的MacBook上的10%)

其中一位同事的想法是实现一个自定义TableEditor:带图像的标签动画GIF),但没有文本,每个TableEditor实例都会启动自己的线程,它会更新标签的图像,效果很好,但是每个动画图标都有一个单独的“动画”线程,并且这是一个性能杀手25%CPU在我的MacBook上。

个最后进近具有三个积木

  • 一个其描绘一个静态图像或动画GIF
  • 动画线程(起搏器)的帧OwnerDrawLabelProvider,它调用重绘()为列,其包含动画GIF并且它还调用update()
  • 以及控制动画线程的查看器的内容提供者。

我的博客详情http://www.frightanic.com/2010/02/09/animated-gif-in-swt-tabletree-viewer-cell/

1

你能不能让LabelProvider返回不同的图像,然后调用viewer.update(... )关于您想要动画的元素。您可以使用Display.timerExec获取回调,而不是使用单独的线程。

查看我的回答here了解如何更改颜色。你应该可以用图像做类似的事情。

+0

感谢您的指针,我会看看它。 为了清楚起见,您建议实施“常规”标签提供程序(即,不是OwnerDraw)在适当的时候返回静态图像 - 在具有静态图像的行上 - 并且为具有动画图像的所有行单独调用viewer.update(...)。 – 2010-01-11 20:59:18

+0

Hhhmmm,这很好,但我仍然需要找到正确的显示和GC实例来绘制... – 2010-01-11 21:17:41

+0

您可以从控件中获取显示。 GC gc =新的GC(myTable.getDisplay())。 – 2010-01-12 06:53:56