如何编写JPanel代码使绘制的图形始终完整可见?
解决Swing中FlowLayout下SchedulePanel网格只显示右上角的问题
问题场景
开发事件调度系统时,自定义的SchedulePanel绘制网格,但添加到使用FlowLayout的主面板后,仅能看到网格右上角,无法完整显示。
原SchedulePanel代码:
public class SchedulePanel extends JPanel { private static final long serialVersionUID = 1L; static final int originX = 0; static final int originY = 0; static final int cellSide = 50; static final int cols = 5; static final int rows = 5; public SchedulePanel() { setMinimumSize(new Dimension(cols * cellSide, rows * cellSide)); setBackground(Color.LIGHT_GRAY); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); // 绘制分隔行的水平线 for (int i = 0; i < rows; i++) { g.drawLine(originX, originY + (i * cellSide), originX + (cols * cellSide), originY + (i * cellSide)); } // 绘制分隔列的垂直线 for (int i = 0; i < cols; i++) { g.drawLine(originX + (i * cellSide), originY, originX + (i * cellSide), originY + (rows * cellSide)); } } }
主面板代码:
public class EventSchedulerGUI extends JPanel { RoomPanel roomPanel; SchedulePanel schedulePanel; JList<Room> roomList; public EventSchedulerGUI() { FlowLayout layout = new FlowLayout(); setLayout(layout); roomPanel = new RoomPanel(); schedulePanel = new SchedulePanel(); schedulePanel.setMinimumSize(new Dimension(400, 400)); add(roomPanel); add(schedulePanel); }
问题原因
- FlowLayout的尺寸优先级:
FlowLayout会优先使用组件的preferredSize分配空间,仅设置minimumSize不会被该布局管理器优先考虑,导致SchedulePanel被压缩到极小,仅显示局部内容。 - 绘制循环逻辑缺陷:原代码中绘制水平线和垂直线的循环条件为
i < rows/i < cols,这会漏掉最后一条边框线(比如5行网格需要6条水平线才能分隔出5个完整单元格)。
解决方案
1. 重写SchedulePanel的getPreferredSize方法
让组件主动向布局管理器提供正确的首选尺寸,替代仅设置minimumSize的方式。
2. 修正绘制循环的边界条件
确保完整绘制所有网格边框线。
3. 移除主面板中多余的minimumSize设置
让组件自身的尺寸逻辑生效。
修改后的SchedulePanel代码:
public class SchedulePanel extends JPanel { private static final long serialVersionUID = 1L; static final int originX = 0; static final int originY = 0; static final int cellSide = 50; static final int cols = 5; static final int rows = 5; public SchedulePanel() { setBackground(Color.LIGHT_GRAY); } // 重写getPreferredSize,提供正确的首选尺寸 @Override public Dimension getPreferredSize() { return new Dimension(cols * cellSide, rows * cellSide); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); // 绘制分隔行的水平线,修正循环条件为i <= rows for (int i = 0; i <= rows; i++) { g.drawLine(originX, originY + (i * cellSide), originX + (cols * cellSide), originY + (i * cellSide)); } // 绘制分隔列的垂直线,修正循环条件为i <= cols for (int i = 0; i <= cols; i++) { g.drawLine(originX + (i * cellSide), originY, originX + (i * cellSide), originY + (rows * cellSide)); } } }
修改后的主面板代码:
public class EventSchedulerGUI extends JPanel { RoomPanel roomPanel; SchedulePanel schedulePanel; JList<Room> roomList; public EventSchedulerGUI() { setLayout(new FlowLayout()); roomPanel = new RoomPanel(); schedulePanel = new SchedulePanel(); add(roomPanel); add(schedulePanel); } }
可选优化:添加滚动支持
如果窗口尺寸可能小于网格尺寸,可以将SchedulePanel放入JScrollPane中,实现滚动查看:
// 在主面板中替换add(schedulePanel)为: add(new JScrollPane(schedulePanel));
内容的提问来源于stack exchange,提问作者Ronald Wingate
相关产品推荐
相关产品推荐

