为什么getScaledInstance()不起作用?

时间:2015-10-24 02:27:54

标签: java image swing paint scaling

所以,我正在努力创造一个垄断游戏。我正在尝试将(电路板的)图像加载到JPanel

我首先想要将图像缩放为1024*1024图像。

我已经将图像显示在JPanel上(因此文件地址有效)。

但每当我使用getScaledInstance()方法时,图像都不会出现

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

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.SystemColor;

//a class that represent the board (JFrame) and all of it components 
public class Board extends JFrame {
private final int SCALE;
private JPanel panel;

public Board(int scale) {
    getContentPane().setBackground(SystemColor.textHighlightText);
    // SCALE = scale;
    SCALE = 1;
    // set up the JFrame
    setResizable(false);
    setTitle("Monopoly");
    // set size to a scale of 1080p
    setSize(1920 * SCALE, 1080 * SCALE);
    getContentPane().setLayout(null);

    panel = new JPanel() {
        public void paint(Graphics g) {
            Image board = new ImageIcon(
                    "C:\\Users\\Standard\\Pictures\\Work\\Monopoly 1.jpg")
                    .getImage();
            board = board.getScaledInstance(1022, 1024, java.awt.Image.SCALE_SMOOTH);

            g.drawImage(board, 0, 0, null);
        }
    };
    panel.setBounds(592, 0, 1024, 1024);
    getContentPane().add(panel);
}

public static void main(String[] args) {
    Board board = new Board(1);
    board.setVisible(true);
    board.panel.repaint();
 }
}

每当我删除board.getScaledInstance()代码行时,图像就会出现(虽然没有缩放),但是当我添加代码行时,图像根本不会出现。

为什么会这样?

1 个答案:

答案 0 :(得分:2)

你做错了几件事:

  • 你重写油漆,而不是paintComponent。这是危险的,因为你重写的图像太多而且责任太大。不加理会这样做可能会导致严重的图像副作用,并且由于油漆不会产生双重缓冲,也会导致动画效果变慢。
  • 你没有在你的覆盖中调用超级绘画方法,这会导致绘画工件的积累和Swing组件绘画链的破坏。
  • 您可能会在绘画方法中多次读取图像,这种方法必须尽可能快,因为它是应用程序感知响应性的主要决定因素。只读一次,然后将其保存到变量中。
  • 您正在使用null布局和setBounds。虽然null布局和setBounds()似乎是Swing新手,比如创建复杂GUI的最简单和最好的方法,但是你创建的Swing GUI越多,你在使用它们时会遇到更严重的困难。 。当GUI调整大小时,他们不会调整组件的大小,他们是增强或维护的皇室女巫,当他们放置在滚动窗格中时,他们完全失败,当他们在所有平台或屏幕分辨率不同时看起来很糟糕原来的。
  • 您在绘制方法中缩放图像,再次执行会降低GUI感知响应速度的操作。相反,仅将图像缩放一次,并将该缩放图像保存为变量。
  • 重要的是,您为原始图像和缩放图像使用相同的变量板,这将导致每次调用绘制时重新缩放图像。
  • 正如Mad指出的那样,您应该将this传递给g.drawImage(...)方法调用,以便在完全读入之前不要绘制图像。
  • 另外,当您不将其用作ImageIcon时,请不要将图像作为文件或ImageIcon读取。使用ImageIO将其作为BufferedImage读取,并使用资源,而不是文件。

我也会简化一些事情,例如:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;

@SuppressWarnings("serial")
public class MyBoard extends JPanel {
    private static final String IMG_PATH = "http://ecx.images-amazon.com/"
            + "images/I/81oC5pYhh2L._SL1500_.jpg";

    // scaling constants
    private static final int IMG_WIDTH = 1024;
    private static final int IMG_HEIGHT = IMG_WIDTH;

    // original and scaled image variables
    private BufferedImage initialImg;
    private Image scaledImg;

    public MyBoard() throws IOException {
        URL url = new URL(IMG_PATH);
        initialImg = ImageIO.read(url); // read in original image

        // and scale it *once* and store in variable. Can even discard original
        // if you wish
        scaledImg = initialImg.getScaledInstance(IMG_WIDTH, IMG_HEIGHT,
                Image.SCALE_SMOOTH);
    }

    // override paintComponent, not paint
    @Override   // and don't forget the @Override annotation
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); // call the super's painting method

        // just to be safe -- check that it's not null first
        if (scaledImg != null) {
            // use this as a parameter to avoid drawing an image before it's
            // ready
            g.drawImage(scaledImg, 0, 0, this);
        }
    }

    // so our GUI is sized the same as the image
    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet() || scaledImg == null) {
            return super.getPreferredSize();
        }
        int w = scaledImg.getWidth(this);
        int h = scaledImg.getHeight(this);
        return new Dimension(w, h);
    }

    private static void createAndShowGui() {
        MyBoard mainPanel = null;
        try {
            mainPanel = new MyBoard();
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }

        JFrame frame = new JFrame("My Board");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}