JList повторно обновляет defaultlistmodel после выбора элемента 0

Я использую дизайнер Swing в Eclipse для создания графического интерфейса для отображения моих фильмов, которые хранятся в файле XML. После загрузки фрейма и содержимого в различные JList приложение настроено на обновление списков при выборе элемента. Итак, если вы выберете жанр, будут показаны все фильмы этого жанра, то же самое относится к группам, эпизодам и сезонам. У меня также есть кнопка обновления списков, которая перезагружает списки.

проблема, с которой я сталкиваюсь, заключается в следующем: когда я выбрал элемент с индексом 0, вызывается дополнительное действие прослушивателя по сравнению с тем, когда я выбираю индекс 1 или выше. Затем (моя основная проблема), если я нажму кнопку обновления, прослушиватель будет запущен для каждого элемента, добавленного в listmodel для ранее выбранного JList.

Например, если я выберу 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");
    }
}

person APW    schedule 21.05.2015    source источник
comment
Чтобы быстрее получить помощь, опубликуйте MCVE (минимальный полный проверяемый пример) или SSCCE (краткий, автономный, правильный пример).   -  person Andrew Thompson    schedule 21.05.2015
comment
Я отредактирую, спасибо, сейчас отредактировал   -  person APW    schedule 21.05.2015
comment
@APW Пожалуйста, создайте пример, в котором используются только стандартные классы Java, чтобы мы могли запустить его и воспроизвести вашу проблему. У меня нет ни класса Video, ни VideoProvider, ни ItemToUpdate. Я знаю о MigLayout, но его нет в моем пути к классу.   -  person Sergiy Medvynskyy    schedule 21.05.2015
comment
Не совсем понимаю ваш код, но я предполагаю, что он как-то связан с setLists. Если где-то вы снова добавляете все обратно в свою модель списка, например, для обновления, вы будете отключать прослушиватель один раз для каждого добавленного элемента.   -  person swingMan    schedule 21.05.2015
comment
Я заменил код на новую версию, которая сталкивается с точно такими же проблемами при обновлении индекса 0.   -  person APW    schedule 21.05.2015
comment
@SergiyMedvynskyy Добавлено всего 3 компонента. Я просто удалил строку setLayout. С учетом сказанного, @APW все равно должен это исправить.   -  person user1803551    schedule 22.05.2015


Ответы (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 для обоих списков.
  • I removed the Integer list selection listener because it serves no purpose. It will be called once in 2 situations:
    1. When a value is selected (selected index >= 0).
    2. При применении фильтра, так как список очищается (выбранный индекс = -1).
  • Используйте pack() для JFrame вместо установки его размера и местоположения.
person user1803551    schedule 22.05.2015
comment
Кажется, это решает мои проблемы. Целочисленный список является заполнителем для списка названий фильмов. Если вы считаете, что Jlist — плохой выбор, что бы вы порекомендовали? Я использовал кнопку, потому что обновлял 4 разных списка одновременно, но я вижу преимущество опции «Все» в списках. Спасибо. - person APW; 22.05.2015
comment
@APW Я не думаю, что это плохой выбор, как я его использую. Предполагается, что JList показывает список элементов, из которых вы можете выбрать один (или несколько) элементов. Выбор выделяет элемент и оставляет другие элементы видимыми. Вы не используете это, вы просто удаляете все невыбранные элементы, что заставило меня задуматься о том, что именно вы пытаетесь сделать со списком. Я не знаю, какие еще у вас есть списки, поэтому не могу порекомендовать кнопку обновления. - person user1803551; 22.05.2015
comment
Спасибо, это на самом деле более полезный ответ, чем вы можете себе представить. У меня есть 4 списка, которые в зависимости от их порядка будут изменять оставшиеся невыбранные списки. Раньше я просто запускал метод, который обновлял все 4 списка одновременно, но теперь я понимаю, почему лучше настроить его так, чтобы он обновлял только невыбранные списки. Это приложение было для меня крутой кривой обучения, я пишу на Java всего 6 месяцев :-) - person APW; 22.05.2015
comment
@APW Я не думаю, что тебе нужно что-то обновлять. Просто добавьте нефильтрованный вариант для всех фильтров, например, вариант «Все». - person user1803551; 22.05.2015