Skip to content
Advertisement

How to make all images in Grid Overlay flush?

I am trying to implement a GUI for a maze-based game I created that meets the following specific conditions:

  1. The GUI itself has a set size and is not resizable (line 41) .

  2. The master panel (line 57) that contains all the maze images is scrollable. All maze image components are flush with each other.

    • If maze is small enough, then entire maze will be visible in master panel.
    • If maze is very large, then user would need to scroll.
  3. The master panel needs to be accessed by a mouse listener (line 130) that returns the component that is being clicked.

The following code seems to meet criteria 1 and 3, but fails criteria 2:

public class MazeGui extends JFrame implements DungeonView {
  
  private final Board board;
  
  public MazeGui(ReadOnlyModel m) {

    
    //this.setSize(m.getNumRows()*100, m.getNumCols()*100);
    this.setSize(600, 600);
    this.setLocation(200, 200);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setResizable(false);

    this.board = new Board(m);
    JScrollPane scroller = new JScrollPane(board);
    this.add(scroller, BorderLayout.CENTER);

    setTitle("Dungeon Escape");

  }
  
  private class Board extends JPanel {

    private ReadOnlyModel m;
    

    public Board(ReadOnlyModel m) {

      this.m = m;
      GridLayout layout = new GridLayout(m.getNumRows(),m.getNumCols(), 0, 0);
//      layout.setHgap(-100);
//      layout.setVgap(-100);
      this.setLayout(layout);
      
      this.setSize(m.getNumRows()*64,m.getNumCols()*64);
      

      for (int i = 0; i < m.getNumRows() * m.getNumCols(); i++) {
      
      try {
        // load resource from the classpath instead of a specific file location
        InputStream imageStream = getClass().getResourceAsStream(String.format("/images/%s.png", m.getRoomDirections(i + 1)));
        // convert the input stream into an image
        Image image = ImageIO.read(imageStream);
        // add the image to a label
        JLabel label = new JLabel(new ImageIcon(image));
        label.setPreferredSize(new Dimension(64, 64));
        
        
        JPanel panel = new JPanel();
        panel.setSize(64, 64);
        String name = String.format("%d", i);
        panel.setName(name);
        panel.add(label);

        // add the label to the JFrame
        //this.layout.addLayoutComponent(TOOL_TIP_TEXT_KEY, label);

        
        this.add(panel);
        
      } catch (IOException e) {
        JOptionPane.showMessageDialog(this, e.getMessage());
        e.printStackTrace();
      }
    }


    }
  }
  
  

  @Override
  public void addClickListener(DungeonController listener) {

    Board board = this.board;
    
    MouseListener mouseListener = new MouseAdapter() {

      @Override
      public void mouseClicked(MouseEvent e) {

         System.out.println(String.format("(%d,%d)", e.getX(), e.getY()));
         JPanel panel = (JPanel) board.getComponentAt(e.getPoint());
         System.out.println(panel.getName());
         

      }

    };

    board.addMouseListener(mouseListener);

  }
    
  

  @Override
  public void refresh() {
    
    this.repaint();
  }

  @Override
  public void makeVisible() {

    this.setVisible(true);
    
  }

}

Here is an image of what it produces:

enter image description here

Advertisement

Answer

First, I’d make use of a different layout manager, one which would try and expand to fit the size of the underlying container.

Then, I would let the components do their jobs. I don’t know why you’re adding the label to another panel, the panel doesn’t seem to be adding additional functionality/features and is just adding to the complexity.

