正确刷新小部件?

时间:2014-02-24 11:34:59

标签: java multithreading swt

我目前正在努力使我们的应用程序的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();   
            }
        });
    }

1 个答案:

答案 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();
                    }

                } 
                        }
             });

这最终为我工作如果有人可以改进,请告诉我:)