繁体   English   中英

从其他课程上借鉴JPanel

[英]Draw on JPanel from other class

在我的程序中,我尝试在按下鼠标时在JPanel上绘画。 mousePressed方法仅用于测试另一类的绘画。 稍后,spawn方法将由其他类方法调用。 当我按下鼠标按钮时,将调用spawnPedestrian() ,但未绘制任何Pedestrian 下面是一个正在运行的示例,其中包含我项目中的代码。 如果创建项目Roundabout并将此代码粘贴到其中,则应该能够运行它(图像是热链接的)。 如何修复spawnPedestrian()方法?

public class Roundabout extends JFrame {

public static Surface surface;

public Roundabout() {
    initUI();
}

private void initUI() {
    setTitle("Roundabout");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    surface = new Surface();
    add(surface); 
    this.addMouseListener(new MouseAdapter() {// empty implementation of all
        // MouseListener`s methods
        @Override
        public void mousePressed(MouseEvent e) {
            //Spawn
            Spawn sp = new Spawn();
            sp.spawnPedestrian(300, 100);
        }
    });

    setSize(1618, 850);
    setLocationRelativeTo(null);
}

public static JPanel getSurface() {
    return surface;
}

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            Roundabout roundabout = new Roundabout();
            roundabout.setVisible(true);
        }
    });
}

//Track class
class Track {

    BufferedImage track;
    Point trackPosition;
    Point TRACK_POS = new Point(0, 0);

    public Track() {
        try {
            track = ImageIO.read(new URL("http://i.stack.imgur.com/2U3j5.png"));
        } catch (Exception ex) {
            System.out.println("Problem loading track image: " + ex);
        }
        trackPosition = new Point(TRACK_POS.x, TRACK_POS.y);
    }

    public void paint(Graphics g) {
        g.drawImage(track, TRACK_POS.x, TRACK_POS.y, null);
    }

}

//Surface class
public class Surface extends JPanel {

    Track track = new Track();

    public List<Vehicle> toDraw = new ArrayList<>();

    public Surface() {
        Pedestrian p = new Pedestrian(100, 100);
        toDraw.add(p);
    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        //setLayout(null);
        track.paint(g);
        //Make sure the track is painted first
        for (Vehicle v : toDraw) {
            v.paint(g);
        }

    }

}

class Pedestrian extends Vehicle {

    BufferedImage pedestrian;
    Point pedestrianPosition;
    double pedestrianRotation = 0;
    int pedestrianW, pedestrianH;

    public Pedestrian(int x, int y) {
        try {
            pedestrian = ImageIO.read(new URL("http://i.stack.imgur.com/wm0I5.png"));
        } catch (IOException e) {
            System.out.println("Problem loading pedestrian images: " + e);
        }

        pedestrianPosition = new Point(x, y);
        pedestrianW = pedestrian.getWidth();
        pedestrianH = pedestrian.getHeight();
    }

    @Override
    public void paint(Graphics g) {

        Graphics2D g2d = (Graphics2D) g;

        g2d.rotate(Math.toRadians(pedestrianRotation), pedestrianPosition.x, pedestrianPosition.y);

        g2d.drawImage(pedestrian, pedestrianPosition.x, pedestrianPosition.y, null);

    }

    @Override
    public void setPath(List<Point> path) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void update(double i) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}

//Spawn class
class Spawn {

    public void spawnPedestrian(int x, int y) {
        //Create a new pedestrian.        

        System.out.println("Spawn a pedestrian.");
        Pedestrian p = new Pedestrian(x, y);

        Roundabout.surface.toDraw.add(p);
        Roundabout.surface.revalidate();
        Roundabout.surface.repaint();            

    }
}

public abstract class Vehicle {

    public abstract void setPath(List<Point> path);

    public abstract void update(double i);

    public abstract void paint(Graphics g);
    }
}

编辑:现在可以通过单击鼠标来生成Pedestrian

基本上,您想分离代码并将负责人集中到类。 因此,“数据”应由某种模型维护,渲染应由某种视图处理,模型和视图的更新应由某种控制器处理。

这使得交换任何一部分变得更容易,而无需一大堆新代码或其他更改。 这也意味着每个类都有一个明确的责任范围,并阻止您尝试例如从视图中对状态进行更改,而该更改应由模型处理(这可能会使状态陷入混乱)

让我们从要绘画的东西开始

public interface Sprite {

    public void paint(Graphics2D g2d);

}

public interface MoveableSprite extends Sprite {

    public void update(Container container);

}

它们代表静态精灵(例如树)或正在移动(并希望定期更新的精灵)

