使用线程缩放图像 - JAVA

4

假设我有一张图片。我把这张图片放在一个JPanel里面,再把JPanel放在一个JFrame内。使用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 函数(只是从底部向上移动),图像会显示并移动,但边框会快速闪烁。

有什么想法来解决这个问题,使我能够同时缩小图像并移动它,并解决闪烁的边框问题吗?


1
首先,您的线程访问变量应该是volatile的。其次,在线程内部的paint调用必须用SwingUtilities.invokeLater()包围起来。 - morpheus05
如果不使用线程,如何减少变量的值? - noobprogrammer
2个回答

2
你不应该覆盖JFrame的paint方法。如果你想要绘制任何东西,你应该在一个扩展JPanel的类中绘制,在那里你覆盖paintComponent方法。
你不应该在绘图方法中加载图像。这是非常低效的。你应该只加载一次图像,可能是在构造函数中。
你不应该调用Graphics2D#setTransform()方法。查看JavaDoc http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html#setTransform%28java.awt.geom.AffineTransform%29,它明确说明:
警告:此方法永远不应该用于在现有变换上应用新的坐标变换。
你应该考虑你的“w”和“h”值。它们应该是绘制的图像的大小,还是用作图像的缩放因子?将它们设置为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);
    }
}

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

以下是代码重构。

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部分,但是修复了你的其他问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接