JList 在选择项目 0 后重复更新 defaultlistmodel
JList repeatedly updating defaultlistmodel after selecting item 0
我正在使用 Eclipse 中的 Swing 设计器构建一个 GUI 来列出我存储在 XML 文件中的电影。将框架和内容加载到各种 JList
后,我将应用程序设置为在 selected 项目时更新列表。因此,如果您选择一种类型,将显示该类型的所有电影,这同样适用于团体、剧集和季节。我还有一个刷新列表按钮,可以重新加载列表。
我遇到的问题是:当我 select 编辑索引 0
处的项目时,与 select 索引 [=13] 相比,会调用额外的侦听器操作=] 或更高。然后(我的主要关注点),如果我 select 刷新按钮,则会为之前 selected JList
添加到 listmodel
的每个项目触发一个侦听器。
例如,如果我从剧集列表中 select 1
然后刷新,则只会调用 1 个侦听器。但是,如果我从剧集列表 select 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();
}
}
备注:
- 我为过滤器列表添加了一个 "All" 选项,而不是刷新按钮。
- 不应修改过滤器列表(没有理由)。
- 检查
e.getValueIsAdjusting()
以免执行不必要的操作。
- 我将两个列表的选择模型都设置为
SINGLE_SELECTION
。
- 我删除了
Integer
列表选择侦听器,因为它没有用。它会在两种情况下被调用 一次:
- 选择一个值时(选择的索引>=0)。
- 应用过滤器时,由于列表被清除(所选索引 = -1)。
- 在
JFrame
上使用 pack()
而不是设置其大小和位置。
我正在使用 Eclipse 中的 Swing 设计器构建一个 GUI 来列出我存储在 XML 文件中的电影。将框架和内容加载到各种 JList
后,我将应用程序设置为在 selected 项目时更新列表。因此,如果您选择一种类型,将显示该类型的所有电影,这同样适用于团体、剧集和季节。我还有一个刷新列表按钮,可以重新加载列表。
我遇到的问题是:当我 select 编辑索引 0
处的项目时,与 select 索引 [=13] 相比,会调用额外的侦听器操作=] 或更高。然后(我的主要关注点),如果我 select 刷新按钮,则会为之前 selected JList
添加到 listmodel
的每个项目触发一个侦听器。
例如,如果我从剧集列表中 select 1
然后刷新,则只会调用 1 个侦听器。但是,如果我从剧集列表 select 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();
}
}
备注:
- 我为过滤器列表添加了一个 "All" 选项,而不是刷新按钮。
- 不应修改过滤器列表(没有理由)。
- 检查
e.getValueIsAdjusting()
以免执行不必要的操作。 - 我将两个列表的选择模型都设置为
SINGLE_SELECTION
。 - 我删除了
Integer
列表选择侦听器,因为它没有用。它会在两种情况下被调用 一次:- 选择一个值时(选择的索引>=0)。
- 应用过滤器时,由于列表被清除(所选索引 = -1)。
- 在
JFrame
上使用pack()
而不是设置其大小和位置。