Java Swing实现JFrame同一JScrollPane内两个JPanel并排显示
问题根因
JScrollPane的滚动视图区(Viewport)仅支持承载单个组件,直接调用scrollPane.add(consolePanel)是把组件加到滚动面板的非视图层(滚动条、角落组件预留层),不会显示在滚动区域内。- 直接调用
this.add(consolePanel)时,JFrame默认使用的BorderLayout会把无约束的组件放到CENTER区域,和原有的scrollPane抢占布局位置,同一个布局位置添加多个组件就会出现渲染错乱。
实现方法
新增一个中间JPanel容器作为JScrollPane视图区的唯一组件,使用水平排列的布局将MapPanel和ConsolePanel按顺序添加到这个中间容器中,再把中间容器设置为滚动面板的视图内容即可实现两个面板并排、同区域滚动的效果。
修改后的MapFrame核心代码
public class MapFrame extends JFrame{ public MapFrame() { buildTheUI(); setUpEventHandling(); mapPanel = new MapPanel(); ConsolePanel consolePanel = new ConsolePanel(); // 给控制台面板设置初始尺寸 consolePanel.setPreferredSize(new Dimension(400, mapPanel.getPreferredSize().height)); // 如果需要固定控制台宽度不被布局压缩,放开下面两行注释 // consolePanel.setMinimumSize(consolePanel.getPreferredSize()); // consolePanel.setMaximumSize(consolePanel.getPreferredSize()); // 创建承载两个面板的中间容器 JPanel scrollContent = new JPanel(); // 设置水平排列布局 scrollContent.setLayout(new BoxLayout(scrollContent, BoxLayout.X_AXIS)); scrollContent.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); // 按顺序添加组件,中间留10px空隙 scrollContent.add(mapPanel); scrollContent.add(Box.createHorizontalStrut(10)); scrollContent.add(consolePanel); JScrollPane scrollPane = new JScrollPane(); // 将中间容器设置为滚动面板的视图内容 scrollPane.setViewportView(scrollContent); scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); this.setLayout(new BorderLayout()); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(1024, 1024); // 明确指定滚动面板放到BorderLayout的CENTER区域占满窗口 this.add(scrollPane, BorderLayout.CENTER); this.pack(); this.setVisible(true); } }
ConsolePanel优化修正
原有代码复用同一个GridBagConstraints对象会导致布局约束异常,调整为每个组件单独设置约束,同时让文本区自动占满面板剩余空间:
public class ConsolePanel extends JPanel { public ConsolePanel(){ this.setLayout(new GridBagLayout()); // 通过行列数定义文本区初始尺寸,比直接setPreferredSize更适配不同系统的字体渲染 TextArea console = new TextArea("random info here", 25, 40); console.setEditable(false); // 控制台标题约束 GridBagConstraints titleCons = new GridBagConstraints(); titleCons.gridx = 0; titleCons.gridy = 0; titleCons.anchor = GridBagConstraints.WEST; titleCons.insets = new Insets(0,0,5,0); this.add(new JLabel("Console"), titleCons); // 文本区约束 GridBagConstraints textCons = new GridBagConstraints(); textCons.gridx = 0; textCons.gridy = 1; textCons.weightx = 1.0; textCons.weighty = 1.0; textCons.fill = GridBagConstraints.BOTH; this.add(console, textCons); } }
注意事项
- 不要直接调用
JScrollPane.add()添加业务组件,该方法仅用于添加滚动面板自身的内部控件(滚动条、角标等),业务内容必须通过setViewportView()设置到视图区。 - 使用BorderLayout时,建议给所有添加的组件明确指定布局约束(比如
BorderLayout.CENTER/BorderLayout.EAST),避免默认位置导致的布局覆盖问题。
内容的提问来源于stack exchange,提问作者Mr.Gomer
相关产品推荐
相关产品推荐

