I am trying to implement a GUI for a maze-based game I created that meets the following specific conditions:
The GUI itself has a set size and is not resizable (line 41) .
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.
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:
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.
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(); } } } } }