【问题标题】:Swing JList freezes when I delete and add while 0 index was selected当我在选择 0 索引时删除和添加时,Swing JList 冻结
【发布时间】:2012-11-21 13:27:52
【问题描述】:

这是一个示例,您按下一个按钮,jList1 将重新填充从 a1 到 a1000 的项目。:

//variable
private List<String> list = new ArrayList<>();

...

//main method
jList1.setModel(new DefaultListModel());
for(int i = 0; i < 1000; i++) {
    list.add("a"+i);
}

...

//button action - jList1 refill
DefaultListModel dtm = (DefaultListModel)jList1.getModel();
dtm.removeAllElements();
for(String s : list) {
    dtm.addElement(s);
}

如果我填写jList1,然后选择(用鼠标)0 索引(jList 中的第一个元素),然后在重新填写列表时按下程序冻结的按钮。如果我选择任何其他元素或根本不选择列表中的任何项目,那么它就可以填满。

附:这个例子是在没有任何 swing 或 EWT 线程的情况下完成的,因为使用它们找到了主要原因。

SSCCE:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package lt;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;

/**
 *
 * @author Minutis
 */
public class Window {

    public static void main(String[] args) {
        final List<String> list = new ArrayList<>();


        JFrame frame = new JFrame("BorderLayout Frame");
        JPanel panel = new JPanel();
        final JList jList1 = new JList();
        JButton refill = new JButton("Refill");

        jList1.setModel(new DefaultListModel());
        for(int i = 0; i < 1000; i++) {
            list.add("a"+i);
        }

        refill.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                DefaultListModel dtm = (DefaultListModel)jList1.getModel();
                dtm.removeAllElements();
                for(String s : list) {
                    dtm.addElement(s);
                }
            }

        });

        frame.add(panel);
        panel.setLayout(new BorderLayout());
        panel.add(jList1, BorderLayout.CENTER);
        panel.add(refill, BorderLayout.SOUTH);
        frame.setSize(300, 300);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

【问题讨论】:

  • 你有异常吗?
  • 不,没有例外,这就是我写在这里的原因。
  • 你能发一个SSCCE吗?
  • 在类似代码中为我工作,没人知道你的休息如何,可能很重要然后发布一个 SSCCE 生成的上午问题,否则必须等待奇迹
  • @Minutis 是的,我知道:这是为了说明 removeAllElements 在选择索引时似乎会做一些不同的事情......无论如何,这是一个很好的解决方法来做 jList1.setSelectedIndex(1);在您清空列表之前:我查看了 java 源代码并检查了索引是否会导致您的代码永远不会崩溃……这不是一个可接受的答案,而是一种解决方法……如果有任何事情要做的话,这是一个非常有趣的“错误”要解决这个问题,它将在 JList 中而不是在模型中......

标签: java swing user-interface jlist


【解决方案1】:

问题是在选择第一个元素时删除模型中的所有元素引起的。 The way it is implemented, when an index is selected and is removed, for some reason it generates a selectionChanged event.如果在删除另一个索引时选择了另一个索引(即使这意味着元素移动),它也不会生成 selectionChanged 事件。

删除的实现方式是定期删除第一个元素,而选择索引保持不变。因此对于选择索引 0 的情况,它会生成 1000 个 selectionChanged 事件,这些事件必须由 EDT 和侦听器处理。如果您选择另一个索引,则仅生成 1 个事件。这大大减少了开销。

在选择索引 0 时重新填充之前,尝试手动将选择设置为索引 1:

if(jList1.getSelectedIndex() == 0){
     jList1.setSelectedIndex(1);
}

如果列表中只有一个元素,我认为无需担心 - 它不应该做任何事情来设置索引大于元素计数。但这可能是特定于实现的。

由于某种原因,clearSelection() 将导致生成 selectionChanged 事件以重新填充空列表。

【讨论】:

  • 在此处查看我的编辑 +1 以获得另一种选择,但我怀疑,JList 导致了一些性能问题......
  • 谢谢这真的有效,如果我把这三行放在jList1.removeAllElements();之前
  • 不知道,你能拿我的 SSCCE 来修改你的观点吗,在这种情况下,代码行的顺序可能取决于 :-),顺便说一下 clearSelection 和 Swing Timer 的延迟(或 trhead.sleep == don 't talk about)解决了这个问题
  • @Minutis 没有像你描述的那样冻结,必须等待 Jakub :-)
