Java Swing:JScrollPane中列表行垂直均分空白问题求解
问题描述
我是Java新手,昨天刚开始学习,请多包涵。目前我在把一组继承自JPanel的StudentRow添加到作为JScrollPane视口的JPanel中,遇到了问题:添加少量列表项时,JPanel的剩余空间会被各列表行垂直均分,效果如下:
- 添加2个项的效果:

- 添加3个项的效果:

只有添加约10个项后,列表才会展开并支持滚动。我搜了好几个小时都没找到解决办法,求各位给点建议!
问题代码
StudentListView类
public class StudentListView extends JScrollPane { private JPanel myList; private EventManager events; private List<StudentModel> students; private StudentRow listRow; public StudentListView(List<StudentModel> students, EventManager events) { this.students = students; this.events = events; myList = new JPanel(); myList.setLayout(new BoxLayout(myList, BoxLayout.Y_AXIS)); for (int i = 0; i < this.students.size(); i++) { listRow = new StudentRow(students.get(i), events, i); listRow.setAlignmentY(Component.TOP_ALIGNMENT); myList.add(listRow); } setViewportView(myList); } public void updateView(List<StudentModel> students) { myList.removeAll(); this.students = students; for (int i = 0; i < this.students.size(); i++) { listRow = new StudentRow(students.get(i), events, i); myList.add(listRow); } myList.revalidate(); setViewportView(myList); } }
StudentRow类
public class StudentRow extends JPanel { public int index; private JLabel nameLabel; private JLabel ageLabel; private JButton editButton; private JButton deleteButton; public StudentRow(StudentModel student, EventManager events, int index) { this.index = index; setPreferredSize(new Dimension(400, 30)); nameLabel = new JLabel(); nameLabel.setText(student.getName()); ageLabel = new JLabel(); ageLabel.setText(Integer.toString(student.getAge())); editButton = new JButton("Edit"); deleteButton = new JButton("Delete"); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.fill = GridBagConstraints.WEST; add(nameLabel, gbc); gbc.gridx = 1; gbc.gridy = 0; gbc.fill = GridBagConstraints.WEST; add(ageLabel, gbc); gbc.gridx = 2; gbc.gridy = 0; gbc.fill = GridBagConstraints.EAST; add(editButton, gbc); gbc.gridx = 3; gbc.gridy = 0; gbc.fill = GridBagConstraints.EAST; add(deleteButton, gbc); // Create component action listeners deleteButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { events.notify("removeStudent", student); } }); } }
解决方案
修改后的StudentListView代码如下:
public class StudentListView extends JScrollPane { private JPanel myList; private EventManager events; private List<StudentModel> students; private StudentRow listRow; private JPanel BorderLayoutPanel; public StudentListView(List<StudentModel> students, EventManager events) { this.students = students; this.events = events; myList = new JPanel(); myList.setLayout(new GridLayout(0,1)); BorderLayoutPanel = new JPanel(new BorderLayout()); BorderLayoutPanel.add(myList, BorderLayout.PAGE_START); for (int i = 0; i < this.students.size(); i++) { listRow = new StudentRow(students.get(i), events, i); myList.add(listRow); } setViewportView(BorderLayoutPanel); } public void updateView(List<StudentModel> students) { myList.removeAll(); this.students = students; for (int i = 0; i < this.students.size(); i++) { listRow = new StudentRow(students.get(i), events, i); myList.add(listRow); } myList.revalidate(); setViewportView(BorderLayoutPanel); } }
为什么这样能解决问题
- 原来的
BoxLayout.Y_AXIS布局,当视口高度大于所有行的总高度时,会自动拉伸每个行组件去填充剩余空间,导致行被均分高度。 - 改用
GridLayout(0,1):第一个参数设为0表示行数随内容自动调整,第二个参数1表示单列布局,这样每个StudentRow会保持自己设置的30px高度,不会被拉伸。 - 再把这个列表容器放到BorderLayout的
PAGE_START位置,这个区域的组件只会占用自身所需的垂直空间,不会被强制填充整个视口。当内容总高度超过视口高度时,JScrollPane就会自动显示滚动条,不用等凑够10个项才触发滚动。
内容的提问来源于stack exchange,提问作者Nex
相关产品推荐
相关产品推荐

