Java Swing MapPanel更新图形

Java Swing MapPanel更新图形,java,swing,animation,jpanel,Java,Swing,Animation,Jpanel,正在尝试创建具有图形地图概述的面板。地图概览显示了整个地图的10x10个分幅(因此始终只显示特定区域)。这导致有100个MapTile对象,每个对象表示MapPanel类中的一个tile。每个MapTile都包含一个当前正在显示的字段对象。field对象保存了大量数据,例如,如果它被阻止,哪个人站在field上,field是哪种类型,等等(可能的类型是草地、泥土、石头等) 每当发生变化时,我需要更新MapPanel,使其显示实际情况,而不是我实例化的情况。这就是我目前失败的地方 这就是我到目前为

正在尝试创建具有图形地图概述的面板。地图概览显示了整个地图的10x10个分幅(因此始终只显示特定区域)。这导致有100个MapTile对象,每个对象表示MapPanel类中的一个tile。每个MapTile都包含一个当前正在显示的字段对象。field对象保存了大量数据,例如,如果它被阻止,哪个人站在field上,field是哪种类型,等等(可能的类型是草地、泥土、石头等)

每当发生变化时,我需要更新MapPanel,使其显示实际情况,而不是我实例化的情况。这就是我目前失败的地方

这就是我到目前为止所做的:

public class MapTile extends JPanel {
    private BufferedImage backgroundImage;
    private BufferedImage fighterImage;
    private Field field;

    stuff...

    public MapTile(Field field) throws MidWarGeneralException {
        loadBackgroundImage(field.getType());
        if(field.isOccupied()) {
            loadFighterImage(field.getFighter().getTeam());
        }
        setToolTip(field);
        this.field = field;
    }

    private void setToolTip(Field field) {
        if(field.isOccupied()) {
            setToolTipText(field.getX() + "/" + field.getY() + "\n"
                    + "used by: " + field.getFighter().getName() + "(Team: " + field.getFighter().getTeam().getName()
                    + ")\n" + "Type: " + field.getType().getName());
        }
        else {
            setToolTipText(field.getX() + "/" + field.getY() + "\n" +
                    "Type: " + field.getType().getName());
        }
    }

    private void loadBackgroundImage(TileType type) {
        stuff...
    }

    private void loadFighterImage(Team team) {
       stuff ...
    }

    public void update(Field field) {
        this.field = field;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics graphics) {
        super.paintComponent(graphics);
        Graphics2D g2d = (Graphics2D) graphics;
        g2d.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this);
        if(fighterImage != null) {
            g2d.drawImage(fighterImage, 0, 0, getWidth(), getHeight(), this);
        }
    }
}
这两个load()函数都将根据当前字段对象的当前数据加载相应的图像。我想要的是:MapTile对象始终有一个背景(grass.png、stone.png等),如果字段被一个人占用,它将以团队的颜色在其上绘制person.jpg。到目前为止,这确实有效,但是我无法更新视图

