JList 没有像我预期的那样表现

JList not behaving as I expected

我正在练习 JList,当单击“添加数字”按钮时,它会填充随机数,我 运行 遇到了一些我无法解决的问题修复。

在下面的代码中,我放置了一个按钮来切换列表的可见性状态,但事实证明它不起作用,除非列表最初是可见的。

然后我将列表设置为显示 8 行,但只显示了 7 行。

最后,如果只使用小数点后 3 位,那么右侧有足够的空间,为什么水平滚动窗格会出现?

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class JListTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        listFrame myFrame=new listFrame();
        myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        myFrame.setVisible(true);
    }
}

class listFrame extends JFrame {
    private static DecimalFormat df3 = new DecimalFormat("#.###");
    public listFrame() {
        setTitle("List demo");
        setBounds(400,300,400,300);
        listModel = new DefaultListModel();
        randomNumberList=new JList(listModel);
        //**********************************************************************
        // the number of elements visible in the list turns out to be
        // one less than the specified below
        randomNumberList.setVisibleRowCount(8);
        //**********************************************************************
        randomNumberList.setFixedCellWidth(100);
        JScrollPane scrollPanel=new JScrollPane(randomNumberList);
        //**********************************************************************
        // if this line is uncommented the button fails to make the list visible
        // scrollPanel.setVisible(false);
        //**********************************************************************
        JPanel listPanel=new JPanel();
        listPanel.add(scrollPanel);
        JPanel textPanel=new JPanel();      
        toggle=new JButton("Toggle Visible");
        toggle.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                scrollPanel.setVisible(!scrollPanel.isVisible());
            }
        });
        textPanel.add(toggle);
        addNumber=new JButton("Add Numbers");
        addNumber.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                double min=0;
                double max=1000;
                double x= Math.random()*(max-min+1)+min;
                listModel.addElement(df3.format(x));
                randomNumberList.ensureIndexIsVisible(listModel.getSize()-1);
            }
        });
        textPanel.add(addNumber);
        add(listPanel,BorderLayout.NORTH);
        add(textPanel,BorderLayout.SOUTH);
    }
    private JButton toggle,addNumber;
    private JList randomNumberList;
    private DefaultListModel listModel;
}

更新:这是我在下面的评论中提到的一些代码,其中 setVisibleRowCount 确实有效:

import java.awt.BorderLayout;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class JList_ShowMonths {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        JFrame myLFrame=new MonthFrame();
        myLFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    
        myLFrame.setVisible(true);
    }
}

class MonthFrame extends JFrame {
    private JList<String> monthList;
    private JPanel listPanel,txtPanel;
    private JLabel selectionLabel;
    public MonthFrame() {
        setTitle("Display the month names");
        setBounds(400,300,400,300);
        String [] months= {"January","February","March","April","May","June",
                "July","August","September","October","November","December"};
        monthList=new JList<String>(months);
        monthList.setVisibleRowCount(4);
        JScrollPane monthScroll=new JScrollPane(monthList);
        listPanel=new JPanel();
        listPanel.add(monthScroll);
        monthList.addListSelectionListener(new ListSelectionListener(){
            public void valueChanged(ListSelectionEvent e) {
                List<String> values=monthList.getSelectedValuesList();
                StringBuilder text=new StringBuilder("Selected month: ");
                for (String element:values) {
                    String word=element;
                    text.append(word);
                    text.append(" ");
                }
                selectionLabel.setText(text.toString());
            }
        });
        txtPanel=new JPanel();
        selectionLabel=new JLabel("Mes seleccionado:");
        txtPanel.add(selectionLabel);
        add(listPanel,BorderLayout.NORTH);
        add(txtPanel,BorderLayout.SOUTH);
    }
}

首先是代码。代码后的解释。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;

import java.text.DecimalFormat;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class LstFrame extends JFrame {
    private static DecimalFormat df3 = new DecimalFormat("#.###");

    private JButton toggle, addNumber;
    private JList<Object> randomNumberList;
    private DefaultListModel<Object> listModel;

    public LstFrame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("List demo");
        listModel = new DefaultListModel<Object>();
        randomNumberList = new JList<>(listModel);
        randomNumberList.setVisibleRowCount(8);
        randomNumberList.setFixedCellWidth(100);
        JScrollPane scrollPanel = new JScrollPane(randomNumberList);
        scrollPanel.setPreferredSize(new Dimension(110, 100));
        scrollPanel.setVisible(false);
        JPanel textPanel = new JPanel();
        toggle = new JButton("Toggle Visible");
        toggle.addActionListener(e -> {
            scrollPanel.setVisible(!scrollPanel.isVisible());
            revalidate();
        });
        textPanel.add(toggle);
        addNumber = new JButton("Add Numbers");
        addNumber.addActionListener(e -> {
            double min = 0;
            double max = 1000;
            double x = Math.random() * (max - min + 1) + min;
            listModel.addElement(df3.format(x));
            randomNumberList.ensureIndexIsVisible(listModel.getSize() - 1);
        });
        textPanel.add(addNumber);
        add(scrollPanel, BorderLayout.CENTER);
        add(textPanel, BorderLayout.SOUTH);
        setSize(260, 240);
        setLocationByPlatform(true);
        setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> new LstFrame());
    }
}

如果一个组件最初是不可见的,则不会对其进行绘制,其余组件也不会以为不可见组件留下 space 的方式进行绘制。因此,在上面的代码中,我设置了 JFrame 的大小。我只是简单地摆弄数字,直到找到合适的值。

是的,JFrame[的内容窗格] 的默认布局管理器是 BorderLayout。只有 BorderLayout 中的中心组件以其首选大小显示。因此,您应该在中心而不是在 NORTH 添加 JScrollPane(其中包含 JList)。并且您还应该明确设置 JScrollPane 的首选大小。另请注意,在确定 NORTH、EAST、WEST 和 SOUTH 组件所需的 space 后,CENTER 组件占据了剩余的所有 space。因此,如果您调整 JFrame 的大小,JScrollPane 的大小也会改变。

包含 JButtonJPanel 可以安全地添加到 SOUTH。

当您更改容器中显示的组件时(通过添加或删除组件或更改组件的可见性),您需要重新绘制 GUI。方法 revalidate 是一种方法。 toggle.

参考 ActionListener

我不知道如何创建动画 GIF,所以我无法添加一个演示上述代码的实际操作。但是,我可以 post 分开显示不同状态的图像。

启动应用程序后。

按下后 切换 Visibe

添加十个 [随机] 数字后 – 因为 JScrollPane 的首选高度足以显示九个数字。