如何创建仅显示3项的水平JList(带滚动条)
问题描述
我尝试在JScrollPane中创建一个包含7个项的水平JList,仅让其中3项可见,其余项可通过滚动条访问,预期效果如下:
我编写了如下代码:
JFrame frame = new JFrame("JList Example"); String[] items = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 9", "Item 10"}; JList<String> list = new JList<>(items); list.setLayoutOrientation(JList.HORIZONTAL_WRAP); list.setVisibleRowCount(1); JScrollPane scrollPane = new JScrollPane(list); scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); frame.add(scrollPane);
但实际效果如下:
我找不到除设置JScrollPane的setPreferredSize之外的方法来限制可见项数量,而该方法并不合适且对我无效,请问还有其他实现方式吗?
P.S. 我的英文不好,若有表述不清之处请见谅。
解决方案
要实现仅显示指定数量的水平JList项,核心是让JList根据项的实际尺寸计算自身的首选视口大小,而非硬编码尺寸。以下是两种可行方案:
方案一:基于单元格渲染器计算尺寸
通过获取默认单元格渲染器的尺寸,计算出3个项的总宽度,再设置JList的首选尺寸:
JFrame frame = new JFrame("JList Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); String[] items = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 9", "Item 10"}; JList<String> list = new JList<>(items); list.setLayoutOrientation(JList.HORIZONTAL_WRAP); list.setVisibleRowCount(1); // 获取默认渲染器,计算单个项的首选宽度 ListCellRenderer<? super String> renderer = list.getCellRenderer(); Component comp = renderer.getListCellRendererComponent(list, items[0], 0, false, false); int singleItemWidth = comp.getPreferredSize().width; // 计算3个项的总宽度,包含列表内边距 int preferredWidth = singleItemWidth * 3 + list.getInsets().left + list.getInsets().right; list.setPreferredSize(new Dimension(preferredWidth, list.getPreferredSize().height)); JScrollPane scrollPane = new JScrollPane(list); scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); frame.add(scrollPane); frame.pack(); frame.setVisible(true);
方案二:重写JList的视口尺寸方法
这是更优雅的方式,符合Swing的布局机制,避免直接调用setPreferredSize:
JFrame frame = new JFrame("JList Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); String[] items = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 9", "Item 10"}; JList<String> list = new JList<>(items) { @Override public Dimension getPreferredScrollableViewportSize() { // 获取第一个项的渲染组件,计算单一项宽度 ListCellRenderer<? super String> renderer = getCellRenderer(); Component comp = renderer.getListCellRendererComponent(this, getModel().getElementAt(0), 0, false, false); int itemWidth = comp.getPreferredSize().width; // 计算3个项的总视口宽度,包含内边距 int viewportWidth = itemWidth * 3 + getInsets().left + getInsets().right; // 高度沿用默认的单行高度 return new Dimension(viewportWidth, super.getPreferredScrollableViewportSize().height); } }; list.setLayoutOrientation(JList.HORIZONTAL_WRAP); list.setVisibleRowCount(1); JScrollPane scrollPane = new JScrollPane(list); scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); frame.add(scrollPane); frame.pack(); frame.setVisible(true);
方案优势
- 基于项的实际内容尺寸计算,不会因文本长度变化导致布局错位
- 遵循Swing的布局管理器规则,适配不同外观风格(LAF)
- 无需硬编码数值,灵活性更强
内容的提问来源于stack exchange,提问作者Obaraten64
相关产品推荐
相关产品推荐