这些都包含在模型中

public interface GameModel {

    public List<Sprite> getSprites();

    public void setObserver(Observer<MoveableSprite> observer);

    public Observer<MoveableSprite> getObserver();

    public void spawnSprite();

}

它提供了一些方法,可以通知(在这种情况下,是单个)有关方某种状态更改。 对于此示例,这意味着新的MoveableSprite已可用

Observer是非常基本的,只有一个回叫...

public interface Observer<T> {

    public void stateChanged(T parent);

}

还有帮助驱动它的“引擎”

public class GameEngine {

    private GameModel model;
    private SurfacePane surface;
    private Timer timer;

    public GameEngine(GameModel model, SurfacePane surface) {
        this.model = model;
        this.surface = surface;

        model.setObserver(new Observer<MoveableSprite>() {
            @Override
            public void stateChanged(MoveableSprite sprite) {
                sprite.update(getSurface());
            }
        });

        timer = new Timer(40, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                for (Sprite sprite : getModel().getSprites()) {
                    if (sprite instanceof MoveableSprite) {
                        ((MoveableSprite) sprite).update(getSurface());
                    }
                }
                getSurface().repaint();
            }
        });
    }

    public GameModel getModel() {
        return model;
    }

    public SurfacePane getSurface() {
        return surface;
    }

    public void start() {
        timer.start();
    }

    public void stop() {
        timer.stop();
    }

}

这是一个非常基本的示例,但是从根本上讲,它会更新MoveableSprite的位置,并要求表面重新绘制自身。 它还会观察GameModel是否有任何新的精灵,它将立即更新其位置,因此它们不会出现在某些“怪异”的地方

好的,现在我们实际上需要实现其中的一些功能

public class DefaultGameModel implements GameModel {

    private Observer<MoveableSprite> observer;
    private List<Sprite> sprites;

    public DefaultGameModel() {
        sprites = new ArrayList<>(25);
        for (int index = 0; index < 10; index++) {
            spawnSprite();
        }
    }

    @Override
    public List<Sprite> getSprites() {
        return Collections.unmodifiableList(sprites);
    }

    public void spawnSprite() {
        try {
            ZombieSprite sprite = new ZombieSprite();
            sprites.add(sprite);

            Observer<MoveableSprite> observer = getObserver();
            if (observer != null) {
                observer.stateChanged(sprite);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setObserver(Observer<MoveableSprite> observer) {
        this.observer = observer;
    }

    @Override
    public Observer<MoveableSprite> getObserver() {
        return observer;
    }

}

public class ZombieSprite implements MoveableSprite {

    private int x;
    private int y;

    private int xDelta;
    private int yDelta;

    private BufferedImage img;

    private Observer<Sprite> observer;
    private boolean initialised = false;

    public ZombieSprite() throws IOException {
        img = ImageIO.read(getClass().getResource("/LogoZombi.png"));
    }

    @Override
    public void update(Container container) {
        if (!initialised) {
            x = (int) (Math.random() * container.getWidth());
            y = (int) (Math.random() * container.getHeight());

            Random rnd = new Random();
            xDelta = rnd.nextBoolean() ? 1 : -1;
            yDelta = rnd.nextBoolean() ? 1 : -1;
            initialised = true;
        }
        x += xDelta;
        y += yDelta;

        if (x < 0) {
            x = 0;
            xDelta *= -1;
        } else if (x + img.getWidth() > container.getWidth()) {
            x = container.getWidth() - img.getWidth();
            xDelta *= -1;
        }
        if (y < 0) {
            y = 0;
            yDelta *= -1;
        } else if (y + img.getHeight() > container.getHeight()) {
            y = container.getHeight() - img.getHeight();
            yDelta *= -1;
        }
    }

    @Override
    public void paint(Graphics2D g2d) {
        g2d.drawImage(img, x, y, null);
    }

}

这两个类实现了GameModelMoveableSprite接口。 我们使用接口来解耦代码,这使更改工作方式变得更加容易,并为约定的合同和实现的例外提供了一个起点。

最后,实际上可以描绘出当前状态的东西...

public class SurfacePane extends JPanel {

    private GameModel model;

    public SurfacePane(GameModel model) {
        this.model = model;

        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                getModel().spawnSprite();
            }
        });
    }

    public GameModel getModel() {
        return model;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        GameModel model = getModel();
        for (Sprite sprite : model.getSprites()) {
            sprite.paint(g2d);
        }
        g2d.dispose();
    }

}

您不会发现此类具有MouseListener ,这是故意的,因为可能添加到此容器中的其他组件可能会阻止MouseListener收到通知,因此请不要这样做。 但是MouseListener只是调用模型以生成另一个僵尸...

最后,我们需要完全了解它...

GameModel model = new DefaultGameModel();
SurfacePane surfacePane = new SurfacePane(model);
GameEngine engine = new GameEngine(model, surfacePane);

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(surfacePane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

engine.start();

只是因为我知道有很多不相干的概念可以组合在一起,所以是一个完整的示例...

import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeListener;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                GameModel model = new DefaultGameModel();
                SurfacePane surfacePane = new SurfacePane(model);
                GameEngine engine = new GameEngine(model, surfacePane);

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(surfacePane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                engine.start();
            }
        });
    }

    public class SurfacePane extends JPanel {

        private GameModel model;

        public SurfacePane(GameModel model) {
            this.model = model;

            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    getModel().spawnSprite();
                }
            });
        }

        public GameModel getModel() {
            return model;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            GameModel model = getModel();
            for (Sprite sprite : model.getSprites()) {
                sprite.paint(g2d);
            }
            g2d.dispose();
        }

    }

    public class GameEngine {

        private GameModel model;
        private SurfacePane surface;
        private Timer timer;

        public GameEngine(GameModel model, SurfacePane surface) {
            this.model = model;
            this.surface = surface;

            model.setObserver(new Observer<MoveableSprite>() {
                @Override
                public void stateChanged(MoveableSprite sprite) {
                    sprite.update(getSurface());
                }
            });

            timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    for (Sprite sprite : getModel().getSprites()) {
                        if (sprite instanceof MoveableSprite) {
                            ((MoveableSprite) sprite).update(getSurface());
                        }
                    }
                    getSurface().repaint();
                }
            });
        }

        public GameModel getModel() {
            return model;
        }

        public SurfacePane getSurface() {
            return surface;
        }

        public void start() {
            timer.start();
        }

        public void stop() {
            timer.stop();
        }

    }

    public interface Observer<T> {

        public void stateChanged(T parent);

    }

    public interface Sprite {

        public void paint(Graphics2D g2d);

    }

    public interface MoveableSprite extends Sprite {

        public void update(Container container);

    }

    public interface GameModel {

        public List<Sprite> getSprites();

        public void setObserver(Observer<MoveableSprite> observer);

        public Observer<MoveableSprite> getObserver();

        public void spawnSprite();

    }

    public class DefaultGameModel implements GameModel {

        private Observer<MoveableSprite> observer;
        private List<Sprite> sprites;

        public DefaultGameModel() {
            sprites = new ArrayList<>(25);
            for (int index = 0; index < 10; index++) {
                spawnSprite();
            }
        }

        @Override
        public List<Sprite> getSprites() {
            return Collections.unmodifiableList(sprites);
        }

        public void spawnSprite() {
            try {
                ZombieSprite sprite = new ZombieSprite();
                sprites.add(sprite);

                Observer<MoveableSprite> observer = getObserver();
                if (observer != null) {
                    observer.stateChanged(sprite);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void setObserver(Observer<MoveableSprite> observer) {
            this.observer = observer;
        }

        @Override
        public Observer<MoveableSprite> getObserver() {
            return observer;
        }

    }

    public class ZombieSprite implements MoveableSprite {

        private int x;
        private int y;

        private int xDelta;
        private int yDelta;

        private BufferedImage img;

        private Observer<Sprite> observer;
        private boolean initialised = false;

        public ZombieSprite() throws IOException {
            img = ImageIO.read(getClass().getResource("/LogoZombi.png"));
        }

        @Override
        public void update(Container container) {
            if (!initialised) {
                x = (int) (Math.random() * container.getWidth());
                y = (int) (Math.random() * container.getHeight());

                Random rnd = new Random();
                xDelta = rnd.nextBoolean() ? 1 : -1;
                yDelta = rnd.nextBoolean() ? 1 : -1;
                initialised = true;
            }
            x += xDelta;
            y += yDelta;

            if (x < 0) {
                x = 0;
                xDelta *= -1;
            } else if (x + img.getWidth() > container.getWidth()) {
                x = container.getWidth() - img.getWidth();
                xDelta *= -1;
            }
            if (y < 0) {
                y = 0;
                yDelta *= -1;
            } else if (y + img.getHeight() > container.getHeight()) {
                y = container.getHeight() - img.getHeight();
                yDelta *= -1;
            }
        }

        @Override
        public void paint(Graphics2D g2d) {
            g2d.drawImage(img, x, y, null);
        }

    }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM