尝试创建一个带有图形 map 概览的面板。 map 概览显示完整 map 的 10x10 block (因此始终只显示特定区域)。这导致有 100 个 MapTile 对象,每个对象代表 MapPanel 类中的一个图 block 。每个 MapTile 都包含一个当前正在显示的 Field 对象。一个 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。到目前为止这确实有效,但是我无法更新 View 。
View 需要在以下情况下更新:
- 我们更改渲染区域( map 也可以是例如 200x200,但我们始终只渲染它的 10x10 区域。因此我们可以在每个方向“行走”并渲染 map 的不同区域)
- 一个人搬家了(简单更新旧字段和新字段)
- 一个人死了(简单地更新旧字段)
这是我的 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 中的几张图片的帖子,但没有关于如何更新它们的帖子......我试过默认重绘();这是行不通的。有人有什么想法吗?谢谢!
最佳答案
看起来您需要改进 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);
}
但再次作为一个“侧面”建议,一个不会解决您原来的问题但可能有助于解决 future 问题的建议,我建议您将程序结构更改为更多的 MVC(模型- View -控制) 类型结构,并拥有您的 View ——上面的 GUI,监听模型(程序的逻辑部分)的变化,并在发生变化时更新自身。
关于java - Swing MapPanel 更新图形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31273602/