【解决方案2】:
  • 逻辑和更好的可以(只是为了避免拼写错误)是add/remove/modifyItems直接在XxxListModel

例如

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Testing extends JFrame {

    private static final long serialVersionUID = 1L;
    private DefaultListModel listModel = new DefaultListModel();
    private JList list = new JList(listModel);
    private int currentSelectedRow = 0;
    private int xX = 0;

    public Testing() {
        setLocation(400, 300);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        for (int x = 0; x < 51; x++) {
            listModel.addElement("" + x);
            xX++;
        }
        JScrollPane sp = new JScrollPane(list);
        final JViewport vp = sp.getViewport();
        add(sp, BorderLayout.CENTER);
        /*JButton btn = new JButton("Get Row:");
        add(btn, BorderLayout.SOUTH);
        btn.addActionListener(new ActionListener() {

        public void actionPerformed(ActionEvent ae) {
        try {
        int goToRow = Integer.parseInt(JOptionPane.showInputDialog(getContentPane(), "Go To Row:"));
        Rectangle r = list.getCellBounds(goToRow, goToRow);
        if (goToRow > currentSelectedRow) {
        r = list.getCellBounds(goToRow - 1, goToRow - 1);
        int vph = vp.getExtentSize().height;
        r.y += vph;
        }
        list.scrollRectToVisible(r);
        list.setSelectedIndex(goToRow);
        currentSelectedRow = goToRow;
        } catch (Exception e) {

        }
        }
        });*/
        JButton btn1 = new JButton("Reset Model CastingModel");
        add(btn1, BorderLayout.NORTH);
        btn1.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                DefaultListModel model = (DefaultListModel) list.getModel();
                model.removeAllElements();
                for (int x = 0; x < 51; x++) {
                    model.addElement("" + (x + xX));
                    xX++;
                }
                //list.setModel(model);
            }
        });

        JButton btn2 = new JButton("Reset Model directly from Model");
        add(btn2, BorderLayout.SOUTH);
        btn2.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                listModel.removeAllElements();
                for (int x = 0; x < 51; x++) {
                    listModel.addElement("" + (x + xX));
                    xX++;
                }
            }
        });

        pack();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Testing().setVisible(true);
            }
        });
    }
}

编辑list.clearSelection();没有任何问题,所有超过 1k 行都是由 OP 所描述的问题引起的

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Testing extends JFrame {

    private static final long serialVersionUID = 1L;
    private DefaultListModel listModel = new DefaultListModel();
    private JList list = new JList(listModel);
    private int currentSelectedRow = 0;
    private int xX = 0;

    public Testing() {
        setLocation(400, 300);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        for (int x = 0; x < 999; x++) {
            listModel.addElement("" + x);
            xX++;
        }
        JScrollPane sp = new JScrollPane(list);
        final JViewport vp = sp.getViewport();
        add(sp, BorderLayout.CENTER);

        JButton btn1 = new JButton("Reset Model CastingModel");
        add(btn1, BorderLayout.NORTH);
        btn1.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                list.clearSelection();
                DefaultListModel model = (DefaultListModel) list.getModel();
                model.removeAllElements();
                for (int x = 0; x < 999; x++) {
                    model.addElement("" + (x + xX));
                    xX++;
                }
                //list.setModel(model);
            }
        });

        JButton btn2 = new JButton("Reset Model directly from Model");
        add(btn2, BorderLayout.SOUTH);
        btn2.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                list.clearSelection();
                listModel.removeAllElements();
                for (int x = 0; x < 999; x++) {
                    listModel.addElement("" + (x + xX));
                    xX++;
                }
            }
        });

        pack();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Testing().setVisible(true);
            }
        });
    }
}

【讨论】:

  • 仍然是同样的问题,您不会感觉到元素数量的冻结 - 将其从 50 增加到 5000。然后不要选择列表中的任何内容并按下这两个按钮中的任何一个。不会有滞后。但是,如果您首先选择列表中的第一个元素,然后按这两个按钮中的任何一个 - 您将看到 THE LAG。
  • 对,(我从来没有把大量的项目放到 JList 中)请对你这边的项目有限制,在
猜你喜欢
  • 2021-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-16
  • 1970-01-01
  • 2011-03-28
  • 2014-07-09
相关资源
最近更新 更多