Frame -> MainContentPane -> MapPanel -> Map -> Tile[]
JFrame -> JPanel(new GridBagLayout) -> JPanel -> JPanel(new GridLayout(31,30) -> JComponent
I'm trying to paint 32x32 pix tiles on a JPanel, but no matter where I call repaint(); it will only paint the tiles if I call validate(); on the JFrame.
If I bypass Panels and paint directly (use of the draw() methods) onto the MapPanel the images will only paint if I resize or move the JFrame so that the Frame has to be repainted by the repaintmanager. However calling repaint(), validate() or both on my ContentPanel will not paint the images.
If I understand how Java.swing paints thing right, if I call a repaint on the highest level Component it should repaint all child Components that the repaintmanager thinks should be repainted. Since I am adding components after the frame has been set to visible I need to call validate() on the highest level Component to tell the repaintmanager that there are new things. Am I right with this understanding?
Things that will not work:
telling me to add all the components before setting the frame to visible. The Map and Tile[] are going to be changing quite regularly, and it would be very impractical to reset the Frame every time I add/remove something.
public class NetScore {
public static void main(String[] args) {
MapPanel mapPanel = new MapPanel();
InfoPanel infoPanel = new InfoPanel();
ImageLoader imageLoader = new ImageLoader();
Player player = new Player("Tester", imageLoader);
JPanel contentPane = new MainContentPane((JPanel)mapPanel, (JPanel)infoPanel);
System.out.println(mapPanel.getHeight());
System.out.println(mapPanel.getWidth());
MapBuilder mapBuilder = new MapBuilder(player, imageLoader);
Map map = new Map(mapBuilder, mapPanel, player);
map.drawMap();
System.out.println();
}
}
public class MapPanel extends JPanel implements ActionListener{
Map map;
Timer clock;
public MapPanel(){
clock = new Timer(500, this);
clock.start();
}
public void addMap(Map map){
this.map = map;
this.add(map);
this.validate();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
System.out.println(map == null);
System.out.println("paint mapPanel");
Graphics2D g2 = (Graphics2D) g;
if(map == null){
//map.draw(g2);
}
}
@Override
public void actionPerformed(ActionEvent e) {
//repaint();
}
}
public class MainContentPane extends JPanel implements ActionListener{
public JFrame frame;
Timer clock;
public MainContentPane(JPanel mapPanel ,JPanel infoPanel){
clock = new Timer(500, this);
clock.start();
frame = new Frame();
JPanel contentPane = new JPanel();
frame.setContentPane(contentPane);
contentPane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.weightx = 2;
c.gridx = 0;
c.gridy = 0;
c.fill = GridBagConstraints.BOTH;
contentPane.add(mapPanel, c);
c.weightx = 1;
c.weighty = 1;
c.gridx = 1;
c.gridy = 0;
c.fill = GridBagConstraints.BOTH;
contentPane.add(infoPanel, c);
frame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
class Frame extends JFrame{
public Frame(){
this.setTitle("netScore");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setBounds(100, 10, 1500, 1000);
this.setResizable(false);
}
}
}
public class Map extends JPanel{
private Tile[][] tiles;
private MapBuilder mapBuilder;
private Player player;
public Map(MapBuilder mapBuilder, MapPanel mapPanel, Player player){
this.player = player;
this.mapBuilder = mapBuilder;
this.setLayout(new GridLayout(31,30));
mapPanel.addMap(this);
}
public void loadMap(){
tiles = mapBuilder.buildMap();
}
public void drawMap(){
loadMap();
this.removeAll();
for(int i = 0; i < tiles.length; i++){
for(int p = 0; p < tiles[i].length; p++){
this.add(tiles[i][p]);
}
}
validate();
}
public void draw(Graphics2D g2){
if(tiles != null){
for(int i = 0; i < tiles.length; i++){
for(int p = 0; p <tiles[i].length; p++){
tiles[i][p].draw(g2, i*32, p*32);
}
}
}
}
// private class GlassPanel extends JComponent{
//
//
// @Override
// protected void paintComponent(Graphics g) {
// super.paintComponent(g);
// Graphics2D g2 = (Graphics2D) g;
// g2.drawImage(player.getImage(), player.getX(), player.getY(), null);
//
// }
//
// }
}
public class Tile extends JComponent{
private int id;
private boolean collision;
private BufferedImage image;
public Tile(char diCo, int id, ImageLoader imageLoader){
this.id = id;
collision = (Character.isUpperCase(diCo));
image = imageLoader.getTileImage(id, diCo);
setPreferredSize(new Dimension(32, 32));
}
// public Dimension getPreferredSize(){
// return new Dimension(32,32);
// }
public boolean isCollision() {
return collision;
}
public void draw(Graphics2D g2, int x, int y){
System.out.println("paint tile, id "+ id);
g2.drawImage(image, null, x, y);
}
public void paintComponent(Graphics g){
System.out.println("paint tile, id "+ id);
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(image, null, 0, 0);
}
}
Edit: Added minimal code. This will work if I replace validate(); with revalidate(); But I don't want to use revalidate(); if nothing on the Panel needs to be invalided. Am I wright with that thinking?
public class test {
public static void main(String[] args) throws Exception {
MapPanel mapPanel = new MapPanel();
ContentPanel contentPanel = new ContentPanel((JPanel)mapPanel);
Map map = new Map();
mapPanel.add(map);
map.loadMap();
}
}
class MapPanel extends JPanel{
public MapPanel(){
//this.setBackground(Color.BLACK);
}
}
class Map extends JPanel{
BufferedImage image;
public Map(){
try {
image = ImageIO.read(new File("graphics//brick_brown0.png"));
} catch (IOException e) {
System.err.println("can't find file.");
}
setLayout(new GridLayout(31,30));
setPreferredSize(new Dimension(962,992));
}
public void loadMap(){
for(int i = 0; i < 30; i++){
for(int p = 0; p < 31; p++){
add(new Tile(image));
}
}
validate();
}
}
class Tile extends JComponent{
BufferedImage image;
public Tile(BufferedImage image){
this.image = image;
setPreferredSize(new Dimension(32,32));
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(image, null, null);
}
}
class ContentPanel extends JPanel implements ActionListener{
Timer clock = new Timer(100, this);
public ContentPanel(JPanel mapPanel){
clock.start();
setLayout(new BorderLayout());
JFrame frame = new Frame();
frame.setContentPane(this);
add(mapPanel);
frame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
private class Frame extends JFrame{
public Frame(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(100, 100, 1000, 1000);
}
}
}
