【问题标题】:Swing MapPanel updating GraphicsSwing MapPanel 更新图形
【发布时间】:2015-07-07 15:55:17
【问题描述】:

尝试创建具有图形地图概览的面板。地图概览显示完整地图的 10x10 块(因此始终只显示特定区域)。这导致有 100 个 MapTile 对象,每个对象代表 MapPanel 类中的一个图块。每个 MapTile 都包含一个当前显示的 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。到目前为止,这确实有效,但是我无法更新视图。

视图需要在以下时间更新:

  1. 我们改变渲染区域(地图也可以是例如 200x200,但我们总是只渲染它的 10x10 区域。所以我们可以在每个方向上“行走”并渲染地图的不同区域)
  2. 一个人搬家(简单更新新旧字段)
  3. 一个人死了(简单更新旧字段)

这是我的 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();
    }
}

所以到目前为止,我在 Google 上搜索了很多,并在 JPanel 中找到了一些关于几张图像的帖子,但没有关于如何更新它们的帖子……我尝试了默认 repaint();这是行不通的。有人有什么想法吗?谢谢!

【问题讨论】:

  • 您需要将您的程序结构更改为更多的 MVC(模型-视图-控制)类型结构,并拥有您的视图——上面的 GUI,监听模型的变化(逻辑部分您的程序)并在发生更改时自行更新。
  • 在 TilePanel 的 render() 方法的嵌套 for 循环内,如果在瓷砖上调用 update() 后调用 tiles.get(tileCounter).repaint(); 会发生什么?
  • 完全没有任何反应。使用 tiles.get(tileCounter).repaint() 将简单地调用 repaint() 这是我已经在 update() 中所做的......
  • 确实你是对的,对不起。

标签: java swing animation jpanel


【解决方案1】:

您似乎需要改进 MapTile 的 update(Field field) 方法,使其从 Field 对象中提取所有信息,类似于您的构造函数。

即,

    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();
    }

    public MapTile(Field field) throws MidWarGeneralException {
        updateField(field);
    }

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    • 2018-01-22
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    相关资源
    最近更新 更多