Java GUI记忆游戏:JFrame与组件自适应布局问题求助
问题:Java GUI记忆游戏布局适配异常
- 已完成Java GUI记忆游戏核心功能,但布局适配存在问题:键盘、随难度变化的网格(简单3×4/中等4×7/困难7×8)、左侧TurnBox组件无法适配JFrame,界面布局混乱
- 尝试过的无效方案:设置大尺寸JFrame后调用
pack();移除width参数改用固定值能对齐网格,但会导致TurnBox消失
提供的代码片段
TurnBox构造代码
public TurnBox(MemoryFrame view, MemoryModel model, int width) //extends JPanel { this.model = model; this.letterWidth = 64; this.insets = new Insets(0, 6, 6, 6); this.topMargin = 0; int wordWidth = (letterWidth + insets.right) * model.getColumns(); //# of columns in the game this.leftMargin = (width - wordWidth)/2; int height = (letterWidth + insets.bottom) * model.getRows() //# of rows in the game + 2 * topMargin; this.setPreferredSize(new Dimension(width, height)); this.turn = buildRectangle(); } private Rectangle buildRectangle() { int x = 50; int y = topMargin; Rectangle turn = new Rectangle(x, y, letterWidth, letterWidth); return turn; }
MemoryBoard构造代码
public MemoryBoard(MemoryFrame view, MemoryModel model, int width) { this.model = model; this.action = new KeyBoardButtonAction(view, model); this.topMargin = 0; this.letterWidth = 64; this.insets = new Insets(0, 6, 6, 6); //Distance between squares int wordWidth = (letterWidth + insets.right) * model.getColumns(); this.leftMargin = (width - wordWidth) / 2; int height = (letterWidth + insets.bottom) * model.getRows() + 2 * topMargin; this.setPreferredSize(new Dimension(width, height)); this.grid = buildGrid(); } private Rectangle[][] buildGrid() { //Part 3 here, change size of grid Rectangle[][] grid = new Rectangle[model.getRows()][model.getColumns()]; //Rectangle[][] grid = new Rectangle[7][6]; int x = leftMargin; int y = topMargin; for (int row = 0; row < model.getRows(); row++) { for (int column = 0; column < model.getColumns(); column++) { grid[row][column] = new Rectangle(x, y, letterWidth, letterWidth); x += letterWidth + insets.right; } x = leftMargin; y += letterWidth + insets.bottom; } return grid; }
MemoryFrame构造代码
public MemoryFrame(MemoryModel model, StartingFrame s) { this.model = model; this.start = s; this.keyboardPanel = new KeyboardPanel(this, model); int width = keyboardPanel.getPanel().getPreferredSize().width; this.board = new MemoryBoard(this, model, width); this.turn = new TurnBox(this, model, width); this.frame = initializeFrame(); } private JFrame initializeFrame() { JFrame frame = new JFrame("GUI Memory Game"); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); //frame.setJMenuBar(createMenuBar()); frame.setResizable(false); //frame.setSize(1000,1000); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent event) { shutdown(); } }); frame.add(createTitlePanel(), BorderLayout.NORTH); frame.add(turn, BorderLayout.WEST); frame.add(board, BorderLayout.CENTER); //Change according to difficulty frame.add(keyboardPanel.getPanel(), BorderLayout.SOUTH); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); System.out.println("Frame size: " + frame.getSize()); return frame; }
解决方案
1. 修复TurnBox的尺寸逻辑
TurnBox当前错误地将键盘面板宽度设为自身PreferredWidth,导致和MemoryBoard宽度冲突,挤占WEST区域空间。修改为固定宽度,高度与网格保持一致:
// 修改TurnBox构造方法 public TurnBox(MemoryFrame view, MemoryModel model) // 移除width参数 { this.model = model; this.letterWidth = 64; this.insets = new Insets(0, 6, 6, 6); this.topMargin = 0; // 设置TurnBox固定宽度(单个格子宽度+边距) int turnBoxWidth = letterWidth + 20; // 高度与MemoryBoard对齐 int height = (letterWidth + insets.bottom) * model.getRows() + 2 * topMargin; this.setPreferredSize(new Dimension(turnBoxWidth, height)); this.turn = buildRectangle(); }
2. 调整MemoryBoard的宽度计算
MemoryBoard无需依赖键盘宽度,直接根据网格尺寸计算自身宽度,同时取消内部左偏移,让BorderLayout自动居中:
// 修改MemoryBoard构造方法 public MemoryBoard(MemoryFrame view, MemoryModel model) // 移除width参数 { this.model = model; this.action = new KeyBoardButtonAction(view, model); this.topMargin = 0; this.letterWidth = 64; this.insets = new Insets(0, 6, 6, 6); int wordWidth = (letterWidth + insets.right) * model.getColumns(); this.leftMargin = 0; // 取消左偏移,由布局管理器处理居中 int height = (letterWidth + insets.bottom) * model.getRows() + 2 * topMargin; this.setPreferredSize(new Dimension(wordWidth, height)); this.grid = buildGrid(); } // 同步修改buildGrid的起始坐标 private Rectangle[][] buildGrid() { Rectangle[][] grid = new Rectangle[model.getRows()][model.getColumns()]; int x = 0; // 从0开始绘制 int y = topMargin; for (int row = 0; row < model.getRows(); row++) { for (int column = 0; column < model.getColumns(); column++) { grid[row][column] = new Rectangle(x, y, letterWidth, letterWidth); x += letterWidth + insets.right; } x = 0; y += letterWidth + insets.bottom; } return grid; }
3. 更新MemoryFrame的组件初始化
移除基于键盘宽度的参数传递,直接初始化组件:
// 修改MemoryFrame构造方法 public MemoryFrame(MemoryModel model, StartingFrame s) { this.model = model; this.start = s; this.keyboardPanel = new KeyboardPanel(this, model); // 不再传递width参数 this.board = new MemoryBoard(this, model); this.turn = new TurnBox(this, model); this.frame = initializeFrame(); }
4. 优化窗口布局兼容性
- 确保
createTitlePanel()的PreferredHeight合理,避免挤压下方组件 - 若保留
frame.setResizable(false),需确保所有组件的PreferredSize计算准确,让pack()能正确推导窗口尺寸
内容的提问来源于stack exchange,提问作者Derek Kwon
相关产品推荐
相关产品推荐

