JList - 水平列表,可见数量的值

问题描述 投票:0回答:1

我正在尝试在 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 中描述的一个很好的方法,而且它对我来说真的不起作用。还有另一种方法可以做我想做的事吗?

附言我英语不好,如果你误解了我的意思,我很抱歉。尽我所能

java swing user-interface jscrollpane jlist
1个回答
0
投票

我只想指出显而易见的是“这些项目中只有三个需要可见”是有问题的,因为前三个值可能比以下项目更大或更小,或者使用不同的数据你会得到不同的,有时,奇怪的结果。

我们是使用“原型”值,模型的第一个元素,还是尝试从模型中获取第一个

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
,否则它会满足您想要的结果,搞乱“可见列”是模棱两可和有问题的

© www.soinside.com 2019 - 2024. All rights reserved.