http://www.java2s.com/Code/Java/ SWT-JFace-Eclipse/DisplayananimatedGIF.htm 描述了如何在 SWT 中显示动画 GIF - 一般情况。虽然代码可以工作并且很容易理解,但我在使用该技术在 SWT/JFace 表/树查看器单元格中显示动画 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
http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/DisplayananimatedGIF.htm describes how to display an animated GIF in SWT - in general. While the code works and is easily comprehensible I'm facing serious issues displaying an animated GIF in a SWT/JFace table/tree viewer cell with that technique. -> all code below
Essentially, I implemented my own OwnerDrawLabelProvider which creates an ImageLoader in paint(Event, Object) and starts an animation thread. The problem seems to be that this animation thread is not the UI thread and I don't know which GC or Display instance to use in its run() method.
I tried creating a separate GC instance in the thread's constructor - derived from event.gc - but the thread fails writing to that GC as soon as I step out of the debugger...
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
How do I need to handle this situation?
Below are the relevant code sections:
/* 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
I posted the same problem to the SWT newsgroup http://www.eclipse.org/forums/index.php?t=tree&th=160398
发布评论
评论(2)
经过几个小时令人沮丧的反复试验后,一位同事想出了一个可行的解决方案。我最初在完全独立的 LabelProvider 中实现此方法的方法惨败。
一种不起作用的方法是重写 LabelProvider#update() 并从该方法中调用timerExec(100, new Runnable() {...viewer.update()...。这很难控制,而且它使用了太多的 CPU 周期(在我的 MacBook 上为 10%)。
同事的想法之一是实现一个自定义 TableEditor:一个带有图像(动画 GIF 的一帧)但没有文本的标签。 TableEditor 实例将启动自己的线程,在其中更新标签的图像,这效果很好,但每个动画图标都有一个单独的“动画”线程,这也是一个性能杀手,在我的 MacBook 上消耗了 25% 的 CPU
。最后一种方法具有三个构建块:
详细信息请参阅我的博客 http://www.frightanic.com/2010/02/09/animated-gif-in-swt-tabletree-viewer-cell/。
After many hours of frustrating trial-and-error a co-worker came up with a feasible solution. My initial approaches to have this implemented in a totally self-contained LabelProvider failed miserably.
One approach that didn't work was to override LabelProvider#update() and to call timerExec(100, new Runnable() {...viewer.update()... from within that method. The "life"-cycle of that is hard to control and it uses too many CPU cycles (10% on my MacBook).
One of the colleague's ideas was to implement a custom TableEditor: a label with an image (one frame of the animated GIF) but no text. Each TableEditor instance would start its own thread in which it updates the label's image. This works quite well, but there's a separate "animation" thread for each animated icon. Also, this was a performance killer, consumed 25% CPU on my MacBook.
The final approach has three building blocks
Details in my blog http://www.frightanic.com/2010/02/09/animated-gif-in-swt-tabletree-viewer-cell/.
不能让 LabelProvider 返回不同的图像,然后对要设置动画的元素调用viewer.update(...) 吗?您可以使用 Display.timerExec 来获取回调,而不用使用单独的线程。
请参阅我的回答此处了解如何更改颜色。您应该能够对图像执行类似的操作。
Can't you let a LabelProvider return different images and then call viewer.update(...) on the elements you want to animate. You can use Display.timerExec to get a callback instead of having a separate thread.
See my answer here for how you can change colors. You should be able to do something similar with images.