我目前正在努力使我们的应用程序的UI轻量化,因此我试图将重量级服务器调用移动到他们自己的线程。然后,我使用Display.getDefault.asyncExec()
更新小部件,这非常有效。
我想在服务器调用返回时向用户显示动画。到那时,我正在使用另一个线程,它在另一个Display.getDefault.asyncExec()
中显示动画。这也有效...但是以一种奇怪的方式。当我运行应用程序时,窗口小部件会非常频繁地闪烁,有时屏幕会保持未更新状态。问题是,当我运行一个原型版本,即没有主应用程序,只是一个简单的SWT应用程序,它的工作完美。任何想法为什么会这样?
基本工作流程::
showAnimation = new Thread(new Runnable() {
@Override
public void run() {
while(true){
synchronized (this) {
try {
Thread.sleep(1000);
drawCircles(); // basically the animation, also called in a Display.getDefault().asyncExec()
}
catch (InterruptedException e)
{
// do nothing, because this thread is meant to be interrupted!
// and then, break out of the infinite loop
System.out.println("Interrupted");
break;
}
}
}
}
});
invokeLater = new Thread(new Runnable(){
@Override
public void run(){
// do the data base call here
System.out.println("Got data!");
if(showAnimation.isAlive())
{
showAnimation.interrupt();
}
}
});
在我看来 - >
showAnimation.start();
invokeLater.start();
我简单地想知道是否应该增加动画线程的优先级,只是为了看看是否有效。它没有(也没有意义增加线程的优先级,这不是瓶颈应用程序)。
有什么想法吗?
P.S:drawCircles()
代码 - >
public void drawCircles(){
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run(){
int radius = 100;
int maxX = radius ;
int maxY = radius ;
int direction=0;
int centerX = table.getBounds().width/2;
int centerY = table.getBounds().height/2;
System.out.println("Drawing");
Image image = new Image(Display.getDefault(),table.getBounds().width,table.getBounds().height);
GC gc = new GC(image);
gc.setAntialias(SWT.ON);
gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
//gc.drawLine(0, centerY, shell.getBounds().width, centerY);
//gc.drawLine(centerX, 0, centerX, shell.getBounds().height);
// 1st circle
gc.drawOval(centerX-radius/2, centerY-radius - radius/2, maxX, maxY);
// 2nd circle
gc.drawOval(centerX - 2*radius + radius/2, centerY - radius/2, maxX, maxY);
// 3rd circle
gc.drawOval(centerX+radius/2, centerY-radius/2, maxX, maxY);
// 4th circle
gc.drawOval(centerX-radius/2, centerY + radius/2, maxX, maxY);
direction++;
direction %= 4;
switch(direction){
case 0:
gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc.fillOval(centerX - 2*radius + radius/2, centerY - radius/2, maxX, maxY);
break;
case 1:
gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc.fillOval(centerX-radius/2, centerY-radius - radius/2, maxX, maxY);
break;
case 2:
gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc.fillOval(centerX+radius/2, centerY-radius/2, maxX, maxY);
break;
case 3 :
gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc.fillOval(centerX-radius/2, centerY + radius/2, maxX, maxY);
break;
}
table.setBackgroundImage(image);
table.redraw();
table.update();
image.dispose();
gc.dispose();
}
});
}
答案 0 :(得分:1)
为了解决这个问题,我最终使用双缓冲,在GC中绘制图像,然后更新paintEvent gc。即使打开了抗锯齿,这也大大减少了闪烁。
基本上,创建一个PaintListener ::
final PaintListener paint = new PaintListener() {
@Override
public void paintControl(PaintEvent e) {
int radius = 100;
int maxX = radius ;
int maxY = radius ;
int centerX = e.width/2;
int centerY = e.height/2;
Image image = new Image(Display.getDefault(),e.width,e.height);
GC gc = new GC(image);
gc.setAntialias(SWT.ON);
gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
//gc.drawLine(0, centerY, shell.getBounds().width, centerY);
//gc.drawLine(centerX, 0, centerX, shell.getBounds().height);
// 1st circle
gc.drawOval(centerX-radius/2, centerY-radius - radius/2, maxX, maxY);
// 2nd circle
gc.drawOval(centerX - 2*radius + radius/2, centerY - radius/2, maxX, maxY);
// 3rd circle
gc.drawOval(centerX+radius/2, centerY-radius/2, maxX, maxY);
// 4th circle
gc.drawOval(centerX-radius/2, centerY + radius/2, maxX, maxY);
direction++;
direction %= 4;
switch(direction){
case 0:
gc.setAlpha(255);
gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc.fillOval(centerX - 2*radius + radius/2, centerY - radius/2, maxX, maxY);
break;
case 1:
gc.setAlpha(170);
gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc.fillOval(centerX-radius/2, centerY-radius - radius/2, maxX, maxY);
break;
case 2:
gc.setAlpha(80);
gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc.fillOval(centerX+radius/2, centerY-radius/2, maxX, maxY);
break;
case 3 :
gc.setAlpha(20);
gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
gc.fillOval(centerX-radius/2, centerY + radius/2, maxX, maxY);
break;
}
e.gc.drawImage(image, 0, 0);
image.dispose();
gc.dispose();
}
};
然后可以将动画线程写为::
showAnimation = new Thread(new Runnable() {
@Override
public void run() {
while(true){
synchronized (this) {
try {
Thread.sleep(100);
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
table.addPaintListener(paint);
table.redraw();
table.update();
table.removePaintListener(paint);
}
});
}
catch (InterruptedException e)
{
// do nothing, because this thread is meant to be interrupted!
// and then, break out of the infinite loop
break;
}
}
}
}
});
我添加并删除了侦听器,因为通知提出了一些问题(绘制的次数超过了所需的次数!)。然后,可以在另一个线程中进行数据库调用,如::
invokeLater = new Thread(new Runnable() {
@Override
public void run() {
//Fetching records from Service
try
{
// database call here
if(showAnimation.isAlive())
{
showAnimation.interrupt();
}
}
}
});
这最终为我工作如果有人可以改进,请告诉我:)