绘画时缓冲的图像闪烁

时间:2017-08-24 04:37:13

标签: java swing awt

我正在开发一个相对复杂的java项目,该项目涉及GUI以及通过网络与两个不同的arduinos进行通信。

我在其中一个arduinos上有一个旋转编码器,可以告诉java程序车轮转了多远。我有一个线程,处理从arduino检索数据和旋转图像。

当我尝试快速旋转旋转编码器时出现问题图像将闪烁白色,如here所示。

我使用以下代码旋转图像:

public static void setimageto(int degree){

     stageRotation.stageangel = degree;
    try {
        BufferedImage localBufferedImage = ImageIO.read(new File("CircleStagePNG.png"));

        JPanel rotatepanel = new JPanel() {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
            }

            @Override
            protected void paintComponent(Graphics g) {
                if (g != null) {
                    super.paintComponent(g);
                    Graphics2D g2 = (Graphics2D) g;
                    g2.rotate(Math.toRadians(degree), localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
                    g2.drawImage(localBufferedImage, 0, 0, null);
                }
            }
        };

        stageRotation.pnPanel3.removeAll();
        rotatepanel.setBackground(stageRotation.color);
        stageRotation.pnPanel3.add(rotatepanel);
        stageRotation.pnPanel0.setBackground(stageRotation.color);
        stageRotation.pnPanel0.updateUI();
    } catch (IOException localIOException) {

    }
}

我还将完整代码上传到此link

主要的java文件名为 stageRotation.java ,而 javatest.java 应该是它应该是什么样子的示例。

任何解释或解决方案都会有所帮助,因为任何建议都会使这个问题更加用户友好。

[编辑] 这是我的主类和构造函数,删除了大量代码。我试图尽可能缩短它,但可能留下了一些不必要的物品,这也是它可能无法正常运行的原因。再次感谢您的帮助

import javax.swing.UIManager.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.net.*;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.net.ServerSocket;
import javax.swing.filechooser.*;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.concurrent.TimeUnit;



public class stageRotation extends JPanel {
    static stageRotation thestageRotation;
    public static JFrame mainFrame;
    public static JPanel pnPanel0;
    public static JPanel pnPanel1;
    public static JPanel pnPanel3;
    public static Object rotationobject;
    public static Object[] queadd;
    public static Thread motorcontrollerthread;
    public static Thread sensorcontrollerthread;
    public static Thread rotationthread =  new Thread();
    public static Thread inputthread =  new Thread();
    public static Boolean endinsight = false;
    public static Boolean rotaterflag = true;
    public static Boolean imagechange = false;
    public static volatile Boolean sensorinput = true;
    public static volatile Boolean motorinput = true;
    public static Color color = Color.WHITE;
    public static PrintWriter motorsocketout;
    public static PrintWriter sensorsocketout;
    public static Socket echoSocket;
    public static BufferedImage localBufferedImage;




    public static void main(String[] args) {
        //Makes the whole program look a lot better but there are some inexcusable errors that need to be worked out

        try {
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception e) {
            // If Nimbus is not available, you can set the GUI to another look and feel.
        }
        thestageRotation = new stageRotation();
    }



