java - 正确刷新小部件吗?

标签 java multithreading swt

我目前正在尝试使应用程序的 UI 变得轻量级,因此我尝试将重量级服务器调用移至它们自己的线程。然后,我使用 Display.getDefault.asyncExec() 更新小部件,效果非常好。

我想在服务器调用返回时向用户显示动画。到目前为止,我正在使用另一个线程,它在另一个 Display.getDefault.asyncExec() 中显示动画。这也有效......但以一种奇怪的方式。当我运行该应用程序时,小部件闪烁得非常厉害,有时屏幕保持未更新状态。问题是,当我运行原型(prototype)版本时,即没有主应用程序,只是一个简单的 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();   
            }
        });
    }

最佳答案

为了解决这个问题,我最终使用了双缓冲,在 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();
                    }

                } 
                        }
             });

这最终对我有用如果有人可以对此进行改进,请告诉我:)

关于java - 正确刷新小部件吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21986575/

相关文章:

java - 如何在Android中显示不同大小的文字,例如Office或Google Docs的功能

java - 带有 GridLayout JFrame 的 JPanels 中的 JButtons

multithreading - 多核系统上的并行问题之外的线程有什么用?

video - 在 SWT 应用程序中运行视频?

java - Uiautomatorviewer SWT 异常

java - 使用 JNI 将列表 <unsigned char*> 从 C++ 返回到 Java

java - JSP - 当值重复时如何打印出空的 <td>?

java.lang.IllegalThreadStateException

ruby - ruby 有真正的多线程吗?

java - 根据切换状态禁用/启用工具栏菜单项