有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

旋转后java图像不在正确位置(图形)

我试图以不同的速率显示两个直径为512untis的旋转车轮,但我无法删除以前绘制的图像图形并将旋转的图形设置在正确的位置。 现在我正在做一个任意角度的旋转。 我尝试了仿射变换,得到了旋转,但奇怪的是所有的像素都散开了。 我正在使用一个while循环和线程。睡眠()。代码如下: //drawSmallCircle和drawBigCircle返回两个图像

class MyFramePart2 extends JFrame

{ 

    String name;
    JPanel big_obj_panel,small_obj_panel;    
    JLabel bigLabel,smallLabel;BufferedImage imgRet,imgRetSmall;
    static double radians,angle,rev,fps,smallAngle,smallRadians;               
    int numLines,i=0;    

    MyFramePart2(String frameName,int numStrokes,double revolutions,double frameps)
    {       
        numLines=numStrokes;
        smallAngle=smallRadians=angle=radians=Math.toRadians(360/numLines);        
        rev=revolutions;
        fps=frameps; 

        setSize(1240,720);       
        setLocation(0,0);
        setLayout(null); 
        getContentPane().setBackground(Color.WHITE);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

        big_obj_panel=new JPanel();
        big_obj_panel.setLayout(null);
        big_obj_panel.setSize(512,512);
        big_obj_panel.setLocation(100,100); 
        big_obj_panel.setBackground(Color.white);
        add(big_obj_panel);   


        imgRet=drawBigCircle();
        bigLabel = new JLabel(new ImageIcon(imgRet));
        bigLabel.setLayout(null);        
        bigLabel.setLocation(0,0);
        bigLabel.setSize(512,512);
        bigLabel.setOpaque(true);
        bigLabel.setBackground(Color.white);  
        big_obj_panel.add(bigLabel);

        small_obj_panel=new JPanel();
        small_obj_panel.setLayout(null);
        small_obj_panel.setSize(512,512);
        small_obj_panel.setLocation(700,100); 
        small_obj_panel.setBackground(Color.white);
        add(small_obj_panel);   

        imgRetSmall=drawSmallCircle();

        smallLabel = new JLabel(new ImageIcon(imgRetSmall));
        smallLabel.setLayout(null);        
        smallLabel.setLocation(0,0);
        smallLabel.setSize(512,512);
        smallLabel.setOpaque(true);
        smallLabel.setBackground(Color.white);  
        small_obj_panel.add(smallLabel);

        setVisible(true);               

        while(i!=5) // suppose to be while true, just checking 
      {                 
        setVisible(true);          
        bigLabel.setIcon(new ImageIcon(imgRet));         
        smallLabel.setIcon(new ImageIcon(imgRetSmall));
        try{
        Thread.sleep(10);        
        }
        catch(Exception e)
        {}
        i++;               
     }                         
 }

    @Override
    public void paint(Graphics g)
    {        
        super.paint(g);
        Graphics2D g2d=(Graphics2D)g;           
        g2d.translate(256,256);
        g2d.rotate(Math.toRadians(20));                       
        g2d.translate(-256,-256); 
        g2d.drawImage(imgRet,0,0,null);
        g2d.dispose();        

        super.paint(g);
        g2d=(Graphics2D)g;
        g2d.translate(256,256);
        g2d.rotate(Math.toRadians(30));
        g2d.translate(-256,-256);        
        g2d.drawImage(imgRetSmall,0,0,null);        
        g2d.dispose();
    }

    public static BufferedImage drawBigCircle()
    {
        BufferedImage img=new BufferedImage(512,512,BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d=img.createGraphics();                
        g2d.setColor(Color.black);
        g2d.drawOval(0,0,511,511);

        Line2D l2d;
        while(angle <= 2*Math.PI)
        {
            l2d=new Line2D.Double(256,256,256+256*Math.cos(angle),256+256*Math.sin(angle));
            g2d.draw(l2d);
            angle=angle+radians;
        }               
        return img;
    }        
}

共 (1) 个答案

  1. # 1 楼答案