  public stageRotation()    {
        /*while(motorconnected == 0 || sensorconnected == 0) {
            if (motorconnected == -1 || sensorconnected == -1) {
                System.exit(0);
            }
        }*/

    //frame definition and layoutmanager definition
    JFrame mainFrame = new JFrame("Que thingy");
    pnPanel0 = new JPanel();
    GridBagLayout localGridBagLayout1 = new GridBagLayout();
    GridBagConstraints localGridBagConstraints1 = new GridBagConstraints();
    pnPanel0.setLayout(localGridBagLayout1);
    pnPanel3 = new JPanel();
    pnPanel3.setLayout(localGridBagLayout1);





     // create image for display
      try {
        final BufferedImage localBufferedImage = ImageIO.read(new File("CircleStagePNG.png"));

        pnPanel1 = new JPanel()   {
            public Dimension getPreferredSize() {
                return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
            }

            protected void paintComponent(Graphics paramAnonymousGraphics) {
                super.paintComponent(paramAnonymousGraphics);
                Graphics2D localGraphics2D = (Graphics2D)paramAnonymousGraphics;
                localGraphics2D.rotate(0.0D, localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
                localGraphics2D.drawImage(localBufferedImage, 0, 0, null);
            }

        };

        //set up graphical properties for image
        GridBagLayout localGridBagLayout2 = new GridBagLayout();
        pnPanel1.setBackground(color);
        pnPanel3.add(pnPanel1);
        pnPanel3.setLayout(localGridBagLayout2);
        localGridBagConstraints1.gridx = 0;
        localGridBagConstraints1.gridy = 0;
        localGridBagConstraints1.gridwidth = 1;
        localGridBagConstraints1.gridheight = 2;
        localGridBagConstraints1.fill = GridBagConstraints.BOTH;
        localGridBagConstraints1.weightx = 1;
        localGridBagConstraints1.weighty = 1;
        localGridBagConstraints1.anchor = GridBagConstraints.NORTH;
        localGridBagLayout1.setConstraints(pnPanel3, localGridBagConstraints1);
        pnPanel3.setBackground(Color.WHITE);
        pnPanel0.add(pnPanel3);




        mainFrame.setContentPane(pnPanel0);
        mainFrame.pack();
        mainFrame.setBackground(Color.WHITE);
        mainFrame.setVisible(true);
        tbJquetable.requestFocus();
      } catch (IOException localIOException) {}
   }








    //changes background will sometimes report nullpointerexception error however has no effect on code

   public static void setimageto(int degree){

         stageRotation.stageangel = degree;
        try {
            localBufferedImage = ImageIO.read(new File("CircleStagePNG.png"));

            pnPanel1 = new JPanel() {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
                }

                @Override
                protected void paintComponent(Graphics g) {
                        super.paintComponent(g);
                        Graphics2D g2 = (Graphics2D) g;
                        g2.rotate(Math.toRadians(degree), localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
                        g2.drawImage(localBufferedImage, 0, 0, null);

                }
            };

            stageRotation.pnPanel3.removeAll();
            pnPanel1.setBackground(stageRotation.color);
            stageRotation.pnPanel3.add(pnPanel1);

            stageRotation.pnPanel0.setBackground(stageRotation.color);
            stageRotation.pnPanel0.updateUI();
        } catch (IOException localIOException) {

        }
  }


}

[EDIT2]

虽然以下代码不会闪烁,但图像会在点处挂起。我无法使用url imagaes重现闪烁,只能使用本地文件;但是,我认为图像悬挂和闪烁是同样的问题。

    import javax.swing.UIManager.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.net.*;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.net.ServerSocket;
import javax.swing.filechooser.*;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.concurrent.TimeUnit;



public class stageRotation extends JPanel {
    static stageRotation thestageRotation;
    public static JFrame mainFrame;
    public static JPanel pnPanel0;
    public static JPanel pnPanel1;
    public static JPanel pnPanel3;
    public static Object rotationobject;
    public static Object[] queadd;
    public static Thread motorcontrollerthread;
    public static Thread sensorcontrollerthread;
    public static Thread rotationthread =  new Thread();
    public static Thread inputthread =  new Thread();
    public static Boolean endinsight = false;
    public static Boolean rotaterflag = true;
    public static Boolean imagechange = false;
    public static volatile Boolean sensorinput = true;
    public static volatile Boolean motorinput = true;
    public static Color color = Color.WHITE;
    public static PrintWriter motorsocketout;
    public static PrintWriter sensorsocketout;
    public static Socket echoSocket;
    public static BufferedImage localBufferedImage;

    public static URL url;





    public static void main(String[] args) {
        //Makes the whole program look a lot better but there are some inexcusable errors that need to be worked out

        try {
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception e) {
            // If Nimbus is not available, you can set the GUI to another look and feel.
        }
        thestageRotation = new stageRotation();
        for (int i = 0; i < 360; i++){
                setimageto(i);
        }
    }



