2010-01-10 130 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