在以下情况下,视图需要更新:

  • 我们更改渲染区域(贴图也可以是200x200,但我们始终只渲染其中的10x10区域。因此,我们可以在每个方向“行走”,并渲染贴图的不同区域)
  • 人员移动(只需更新新旧字段)
  • 有人死亡(只需更新旧字段)
  • 这是我的MapPanel类:

    public class MapPanel extends JPanel {
        private Map map;
        private int currentX;
        private int currentY;
        private List<MapTile> tiles;
    
        public MapPanel(Map map) {
            this.map = map;
            this.currentX = 0;
            this.currentY = 0;
            this.tiles = new ArrayList<>();
    
            init();
        }
    
        private int[] calcRenderArea() {
            currentX = (currentX > map.getWidth()) ? map.getWidth() : currentX;
            currentY = (currentY > map.getHeight()) ? map.getHeight() : currentY;
    
            int difX = map.getWidth() - currentX;
            int difY = map.getHeight() - currentY;
    
            currentX = (difX < 10) ? currentX - (10 - difX) : currentX;
            currentX = (difY < 10) ? currentY - (10 - difY) : currentY;
    
            return new int[]{currentX, currentY};
        }
    
        private void render() {
            int[] offsets = calcRenderArea();
            int tileCounter = 0;
            for(int x = offsets[0]; x < 10; x++) {
                for(int y = offsets[1]; y < 10; y++, tileCounter++) {
                    tiles.get(tileCounter).update(map.getField(x + offsets[0], y + offsets[1]));
                }
            }
        }
    
        private void init() {
            setLayout(new GridLayout(10, 10));
            for(int i = 0; i < 10; i++) {
                for(int j = 0; j < 10; j++) {
                    MapTile tile = new MapTile(map.getField(i, j));
                    tile.setBorder(BorderFactory.createLineBorder(GUIConfig.BORDER_COLOR));
                    add(tile);
                    tiles.add(tile);
                }
            }
        }
    
        public void toLeft() {
            currentX -= 1;
            update();
        }
    
        public void toRight() {
            currentX += 1;
            update();
        }
    
        public void toTop() {
            currentY -= 1;
            update();
        }
    
        public void toBottom() {
            currentY += 1;
            update();
        }
    
        public void update() {
            // Todo :fix the map panel updating
            render();
        }
    }
    
    公共类映射面板扩展了JPanel{
    私人地图;
    私有int-currentX;
    私营企业;
    私人名单瓷砖;
    公共地图面板(地图){
    this.map=map;
    这个.currentX=0;
    该电流y=0;
    this.tiles=新的ArrayList();
    init();
    }
    私有int[]calcRenderArea(){
    currentX=(currentX>map.getWidth())?map.getWidth():currentX;
    currentY=(currentY>map.getHeight())?map.getHeight():currentY;
    int difX=map.getWidth()-currentX;
    int difY=map.getHeight()-currentY;
    currentX=(difX<10)?currentX-(10-difX):currentX;
    currentX=(difY<10)?currentY-(10-difY):currentY;
    返回新的int[]{currentX,currentY};
    }
    私有void render(){
    int[]偏移量=calcRenderArea();
    int tileCounter=0;
    对于(int x=偏移量[0];x<10;x++){
    对于(int y=偏移量[1];y<10;y++,tileCounter++){
    tiles.get(tileCounter).update(map.getField(x+offset[0],y+offset[1]);
    }
    }
    }
    私有void init(){
    setLayout(新网格布局(10,10));
    对于(int i=0;i<10;i++){
    对于(int j=0;j<10;j++){
    MapTile tile=新的MapTile(map.getField(i,j));
    tile.setboorder(BorderFactory.createLineBorder(GUIConfig.BORDER_COLOR));
    添加(瓷砖);
    瓷砖。添加(瓷砖);
    }
    }
    }
    公共收费表(){
    电流x-=1;
    更新();
    }
    公共权利{
    电流x+=1;
    更新();
    }
    公共无效toTop(){
    电流y-=1;
    更新();
    }
    托博托姆公共空间(){
    电流y+=1;
    更新();
    }
    公共无效更新(){
    //Todo:修复地图面板更新
    render();
    }
    }
    

    所以到目前为止,我在谷歌上搜索了很多,找到了一些关于JPanel中几个图像的帖子,但没有关于如何更新它们的帖子。。。我尝试了默认重新绘制();这不管用。有人有什么想法吗?谢谢

    看起来您需要改进MapTile的
    update(Field)
    方法,以便它从Field对象中提取所有信息,与构造函数类似

    i、 e

        public final void update(Field field) {
            // this.field = field;
            loadBackgroundImage(field.getType());
            if(field.isOccupied()) {
                loadFighterImage(field.getFighter().getTeam());
            }
            setToolTip(field);
            this.field = field;
            repaint();
        }
    



    但作为一个“侧面”建议,一个不会解决您最初的问题但可能有助于解决未来问题的建议,我建议您将程序结构更改为更多的MVC(模型-视图-控制)类型结构,并让您的视图(上面的GUI)侦听对模型的更改(程序的逻辑部分)并在发生更改时自我更新。

    您需要将程序结构更改为更多MVC(模型-视图-控制)类型的结构,并让您的视图(上面的GUI)侦听对模型(程序的逻辑部分)的更改并在发生更改时更新自身。在TilePanel的
    render()
    方法的嵌套for循环中,如果在tile上调用
    tiles.get(tileCounter.repaint();
    之后调用
    update()
    ,会发生什么?完全不会发生任何事情。使用tiles.get(tileCounter.repaint()将只调用repaint())这是我在update()中已经做过的…事实上你是对的,对不起。
        public MapTile(Field field) throws MidWarGeneralException {
            updateField(field);
        }