Java 在Nattable叠加绘制器中绘制动画
我正在尝试在nattable上渲染加载动画。我使用OverlyPaint机制在表格顶部绘制一个“玻璃窗格”和一些文本,这非常有效:Java 在Nattable叠加绘制器中绘制动画,java,swt,nattable,Java,Swt,Nattable,我正在尝试在nattable上渲染加载动画。我使用OverlyPaint机制在表格顶部绘制一个“玻璃窗格”和一些文本,这非常有效: public class MessageOverlay implements IOverlayPainter { .... @Override public void paintOverlay(final GC gc, final ILayer layer) { this.currentGC = gc; this.currentLayer = layer;
public class MessageOverlay
implements IOverlayPainter {
....
@Override
public void paintOverlay(final GC gc, final ILayer layer) {
this.currentGC = gc;
this.currentLayer = layer;
if (visible) {
currentGC.setAlpha(200);
currentGC.fillRectangle(0, 0, currentLayer.getWidth(), currentLayer
.getHeight());
drawMessage();
if (withLoadingAnimation) {
showAnimation = true;
}
} else {
showAnimation = false;
}
}
}
但是,paintOverlay
方法不是经常调用的,而是在每次表更改时调用
为了能够显示平滑的动画,我添加了一个新线程
final Thread animatorThread = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.interrupted()) {
try {
Thread.sleep(1000 / fps);
} catch (final InterruptedException e) {
break;
}
display.asyncExec(new Runnable() {
@Override
public void run() {
if (showAnimation && !currentGC.isDisposed()) {
final Image currentImage = getNextImage();
final int posX = currentGC.getClipping().width / 2
- currentImage.getBounds().width;
final int posY = currentGC.getClipping().height / 2
- currentImage.getBounds().height;
currentGC.drawImage(currentImage, posX, posY);
}
}
});
}
}
});
animatorThread.start();
如您所见,它试图访问paintOverlay
方法中设置的图形上下文this.currentGC
。我的问题是,animatorhread
中的currentGC
总是被处理掉
我如何才能a.)确保上下文不在线程中处理,或者b.)以另一种方式解决这个问题
感谢您的帮助。您可以尝试使用当前NatTable实例创建一个新的GC,如果需要,可以从传入的GC实例中传递配置。然后,您负责处理GC实例,并且不应该有在线程外处理GC的风险
一个简单的示例可能类似于下面的代码片段,它简单地显示了1000毫秒的窗格,然后再次删除它。当然,您需要将逻辑更改为更动态的加载操作,然后:
AtomicBoolean paneThreadStarted = new AtomicBoolean(false);
...
natTable.addOverlayPainter(new IOverlayPainter() {
@Override
public void paintOverlay(GC gc, ILayer layer) {
if (this.paneThreadStarted.compareAndSet(false, true)) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
GC currentGC = new GC(natTable);
currentGC.setForeground(GUIHelper.COLOR_WHITE);
currentGC.setBackground(GUIHelper.COLOR_BLACK);
currentGC.setAlpha(200);
currentGC.fillRectangle(0, 0, layer.getWidth(), layer.getHeight());
String load = "Loading data ...";
Point textExtent = currentGC.textExtent(load);
currentGC.drawText(load,
layer.getWidth() / 2 - textExtent.x / 2,
layer.getHeight() / 2 - textExtent.y / 2,
true);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
currentGC.dispose();
natTable.redraw();
}
});
}
}
});
这样,您可以通过从外部更改AtomicBoolean
再次显示窗格:
Button showPaneButton = new Button(buttonPanel, SWT.PUSH);
showPaneButton.setText("Show Pane");
showPaneButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
this.paneThreadStarted.set(false);
natTable.redraw();
}
});
即使GC没有被释放,这仍然会因为“无效线程访问”而失败,因为所有UI操作(如drawImage
)都必须在UI线程中完成。啊,你完全正确,我已经更改了问题以反映在UI线程中运行。不过,这似乎让我更接近结果,图层现在不是绘制在表格上,而是绘制在窗口上。我能够正确地设置剪辑(因此覆盖具有正确的大小)。我使用newgc(table.getShell)
创建新的gc。如果我使用newgc(table.getDisplay)
我看不到任何覆盖,可能是因为它绘制在表的下面?您是否尝试过newgc(natTable)代码>?因为NatTable作为画布
也是一个可绘制的
这听起来是放置它的正确位置,但是,它似乎是在实际表下面绘制的覆盖,因此隐藏了覆盖的内容。在第二个线程中异步渲染时可能会出现并发问题。我对您的代码进行了简单的修改,测试结果对我很有效。如果您仍然有问题,您可以尝试使用PaintListener而不是LoverLayPainter。您介意分享您的示例吗?我可以分析这些差异,如果有的话,看看我是否犯了一个微妙的错误。