  public stageRotation()    {

    try{
        url = new URL("https://upload.wikimedia.org/wikipedia/commons/thumb/0/06/CIRCLE_LINES.svg/220px-CIRCLE_LINES.svg.png");
    } catch(MalformedURLException a){}
    JFrame mainFrame = new JFrame("Que thingy");
    pnPanel0 = new JPanel();
    GridBagLayout localGridBagLayout1 = new GridBagLayout();
    GridBagConstraints localGridBagConstraints1 = new GridBagConstraints();
    pnPanel0.setLayout(localGridBagLayout1);
    pnPanel3 = new JPanel();
    pnPanel3.setLayout(localGridBagLayout1);





     // create image for display
      try {
        final BufferedImage localBufferedImage = ImageIO.read(url);

        pnPanel1 = new JPanel()   {
            public Dimension getPreferredSize() {
                return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
            }

            protected void paintComponent(Graphics paramAnonymousGraphics) {
                super.paintComponent(paramAnonymousGraphics);
                Graphics2D localGraphics2D = (Graphics2D)paramAnonymousGraphics;
                localGraphics2D.rotate(0.0D, localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
                localGraphics2D.drawImage(localBufferedImage, 0, 0, null);
            }

        };

        //set up graphical properties for image
        GridBagLayout localGridBagLayout2 = new GridBagLayout();
        pnPanel1.setBackground(color);
        pnPanel3.add(pnPanel1);
        pnPanel3.setLayout(localGridBagLayout2);
        localGridBagConstraints1.gridx = 0;
        localGridBagConstraints1.gridy = 0;
        localGridBagConstraints1.gridwidth = 1;
        localGridBagConstraints1.gridheight = 2;
        localGridBagConstraints1.fill = GridBagConstraints.BOTH;
        localGridBagConstraints1.weightx = 1;
        localGridBagConstraints1.weighty = 1;
        localGridBagConstraints1.anchor = GridBagConstraints.NORTH;
        localGridBagLayout1.setConstraints(pnPanel3, localGridBagConstraints1);
        pnPanel3.setBackground(Color.WHITE);
        pnPanel0.add(pnPanel3);


        mainFrame.setExtendedState(6);

        WindowListener exitListener = new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                try {
                    System.out.println("EXIT");
                    stageRotation.motorsocketout.println("EXIT");
                    sensorsocketout.println("EXIT");
                    sensorinput = false;
                    motorinput = false;


                    mainFrame.setVisible(false);
                    mainFrame.dispose();
                    System.exit(0);
                } catch (NullPointerException p){
                    System.exit(0);
                }
            }
        };
        mainFrame.addWindowListener(exitListener);

        mainFrame.setContentPane(pnPanel0);
        mainFrame.pack();
        mainFrame.setBackground(Color.WHITE);
        mainFrame.setVisible(true);
      } catch (IOException localIOException) {}
   }








    //changes background will sometimes report nullpointerexception error however has no effect on code

   public static void setimageto(int degree){

        try {
            localBufferedImage = ImageIO.read(url);

            pnPanel1 = new JPanel() {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
                }

                @Override
                protected void paintComponent(Graphics g) {
                        super.paintComponent(g);
                        Graphics2D g2 = (Graphics2D) g;
                        g2.rotate(Math.toRadians(degree), localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
                        g2.drawImage(localBufferedImage, 0, 0, null);

                }
            };

            stageRotation.pnPanel3.removeAll();
            pnPanel1.setBackground(stageRotation.color);
            stageRotation.pnPanel3.add(pnPanel1);

            stageRotation.pnPanel0.setBackground(stageRotation.color);
            stageRotation.pnPanel0.updateUI();
        } catch (IOException localIOException) {

        }
  }


}

2 个答案:

答案 0 :(得分:2)

好的..上面的MCVE表现出各种各样的误解。

  1. 制作动画的方法是包含一个动画循环&#39;在代码中。出于多种原因,最好使用基于Swing的Timer。然后ActionListener(在计时器的构造函数中使用)应该执行动画的单个帧。通常使用循环来设置动画将阻止事件调度线程,最终结果是“动画”和“动画”。将仅显示为第一帧 - 直接切换到最后一帧。
  2. 应为每个帧加载图像。 (具有讽刺意味的是,这样做会隐藏在前一点中提到的“EDT”。)相反,图像应该在启动时加载,并存储为类的属性。
  3. 应为每个新框架创建新的绘图表面。创建它一次更好,但提供一种方法来改变状态,然后重新绘制它的(原始的,单一的)实例。
  4. 可能对代码进行了许多其他改进,但我停在那里,因为它似乎解决了主要问题。

    以下是实现上述建议的代码:

    import javax.swing.UIManager.*;
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.net.*;
    import java.io.*;
    import java.awt.image.BufferedImage;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.imageio.ImageIO;
    
    public class stageRotation extends JPanel {
    
        private static stageRotation thestageRotation;
        public static JPanel pnPanel0;
        public static PnPanel1 pnPanel1;
        public static JPanel pnPanel3;
        public static volatile Boolean sensorinput = true;
        public static volatile Boolean motorinput = true;
        public static Color color = Color.WHITE;
        public static PrintWriter motorsocketout;
        public static PrintWriter sensorsocketout;
        public static BufferedImage localBufferedImage;
    
        public static URL url;
    
        public static void main(String[] args) {
            //Makes the whole program look a lot better but there are some inexcusable errors that need to be worked out
            try {
                for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                    if ("Nimbus".equals(info.getName())) {
                        UIManager.setLookAndFeel(info.getClassName());
                        break;
                    }
                }
            } catch (Exception e) {
                // If Nimbus is not available, you can set the GUI to another look and feel.
            }
            setThestageRotation(new stageRotation());
            ActionListener actionListener = new ActionListener() {
    
                int degree = 0;
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (degree<360) {
                        degree++;
                        setimageto(degree);
                    }
                }
            };
            Timer timer = new Timer(10,actionListener);
            timer.start();
        }
    
        /**
         * @param aThestageRotation the thestageRotation to set
         */
        public static void setThestageRotation(stageRotation aThestageRotation) {
            thestageRotation = aThestageRotation;
        }
    
        public stageRotation() {
    
            try {
                url = new URL("https://upload.wikimedia.org/wikipedia/commons/thumb/0/06/CIRCLE_LINES.svg/220px-CIRCLE_LINES.svg.png");
                localBufferedImage = ImageIO.read(url);
            } catch (Exception ex) {
                Logger.getLogger(stageRotation.class.getName()).log(Level.SEVERE, null, ex);
            }
            JFrame mainFrame = new JFrame("Que thingy");
            pnPanel0 = new JPanel();
            GridBagLayout localGridBagLayout1 = new GridBagLayout();
            GridBagConstraints localGridBagConstraints1 = new GridBagConstraints();
            pnPanel0.setLayout(localGridBagLayout1);
            pnPanel3 = new JPanel();
            pnPanel3.setLayout(localGridBagLayout1);
            pnPanel1 = new PnPanel1();
            pnPanel3.add(pnPanel1);
    
            // create image for display
            try {
                final BufferedImage localBufferedImage = ImageIO.read(url);
    
                //set up graphical properties for image
                GridBagLayout localGridBagLayout2 = new GridBagLayout();
                pnPanel1.setBackground(color);
                pnPanel3.setLayout(localGridBagLayout2);
                localGridBagConstraints1.gridx = 0;
                localGridBagConstraints1.gridy = 0;
                localGridBagConstraints1.gridwidth = 1;
                localGridBagConstraints1.gridheight = 2;
                localGridBagConstraints1.fill = GridBagConstraints.BOTH;
                localGridBagConstraints1.weightx = 1;
                localGridBagConstraints1.weighty = 1;
                localGridBagConstraints1.anchor = GridBagConstraints.NORTH;
                localGridBagLayout1.setConstraints(pnPanel3, localGridBagConstraints1);
                pnPanel3.setBackground(Color.WHITE);
                pnPanel0.add(pnPanel3);
    
                WindowListener exitListener = new WindowAdapter() {
    
                    @Override
                    public void windowClosing(WindowEvent e) {
                        try {
                            System.out.println("EXIT");
                            stageRotation.motorsocketout.println("EXIT");
                            sensorsocketout.println("EXIT");
                            sensorinput = false;
                            motorinput = false;
    
                            mainFrame.setVisible(false);
                            mainFrame.dispose();
                            System.exit(0);
                        } catch (NullPointerException p) {
                            System.exit(0);
                        }
                    }
                };
                mainFrame.addWindowListener(exitListener);
    
                mainFrame.setContentPane(pnPanel0);
                mainFrame.pack();
                mainFrame.setBackground(Color.WHITE);
                mainFrame.setVisible(true);
            } catch (IOException localIOException) {
            }
        }
    
        //changes background will sometimes report nullpointerexception error however has no effect on code
        public static void setimageto(int degree) {
            pnPanel1.setDegree(degree);
            pnPanel1.repaint();
        }
    
        class PnPanel1 extends JPanel {
    
            int degree;
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2 = (Graphics2D) g;
                g2.rotate(Math.toRadians(degree), localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
                g2.drawImage(localBufferedImage, 0, 0, this);
            }
    
            public void setDegree(int degree) {
                this.degree = degree;
            }
        };
    }
    

答案 1 :(得分:1)

我认为问题是针对每个学位的变化,你正在清除stageRotation并重新设置背景。

您应该只调用所有初始化代码一次,只有在需要更改学位时才重绘图像。