    挥杆的第一条规则。不要阻止事件调度线程。这样做会使应用程序看起来像挂起了一样,并阻止EDT处理任何重新绘制请求

    这意味着,您需要某种方式来安排不阻止EDT的更新

    第二条挥杆规则。不要从EDT以外的任何线程创建或修改任何UI组件

    通常,您应该避免覆盖顶级容器(如JFrame)的paint方法,除此之外,它们不是双缓冲的,这意味着您的绘画在更新时会闪烁。相反,您应该使用一个Swing容器,如JPanel

    有很多不同的方法来实现这一点。基本上,这里我使用了三个列表,但如果我是认真的,我会创建一个可以维护所有必需信息的对象(图像、角度和三角形)

    为了实现实际的动画,我使用了javax.swing.Timer。这将至少每隔n时段触发一个事件,但更重要的是,它在事件调度线程的上下文中触发。这确保了对角度所做的所有更改都是以这样的方式进行的,即在我们更新值时,防止出现任何绘制的可能性

    此示例以不同(随机)速度旋转三个图像

    enter image description here

    public class TestRotation {
    
        public static void main(String[] args) {
            new TestRotation();
        }
    
        public TestRotation() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Test");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new AnimationPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
    
            });
        }
    
        public class AnimationPane extends JPanel {
    
            private List<BufferedImage> images;
            private List<Double> angles;
            private List<Double> speed;
    
            public AnimationPane() {
                images = new ArrayList<>(5);
                images.add(createWheel(50, 4));
                images.add(createWheel(50, 3));
                images.add(createWheel(50, 6));
                angles = new ArrayList<>();
                speed = new ArrayList<>();
                for (int index = 0; index < images.size(); index++) {
                    angles.add(0d);
                    speed.add(Math.random() * 5d);
                }
    
                Timer timer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        for (int index = 0; index < angles.size(); index++) {
                            double angle = angles.get(index);
                            double delta = speed.get(index);
                            angle += delta;
                            angles.set(index, angle);
                        }
                        repaint();
                    }
                });
                timer.setRepeats(true);
                timer.setCoalesce(true);
                timer.start();
    
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                int x = 0;
                int y = 0;
                for (int index = 0; index < images.size(); index++) {
                    BufferedImage image = images.get(index);
                    double angle = angles.get(index);
    
                    // This is important.  Basically we going to grab a isolated snap shot
                    // of the current graphics context.  This means any changes we make
                    // will not affect the original graphics context (other then painting)
                    Graphics2D g2d = (Graphics2D) g.create();
                    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                    AffineTransform at = new AffineTransform();
                    at.translate(x, y);
                    at.rotate(Math.toRadians(angle), image.getWidth() / 2, image.getHeight() / 2);
                    g2d.setTransform(at);
                    g2d.drawImage(image, 0, 0, this);
                    g2d.dispose();
    
                    x += image.getWidth();
    
                }
            }
    
        }
    
        protected Point2D calculateOutterPoint(int radius, double angel) {
    
            int x = Math.round(radius / 2);
            int y = Math.round(radius / 2);
    
            double rads = Math.toRadians((angel + 90));
    
            // This determins the length of tick as calculate from the center of
            // the circle.  The original code from which this derived allowed
            // for a varible length line from the center of the cirlce, we
            // actually want the opposite, so we calculate the outter limit first
            double fullLength = (radius / 2d);
    
            // Calculate the outter point of the line
            double xPosy = (x + Math.cos(rads) * fullLength);
            double yPosy = (y - Math.sin(rads) * fullLength);
    
            return new Point2D.Double(xPosy, yPosy);
    
        }
    
        public BufferedImage createWheel(int radius, int spokes) {
            BufferedImage img = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = img.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setColor(Color.black);
            g2d.drawOval(0, 0, radius - 1, radius - 1);
    
            Point2D center = new Point2D.Double(radius / 2d, radius / 2d);
            double angle = 360d / spokes;
            for (int index = 0; index < spokes; index++) {
                Point2D p = calculateOutterPoint(radius, index * angle);
                g2d.draw(new Line2D.Double(center, p));
            }
    
            g2d.dispose();
            return img;
    
        }
    
    }