强制调用JPanel中的getPreferredSize()

时间:2017-08-17 20:31:12

标签: java swing graphics jpanel

在我开始之前,我知道我可能会问错误的问题,也许我正在尝试做的是一个非常糟糕的主意。如果是这种情况,请告诉我。

我有一个类覆盖JPanel方法getPreferredSize()并返回具有特定宽度和高度的自定义Dimension对象。但是,当我在方法中放入调试println()语句时,我注意到它只在创建时调用一次,并且在此之后从未调用过。我需要在内容发生变化时调整JPanel的大小(不,JScrollPane绝对不是我想要的),但我不知道如何强制召回{{1}方法。

如果有人能向我解释我如何回忆这种方法,我们将不胜感激。提前谢谢大家!

以下是我的代码的MCVE:

getPreferredSize()

1 个答案:

答案 0 :(得分:1)

正如我们之前讨论的那样(当你有不同的用户ID时),在这种情况下更容易使用JPanel或JLabel来保存精灵,而是使用单个绘图JPanel,然后绘制精灵,这个单一绘图JPanel中需要的任何一方。以下是使用此精灵表的示例:

enter image description here

this site获得。

同样,它是在JPanel的paintComponent方法中绘制并使用Key Bindings来指示移动方向的示例。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.*;

@SuppressWarnings("serial")
public class Mcve3 extends JPanel {
    private static final int PREF_W = 800;
    private static final int PREF_H = 640;
    private static final int TIMER_DELAY = 50;

    private int spriteX = 400;
    private int spriteY = 320;
    private SpriteDirection spriteDirection = SpriteDirection.RIGHT;
    private MySprite sprite = null;
    private Timer timer = null;

    public Mcve3() {
        try {
            sprite = new MySprite(spriteDirection, spriteX, spriteY);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        setBackground(Color.WHITE);

        setKeyBindings(SpriteDirection.LEFT, KeyEvent.VK_LEFT);
        setKeyBindings(SpriteDirection.RIGHT, KeyEvent.VK_RIGHT);
        setKeyBindings(SpriteDirection.FORWARD, KeyEvent.VK_DOWN);
        setKeyBindings(SpriteDirection.AWAY, KeyEvent.VK_UP);

        timer = new Timer(TIMER_DELAY, new TimerListener());
        timer.start();
    }

    private void setKeyBindings(SpriteDirection dir, int keyCode) {
        int condition = WHEN_IN_FOCUSED_WINDOW;
        InputMap inputMap = getInputMap(condition);
        ActionMap actionMap = getActionMap();

        KeyStroke keyPressed = KeyStroke.getKeyStroke(keyCode, 0, false);
        KeyStroke keyReleased = KeyStroke.getKeyStroke(keyCode, 0, true);

        inputMap.put(keyPressed, keyPressed.toString());
        inputMap.put(keyReleased, keyReleased.toString());

        actionMap.put(keyPressed.toString(), new MoveAction(dir, false));
        actionMap.put(keyReleased.toString(), new MoveAction(dir, true));
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        sprite.draw(g);
    }

    private class MoveAction extends AbstractAction {
        private SpriteDirection dir;
        private boolean released;

        public MoveAction(SpriteDirection dir, boolean released) {
            this.dir = dir;
            this.released = released;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (released) {
                sprite.setMoving(false);
            } else {
                sprite.setMoving(true);
                sprite.setDirection(dir);
            }
        }
    }

    private class TimerListener implements ActionListener {
        @Override
            public void actionPerformed(ActionEvent e) {
                if (sprite.isMoving()) {
                    sprite.tick();
                }
                repaint();
            }
    }

    private static void createAndShowGui() {
        Mcve3 mainPanel = new Mcve3();

        JFrame frame = new JFrame("MCVE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

class MySprite {
    private static final String SPRITE_SHEET_PATH = "http://"
            + "orig12.deviantart.net/7db3/f/2010/338/3/3/"
            + "animated_sprite_sheet_32x32_by_digibody-d3479l2.gif";
    private static final int MAX_MOVING_INDEX = 4;
    private static final int DELTA = 4;
    private SpriteDirection direction;
    private Map<SpriteDirection, Image> standingImgMap = new EnumMap<>(SpriteDirection.class);
    private Map<SpriteDirection, List<Image>> movingImgMap = new EnumMap<>(SpriteDirection.class);
    private int x;
    private int y;
    private boolean moving = false;
    private int movingIndex = 0;

    public MySprite(SpriteDirection direction, int x, int y) throws IOException {
        this.direction = direction;
        this.x = x;
        this.y = y;
        createSprites();
    }

    public void draw(Graphics g) {
        Image img = null;
        if (!moving) {
            img = standingImgMap.get(direction);
        } else {
            img = movingImgMap.get(direction).get(movingIndex);
        }
        g.drawImage(img, x, y, null);
    }

    private void createSprites() throws IOException {
        URL spriteSheetUrl = new URL(SPRITE_SHEET_PATH);
        BufferedImage img = ImageIO.read(spriteSheetUrl);

        // get sub-images (sprites) from the sprite sheet
        // magic numbers for getting sprites from sheet, all obtained by trial and error
        int x0 = 0;
        int y0 = 64;
        int rW = 32;
        int rH = 32;
        for (int row = 0; row < 4; row++) {
            SpriteDirection dir = SpriteDirection.values()[row];
            List<Image> imgList = new ArrayList<>();
            movingImgMap.put(dir, imgList);
            int rY = y0 + row * rH;
            for (int col = 0; col < 5; col++) {
                int rX = x0 + col * rW;
                BufferedImage subImg = img.getSubimage(rX, rY, rW, rH);
                if (col == 0) {
                    // first image is standing
                    standingImgMap.put(dir, subImg);
                } else {
                    // all others are moving
                    imgList.add(subImg);
                }
            }
        }
    }

    public SpriteDirection getDirection() {
        return direction;
    }

    public void setDirection(SpriteDirection direction) {
        if (this.direction != direction) {
            setMoving(false);
        }
        this.direction = direction;

    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public boolean isMoving() {
        return moving;
    }

    public void setMoving(boolean moving) {
        this.moving = moving;
        if (!moving) {
            movingIndex = 0;
        }
    }

    public void tick() {
        if (moving) {
            switch (direction) {
            case RIGHT:
                x += DELTA;
                break;
            case LEFT:
                x -= DELTA;
                break;
            case FORWARD:
                y += DELTA;
                break;
            case AWAY:
                y -= DELTA;
            }
            movingIndex++;
            movingIndex %= MAX_MOVING_INDEX;
        }
    }

    public int getMovingIndex() {
        return movingIndex;
    }

    public void setMovingIndex(int movingIndex) {
        this.movingIndex = movingIndex;
    }

}

enum SpriteDirection {
    FORWARD, LEFT, AWAY, RIGHT
}

使用您的代码的示例:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

@SuppressWarnings("serial")
public class Rotation2 extends JPanel {

    private static final int PREF_W = 750;
    private static final int PREF_H = PREF_W;
    private BufferedImage image = new BufferedImage(400, 400, BufferedImage.TYPE_INT_ARGB);
    private double theta = 0.0;
    private JSlider slider = new JSlider(0, 360, 0);

    public Rotation2() {
        Graphics2D g2 = (Graphics2D) image.createGraphics();
        g2.setColor(Color.red);
        g2.fillRect(0, 0, image.getWidth(), image.getHeight());
        g2.dispose(); 

        slider.setMajorTickSpacing(90);
        slider.setMinorTickSpacing(10);
        slider.setPaintTicks(true);
        slider.setPaintLabels(true);
        slider.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                theta = Math.toRadians(slider.getValue());
                revalidate();
                repaint();
            }
        });
        JPanel bottomPanel = new JPanel();
        bottomPanel.add(slider);
        setLayout(new BorderLayout());
        add(bottomPanel, BorderLayout.PAGE_END);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g.create();
        int x = PREF_W / 2;
        int y = PREF_H / 2;
        g2.rotate(theta, x, y);
        int imgX = (PREF_W - image.getWidth()) / 2;
        int imgY = (PREF_H - image.getHeight()) / 2;
        g2.drawImage(image, imgX, imgY, this);
        g2.dispose();
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    private static void createAndShowGui() {
        JFrame frame = new JFrame("Rotation2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new Rotation2());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}