enter image description here

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                List<Maze.Direction> directions = new ArrayList<>(32);
                directions.add(Maze.Direction.EAST_SOUTH);
                directions.add(Maze.Direction.EAST_SOUTH_WEST);
                directions.add(Maze.Direction.EAST_SOUTH_WEST);
                directions.add(Maze.Direction.EAST_SOUTH_WEST);
                directions.add(Maze.Direction.EAST_SOUTH_WEST);
                directions.add(Maze.Direction.SOUTH_WEST);
                directions.add(Maze.Direction.NORTH_EAST_SOUTH);
                directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
                directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
                directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
                directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
                directions.add(Maze.Direction.NORTH_SOUTH_WEST);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH_SOUTH);
                directions.add(Maze.Direction.NORTH);
                directions.add(Maze.Direction.NORTH);
                directions.add(Maze.Direction.NORTH);
                directions.add(Maze.Direction.NORTH);
                directions.add(Maze.Direction.NORTH);
                directions.add(Maze.Direction.NORTH);

                System.out.println(directions.size());

                Maze maze = new DefaultMaze(5, 6, directions);

                MazeGui frame = new MazeGui(maze);
                frame.addClickListener(null);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface Maze {

        enum Direction {
            EAST_SOUTH("EastSouth.png"), EAST_SOUTH_WEST("EastSouthWest.png"), SOUTH_WEST("SouthWest.png"),
            NORTH_EAST_SOUTH("NorthEastSouth.png"), NORTH_EAST_SOUTH_WEST("NorthEastSouthWest.png"),
            NORTH_SOUTH_WEST("NorthSouthWest.png"), NORTH_SOUTH("NorthSouth.png"), NORTH("North.png");

            private BufferedImage image;

            private Direction(String name) {
                try {
                    image = ImageIO.read(getClass().getResource("/images/" + name));
                } catch (IOException ex) {
                    Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

            public BufferedImage getImage() {
                return image;
            }

        }

        public int getRows();

        public int getColumns();

        public Direction getRoomDirections(int index);
    }

    public class DefaultMaze implements Maze {

        int rows;
        int columns;

        private List<Direction> directions;

        public DefaultMaze(int rows, int columns, List<Direction> directions) {
            this.rows = rows;
            this.columns = columns;
            this.directions = directions;
        }

        public int getRows() {
            return rows;
        }

        public int getColumns() {
            return columns;
        }

        @Override
        public Direction getRoomDirections(int index) {
            return directions.get(index);
        }
    }

    public class MazeGui extends JFrame {

        // Missing code
        public interface DungeonController {
        }

        private final Board board;

        public MazeGui(Maze m) {
            this.setSize(600, 600);
            this.setResizable(false);

            this.board = new Board(m);
            JScrollPane scroller = new JScrollPane(board);
            this.add(scroller, BorderLayout.CENTER);

            setTitle("Dungeon Escape");
        }

        public Board getBoard() {
            return board;
        }

        public void addClickListener(DungeonController listener) {
            Board board = getBoard();
            board.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    Component cell = board.getComponentAt(e.getPoint());
                    System.out.println(cell.getName());
                    board.highlight(cell.getBounds());
                }
            });
        }

        private class Board extends JPanel {

            private Rectangle selectedCell;

            private Maze maze;

            public Board(Maze maze) {
                this.maze = maze;
                setLayout(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 0;

                for (int index = 0; index < maze.getRows() * maze.getColumns(); index++) {
                    Maze.Direction direction = maze.getRoomDirections(index);
                    JLabel label = new JLabel(new ImageIcon(direction.getImage()));
                    label.setName(direction.name());
                    add(label, gbc);
                    gbc.gridx++;
                    if (gbc.gridx >= maze.getColumns()) {
                        gbc.gridx = 0;
                        gbc.gridy++;
                    }
                }

//                addMouseListener(new MouseAdapter() {
//                    @Override
//                    public void mouseClicked(MouseEvent e) {
//                        Component component = getComponentAt(e.getPoint());
//                        selectedCell = null;
//                        if (component != null) {
//                            selectedCell = component.getBounds();
//                        }
//                        repaint();
//                    }
//                });
            }

            public void highlight(Rectangle bounds) {
                selectedCell = bounds;
                repaint();
            }

            @Override
            public void paint(Graphics g) {
                super.paint(g);
                if (selectedCell != null) {
                    Graphics2D g2d = (Graphics2D) g.create();
                    g2d.setColor(new Color(0, 0, 255, 128));
                    g2d.fill(selectedCell);
                    g2d.dispose();
                }
            }
        }
    }
}
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement