通过线程缩放图像 - JAVA

时间:2014-01-25 15:29:05

标签: java swing paint repaint thread-sleep

假设我有一张图片。我将图像放在JPanel中,并在JFrame中添加JPanel。图像从框架的底部移动到框架的顶部,同时使用AffineTransform减小尺寸。变量使用线程更改。

所以这是以下代码:

public class SplashScreen extends JFrame{
    Image img1;
    int w=1,h=1;
    int x=0,y=0;
    Thread th = new Thread(new Runnable() {
    @Override
    public void run() {
        while(true){
            w-=0.05;
            h-=0.05;
            y-=2;
            x+=1;

            if(y==-100){
                new MainMenu_BlueJay().setVisible(true);
                dispose();
            }

            repaint();
            try {
                Thread.sleep(10);
            } catch (InterruptedException ex) {
                Logger.getLogger(SplashScreen.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
    }
});

JPanel p = new JPanel();

public SplashScreen(){
    setLayout(new BorderLayout());

    p.setPreferredSize(new Dimension(900,600));
    p.setBackground(Color.black);
    p.setLayout(new GridLayout());

    add(p);
    setTitle("BlueJay");
    setSize(900,600);

    getContentPane().setBackground(Color.black);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    setVisible(true);
    th.start();
    requestFocus();
    setFocusable(true);
}

@Override
public void paint(Graphics g) {
    super.paint(g);
    Graphics2D g2d = (Graphics2D) g;

    img1 = new ImageIcon("images/Intro/BJ Production 2013.png").getImage();
    AffineTransform at = new AffineTransform();
    at.scale(w,h);
    g2d.setTransform(at);
    g2d.drawImage(img1, x, y, p);
}

 public static void main(String[] args) {
    new SplashScreen();
}

然而,我从上面的代码得到的只是黑屏。怎么了?无论如何,如果我不使用AffineTransform功能(只是从下到上移动),图像会显示并移动但框架会快速闪烁(闪烁)。

任何想法都可以解决这个问题,这样我就可以在减小尺寸的同时移动图像并解决闪烁/快速闪烁的帧?

2 个答案:

答案 0 :(得分:2)

您不应该覆盖JFrame的paint方法。如果你想绘制任何东西,你应该在扩展JPanel的类中绘制它,在那里覆盖paintComponent方法。

您不应该在绘画方法中加载图像。这非常低效。您应该只在ONCE中加载图像,可能在构造函数中。

你不应该致电Graphics2D#setTransform()。查看http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html#setTransform%28java.awt.geom.AffineTransform%29上的JavaDoc,它明确说明了

警告:此方法永远不会用于在现有转换的基础上应用新的坐标转换

您应该考虑wh值。它们应该是绘制的图像的大小,还是用作图像的缩放因子?将它们设置为AffineTransform的缩放因子将不具有将图像缩放到所需大小的效果。目前,它们被声明为int值,因此像w-=0.05这样的东西无论如何都没有意义。

您应该清楚地了解如何描述图像应该执行的动画。

有人可能总结一下:

您不应该编写代码并假设它只是“正确”,因为没有编译错误; - )

但是,以下代码段可能是实现目标的第一步:

package stackoverflow;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class SplashScreen extends JFrame
{
    public static void main(String[] args) 
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                new SplashScreen();
            }
        });
    }    

    private PaintPanel paintPanel;

    public SplashScreen()
    {
        setTitle("BlueJay");
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        getContentPane().setBackground(Color.BLACK);
        getContentPane().setLayout(new BorderLayout());

        paintPanel = new PaintPanel();
        getContentPane().add(paintPanel, BorderLayout.CENTER);

        setSize(900,600);
        setLocationRelativeTo(null);
        setFocusable(true);
        requestFocus();
        setVisible(true);

        startAnimation();
    }

    void startAnimation()
    {
        Thread thread = new Thread(new Runnable()
        {
            int x = 100;
            int y = 100;
            int w = 0;
            int h = 0;

            @Override
            public void run()
            {
                try
                {
                    Thread.sleep(500);
                }
                catch (InterruptedException ex)
                {
                    Thread.currentThread().interrupt();
                    return;
                }

                while (true)
                {
                    if (y == 200)
                    {
                        // new MainMenu_BlueJay().setVisible(true);
                        dispose();
                    }

                    x += 2;
                    y += 1;
                    w += 1;
                    h += 1;
                    paintPanel.setImageCoordinates(x, y, w, h);

                    repaint();
                    try
                    {
                        Thread.sleep(10);
                    }
                    catch (InterruptedException ex)
                    {
                        Thread.currentThread().interrupt();
                        return;
                    }

                }
            }
        });
        thread.start();
    }
}


class PaintPanel extends JPanel
{
    private final Image image;
    private int imageX, imageY;
    private int imageW, imageH;

    PaintPanel()
    {
        image = new ImageIcon("Clipboard02.jpg").getImage();
        imageX = 0;
        imageY = 0;
        imageW = 0;
        imageH = 0;
    }

    void setImageCoordinates(int imageX, int imageY, int imageW, int imageH)
    {
        this.imageX = imageX;
        this.imageY = imageY;
        this.imageW = imageW;
        this.imageH = imageH;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D) gr;

        float scalingX = (float) imageW / image.getWidth(null);
        float scalingY = (float) imageH / image.getHeight(null);
        g.scale(scalingX, scalingY);

        int ix = (int)(imageX / scalingX);
        int iy = (int)(imageY / scalingY);
        g.drawImage(image, ix, iy, null);
    }
}

答案 1 :(得分:2)

  1. 不要在JFrame等顶级容器上绘画。而是使用JPanel并覆盖其paintComponent方法并调用super.paintComponent
  2. 无需调用Thread.sleep()。而是使用javax.swing.Timer
  3. 从EDT运行您的程序
  4. 请勿new ImageIcon方法中创建paint。每次调用repaint()时,它都会创建新的ImageIcon对象。相反,在构造函数中实例化它。
  5. 这是代码的重构。

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class SplashScreen extends JFrame {
    
        Image img1;
        int w = 900, h = 600;
        int x = 0, y = 0;
    
        public SplashScreen() {
    
            setLayout(new BorderLayout());
    
            add(new MyPanel());
            setTitle("BlueJay");
            setSize(900, 600);
    
            getContentPane().setBackground(Color.black);
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setLocationRelativeTo(null);
            setVisible(true);
    
            requestFocus();
            setFocusable(true);
    
        }
    
        private class MyPanel extends JPanel {
    
            public MyPanel() {
                img1 = new ImageIcon(SplashScreen.class.getResource("/resources/stackoverflow5.png")).getImage();
                setBackground(Color.black);
                setLayout(new GridLayout());
                Timer timer = new Timer(20, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        w -= 5;
                        h -= 5;
                        y -= 2;
                        x += 1;
    
                        if (y == -250) {
                            new MainMenu_BlueJay().setVisible(true);
                            dispose();
                        }
                        repaint();
                    }
                });
                timer.start();
            }
    
            @Override
            public void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g;
    
                //AffineTransform at = new AffineTransform();
                // at.scale(w, h);
                // g2d.setTransform(at);
                g2d.drawImage(img1, x, y, w, h, this);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(900, 600);
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new SplashScreen();
                }
            });
    
        }
    }
    

    我对Graphics2D不太熟悉所以我评论了AffirmTransformation的内容,但修复了你的其他问题。