我确定我会这样做但是......
我有一个扩展JComponent的自定义Tile对象的2D数组。它们包含模型信息,以及paintComponent()方法的覆盖。 tile实际上只包含一个Image,一个表示其类型的String,以及两个布尔值,指示它们是否包含一个播放器以及它们是否能够被遍历。这个Tile类是我所有Tile对象的超类,目前包括NormalTile,ActionTile和EmptyTile。
2D数组本身包含在扩展JPanel的TilePanel类中,并且此类有几种方法可用于修改此tile数组。
在这个链的顶部是MapManager,它没有显式扩展任何东西,而是包含TilePanel和JScrollPane的实例,并且TilePanel被添加到JScrollPane。
首次创建TilePanel时,它会使用一系列NormalTiles初始化2D数组,这些NormalTiles可以使用他们使用的测试图像轻松显示自己。这一切都很完美。
然而,在创建TilePanel之后,我立即调用其addTileBlock(int width,int height,int x,int y,String type)方法来更改2D数组中特定点的切片。这是更新显示的问题出现的地方。
指定位置的Tiles确实会根据我打印出来的数据而改变,当玩家踩到它们时它们的行为根据改变的类型指示的方式确实有效,但是显示的变化从未反映过。新的Tiles(在这种情况下,我使用了EmptyTiles)只是简单地显示了之前使用的NormalTiles的相同图像,尽管它们的底层对象已经改变。
现在,“更新”磁贴实际上使旧的Tile引用指向一个新的Tile实例,因为我的Tile对象本身是不可变的。每当更新完成时,TilePanel类只需将抽象类TileFactory类化为使用其generateTile(String type)方法来创建正确的Tile实例。它只是使用一个开关/盒块来返回瓷砖。
有人建议我尝试在tile对象上使用revalidate()
方法来解决问题,你可以在Tile类的构造函数中看到我在哪里实现它。我之前也曾尝试在paintComponent方法中使用它,但这也没有做任何事情。
这是完整的addTileBlock方法和Tile类:
addTileBlock:
public void addTileBlock(int width, int height, int x, int y, String type)
{
for(int i = 0; i < width; i++)
for(int j = 0; j < height; j++)
{
tiles[i][j] = null;
tiles[i][j] = TileFactory.generateTile(type);
tiles[i][j].repaint();
}
}
瓷砖类:
package games.tile.tiles;
import games.tile.Player;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JComponent;
abstract public class Tile extends JComponent implements TileConstants
{
private String type;
private Image tileImage;
private boolean containsPlayer = false;
private boolean walkable;
public Tile(String type, int size, boolean walkable)
{
this.setSize(size, size);
this.type = type;
this.walkable = walkable;
this.setPreferredSize(new Dimension(this.getHeight(), this.getWidth()));
tileImage = null;
revalidate();
}
public Tile(String type, int size, boolean walkable, Image image)
{
this.setSize(size, size);
this.type = type;
this.walkable = walkable;
tileImage = image;
this.setPreferredSize(new Dimension(this.getHeight(), this.getWidth()));
this.revalidate();
}
public boolean getWalkable() { return walkable; }
public void setWalkable(boolean val) { walkable = val; }
public boolean containsPlayer() { return containsPlayer; }
public void setContainsPlayer(boolean val) { containsPlayer = val;}
public Image getImage() { return tileImage; }
public void setImage(Image image) { tileImage = image; }
public String getType() { return type; }
abstract public void applyEffect(Player player);
@Override
public void paintComponent(Graphics g)
{
if(type.equals(EMPTY) || tileImage == null)
{
g.setColor(Color.black);
g.fillRect(0, 0, 32, 32);
}
else
{
g.drawImage(tileImage, 0, 0, null);
}
if(containsPlayer)
{
g.drawImage(Player.PLAYER_IMAGE, 0, 0, null);
}
}
}
任何人都可以告诉我我可能做错了什么吗?
答案 0 :(得分:2)
当您从面板添加/删除组件时,有人建议我尝试在tile对象上使用revalidate()方法来解决问题,
revalidate()完成。所以基本代码是:
panel.add(...);
panel.revalidate();
panel.repaint();
这假设您使用的是正确的布局管理器。在你的情况下,我猜一个GridLayout。
现在看来,“更新”瓷砖实际上会使旧的Tile参考指向新的Tile实例,
您不能只是将变量的引用更改为指向新的Swing组件。您需要将组件实际添加到面板中。所以在你的情况下,因为你正在使用网格,我猜你需要删除网格上当前点的组件,然后在那时添加另一个组件。
这是很多工作。既然你说你的组件基本上只包含一个图像,一个更简单的方法是创建一个changeImage(...)
图像,然后从该方法中调用repaint(),组件将重新绘制自己,你不需要担心创建新组件并将其添加到面板中。