java - 选择项目 0 后 JList 反复更新 defaultlistmodel

标签 java swing jlist defaultlistmodel listselectionlistener

我正在使用 Eclipse 中的 Swing 设计器构建一个 GUI 来列出存储在 XML 文件中的电影。将框架和内容加载到各个 JList 后,我将应用程序设置为在选择某个项目时更新列表。因此,如果您选择一种类型,则该类型的所有电影都会显示,这同样适用于组、剧集和季节。我还有一个刷新列表按钮,可以重新加载列表。

我遇到的问题是:当我选择索引 0 处的项目时,与选择索引 1 或更高索引时相比,会调用额外的监听器操作。然后(我主要关心的是),如果我选择刷新按钮,则会为添加到先前选择的 JListlistmodel 中的每个项目触发监听器。

例如,如果我从剧集列表中选择 1 然后刷新,则只会调用 1 个监听器。但是,如果我从剧集列表中选择 0 并刷新,则会调用 35 个听众(这是列表中的剧集总数)。

对于像剧集这样的小节目来说,这并不是一个大问题,但当这种情况发生在电影专栏上时,我会解雇大约 1500 名听众。

package local.testarea;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import net.miginfocom.swing.MigLayout;

@SuppressWarnings( { "rawtypes", "unchecked" } )
public class ListDemo {

    private JFrame frame;
    private JList list, list_1;
    private JButton btnNewButton;
    private DefaultListModel<String> list2;
    private DefaultListModel<Integer> list1;

    /**
     * Launch the application.
     */
    public static void main( String[] args )
    {
        EventQueue.invokeLater( new Runnable() {

            public void run()
            {
                try
                {
                    ListDemo window = new ListDemo();
                    window.frame.setVisible( true );
                }
                catch ( Exception e )
                {
                    e.printStackTrace();
                }
            }
        } );
    }

    /**
     * Create the application.
     */
    public ListDemo()
    {
        list1 = new DefaultListModel<Integer>();
        list2 = new DefaultListModel<String>();
        initialize();
        updateAll();
    }

    private void updateAll()
    {
        list1.clear();
        list2.clear();
        for ( int i = 0; i < 101; i++ )
        {
            list1.addElement( i );
        }
        list2.addElement( "Even" );
        list2.addElement( "Odd" );

    }

    private void updateLists( int selected )
    {
        list1.clear();
        list2.clear();
        switch( selected )
        {
            case 0:
                for ( int i = 0; i < 101; i++)
                {
                    if ( i % 2 == 0 ) 
                    {
                        list1.addElement( i );
                    }
                }
                list2.addElement( "Even" );
                break;

            case 1:
                for ( int i = 0; i < 101; i++)
                {
                    if ( i % 2 != 0 ) 
                    {
                        list1.addElement( i );
                    }
                }
                list2.addElement( "Odd" );
                break;

            default:
                int z = selected - 10;
                list1.addElement( z );
                list2.addElement( "Even" );
                list2.addElement( "Odd" );
                break;
        }
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize()
    {
        frame = new JFrame();
        frame.setBounds( 100, 100, 450, 481 );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.getContentPane().setLayout(new MigLayout("", "[grow][grow]", "[grow][]"));

        JScrollPane scrollPane = new JScrollPane();
        frame.getContentPane().add(scrollPane, "cell 0 0,grow");

        list = new JList( list1 );
        list.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                System.out.println( "List 1 trigger" );
                System.out.println( "selected item: " + list_1.getSelectedIndex() );
                if ( list.getSelectedIndex() >= 0 )
                {
                    int z = 10 + list.getSelectedIndex();
                    updateLists( z );
                }
            }
        });
        scrollPane.setViewportView(list);

        JScrollPane scrollPane_1 = new JScrollPane();
        frame.getContentPane().add(scrollPane_1, "cell 1 0,grow");

        list_1 = new JList( list2 );
        list_1.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                System.out.println( "List 2 trigger" );
                System.out.println( "selected item: " + list_1.getSelectedIndex() );
                if ( list_1.getSelectedIndex() >= 0 )
                {
                    updateLists( list_1.getSelectedIndex() );
                }
            }
        });
        scrollPane_1.setViewportView(list_1);

        btnNewButton = new JButton("New button");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println( "refresh" );
                updateAll();
            }
        });
        frame.getContentPane().add(btnNewButton, "cell 1 1");
    }
}

最佳答案

您正在修改列表,而选择仍在进行中,这会导致(递归地)触发其他选择事件。您还无缘无故地修改了这两个列表。

String 列表应该仅充当Integer 列表的过滤器。另外,我不明白为什么在选择单个值时要从 Integer 列表中删除所有项目。这使得 JList 看起来不是您想要使用的。

无论如何,我修改了您的ListSelectionListener:

public class ListDemo extends JFrame{

    private DefaultListModel<Integer> listModel1 = new DefaultListModel<>();
    private DefaultListModel<String> listModel2 = new DefaultListModel<>();
    private JList<Integer> list1 = new JList<>(listModel1);
    private JList<String> list2 = new JList<>(listModel2);
    int size = 101;

    public ListDemo() {

        list1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        add(new JScrollPane(list1));

        list2.addListSelectionListener(new ListParityFilter());
        list2.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listModel2.addElement("All");
        listModel2.addElement("Even");
        listModel2.addElement("Odd");
        list2.setSelectedIndex(0);
        add(new JScrollPane(list2), BorderLayout.EAST);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private class ListParityFilter implements ListSelectionListener {

        public void valueChanged(ListSelectionEvent e) {

            if (e.getValueIsAdjusting())
                return;
            System.out.println("Selected List2 item: " + list2.getSelectedValue());
            listModel1.clear();
            switch (list2.getSelectedIndex()) {
                case 0:
                    for (int i = 0; i < size; i++)
                        listModel1.addElement(i);
                    break;
                case 1:
                    for (int i = 0; i < size; i += 2)
                        listModel1.addElement(i);
                    break;
                case 2:
                    for (int i = 1; i < size; i += 2)
                        listModel1.addElement(i);
                    break;
            }
        }
    }

    public static void main(String[] args) {

        new ListDemo();
    }
}

注释:

  • 我为过滤器列表添加了“全部”选项,而不是刷新按钮。
  • 不应修改过滤器列表(没有理由)。
  • 检查 e.getValueIsAdjusting(),以免执行不必要的操作。
  • 我将两个列表的选择模型设置为 SINGLE_SELECTION
  • 我删除了 Integer 列表选择监听器,因为它没有任何作用。在两种情况下它会被调用一次:
    1. 选择某个值时(所选索引 >= 0)。
    2. 应用过滤器后,列表会被清除(所选索引 = -1)。
  • JFrame 上使用 pack(),而不是设置其大小和位置。

关于java - 选择项目 0 后 JList 反复更新 defaultlistmodel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30376609/

相关文章:

java - 套接字:使用 Java 发现端口可用性

java - 缺少 SWT 依赖 Artifact ?

java - GridLayout 中 JPanel 之间的差距

java - 在Java Swing中获取选定值JList或List,卡在ListModel的getElementAt()中

java - 我可以让派生类从 Java 中的基类继承派生成员吗?

java - 使用 JPA hibernate ,连接时间非常慢

Java JTextArea 允许滚动超出文本末尾

java - 在交替列 GridBagLayout 中设置组件

java - 单击按钮加载 JList

java - 将 JList 复制到 arrayList 时出错