我正在尝试在 JScrollPane 中创建一个包含七个项目的水平 JList,其中只有三个项目需要可见,其他项目可通过滚动条访问。这是我正在尝试做的一个例子:
这就是我尝试做的:
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 之外,我找不到其他方法来限制可见项的数量。这不是 here 中描述的一个很好的方法,而且它对我来说真的不起作用。还有另一种方法可以做我想做的事吗?
附言我英语不好,如果你误解了我的意思,我很抱歉。尽我所能
我只想指出显而易见的是“这些项目中只有三个需要可见”是有问题的,因为前三个值可能比以下项目更大或更小,或者使用不同的数据你会得到不同的,有时,奇怪的结果。
我们是使用“原型”值,模型的第一个元素,还是尝试从模型中获取第一个
n
项目来计算“理想的可视宽度”?当模型包含少于 n
元素或根本没有元素时会发生什么?
重点是,有“很多”需要考虑。如果您只想减小组件的水平尺寸,您可以覆盖
getPreferredScrollableViewportSize
并根据需要返回“理想”宽度,但请记住,这不太可能是 n
列。
下面的例子基本上演示了这个概念(尽我所能,而不试图找出每一个可能的边缘情况)。
它扩展了
JList
并覆盖了getPreferredScrollableViewportSize
方法。
visibleColumnCount
为0或更小,它将正常运行fixedCellWidth
,则乘以visibleColumnCount
prototypeCellValue
,则渲染值宽度乘以visibleColumnCount
256
(随便选一个数字)visibleColumnCount
,它会将每个元素的首选宽度相加,取平均值并用平均值填充剩余的列......如果这听起来令人困惑,你应该尝试想出它😳n
列并计算它们的首选宽度例如...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListModel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
String[] items = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 9", "Item 10"};
FixedColumnWidthList<String> list = new FixedColumnWidthList<>(items);
list.setVisibleColumnCount(3);
JScrollPane scrollPane = new JScrollPane(list);
add(scrollPane);
}
}
public class FixedColumnWidthList<T> extends JList<T> {
private int visibleColumnCount = -1;
public FixedColumnWidthList() {
configureDefaults();
}
public FixedColumnWidthList(ListModel<T> dataModel) {
super(dataModel);
configureDefaults();
}
public FixedColumnWidthList(T[] listData) {
super(listData);
configureDefaults();
}
public FixedColumnWidthList(Vector<T> listData) {
super(listData);
configureDefaults();
}
protected void configureDefaults() {
setLayoutOrientation(JList.HORIZONTAL_WRAP);
setVisibleRowCount(1);
}
public int getVisibleColumnCount() {
return visibleColumnCount;
}
public void setVisibleColumnCount(int visibleColumnCount) {
if (this.visibleColumnCount == visibleColumnCount) {
return;
}
this.visibleColumnCount = visibleColumnCount;
revalidate();
repaint();
}
@Override
public Dimension getPreferredScrollableViewportSize() {
int visibleColumnCount = getVisibleColumnCount();
Dimension original = super.getPreferredScrollableViewportSize();
if (visibleColumnCount <= 0) {
return original;
}
ListModel<T> model = getModel();
int desirableWidth = getFixedCellWidth();
if (desirableWidth <= 0) {
T testValue = getPrototypeCellValue();
if (testValue != null) {
desirableWidth = getCellRenderer().getListCellRendererComponent(this, testValue, 0, false, false).getPreferredSize().width;
desirableWidth *= visibleColumnCount;
} else if (getModel().getSize() == 0) {
desirableWidth = 256; // Just pick a number :/
} else {
desirableWidth = 0;
// You could, instead, just take the first value and mutiply
// it's rendered width by the number of visible columns,
// but this could mean you're not actually getting the
// first three columns ... but this whole thing is a bag
// of ambiguity
for (int column = 0; column < visibleColumnCount && column < model.getSize(); column++) {
int width = getCellRenderer().getListCellRendererComponent(this, model.getElementAt(column), column, false, false).getPreferredSize().width;
System.out.println(column + " = " + width);
desirableWidth += width;
}
// I can't find the "horizontal insets", so I'm guessing...
desirableWidth += (8 * (visibleColumnCount - 1));
// If we have less data then visible columns, just
// average the available information and multiply it by
// the remaining number of columns as a guess
if (visibleColumnCount > model.getSize()) {
int averageWidth = desirableWidth / model.getSize();
desirableWidth += (visibleColumnCount - model.getSize());
}
}
} else {
desirableWidth *= visibleColumnCount;
}
return new Dimension(desirableWidth, original.height);
}
}
}
我不应该说 JavaDocs 谈论“水平插入” 但我找不到任何可以访问/可用的地方,所以我做了一个猜测。我怀疑这可能是一个 UI 委托选项,所以如果你真的想使用这个例子,我鼓励你尝试一下。
现在,说了这么多,只需重写
getPreferredScrollableViewportSize
方法并返回一个 width
,否则它会满足您想要的结果,搞乱“可见列”是模棱两可和有问题的