Java 为什么JList的fireContentsChanged调用会冻结整个GUI?

Java 为什么JList的fireContentsChanged调用会冻结整个GUI?,java,multithreading,swing,user-interface,Java,Multithreading,Swing,User Interface,当用Java中的自定义单元格渲染器重新渲染JTable时,我在冻结SWING GUI方面遇到了一些问题。所以我问了一个问题。答案指出了一个事实,即不修改JTable和覆盖doLayout的JList可能是更好的选择。因此,我使用JList实现了这个示例,并遇到了相同的问题:在生成数据时,一切正常,进度条移动。但当视图更新时,程序冻结,进度条停止移动 请注意,sleep语句只是为了让生成过程花费更长、更真实的时间(通过JDBC读取数千个数据集并从中创建对象需要很多时间)。可以删除它并增加生成项目的

当用Java中的自定义单元格渲染器重新渲染
JTable
时,我在冻结SWING GUI方面遇到了一些问题。所以我问了一个问题。答案指出了一个事实,即不修改
JTable
和覆盖
doLayout
JList
可能是更好的选择。因此,我使用
JList
实现了这个示例,并遇到了相同的问题:在生成数据时,一切正常,进度条移动。但当视图更新时,程序冻结,进度条停止移动

请注意,sleep语句只是为了让生成过程花费更长、更真实的时间(通过
JDBC
读取数千个数据集并从中创建对象需要很多时间)。可以删除它并增加生成项目的数量。但是您可以清楚地看到,HTML呈现相当慢。但我需要这种颜色和两条线(如果不一定有这么多不同的颜色)

你能告诉我,我的错在哪里吗?我认为,EDT和其他工作是通过不同的线程分开的,我看不到任何错误

更新:我环顾了一下SO,发现了这个问题“”。据说:

更有趣的问题是如何避免UI阻塞,但我认为仅使用Swing是不可能的,您必须实现一些延迟加载或成批渲染

这意味着,我无法解决我的问题。这是正确的吗


包示例;
导入java.awt.BorderLayout;
导入java.awt.Color;
导入java.awt.Component;
导入java.awt.FlowLayout;
导入java.awt.Graphics;
导入java.awt.event.ActionEvent;
导入java.security.SecureRandom;
导入java.util.ArrayList;
导入java.util.List;
导入javax.swing.AbstractAction;
导入javax.swing.AbstractListModel;
导入javax.swing.Box;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JList;
导入javax.swing.JPanel;
导入javax.swing.JProgressBar;
导入javax.swing.JScrollPane;
导入javax.swing.ListCellRenderer;
导入javax.swing.SwingUtilities;
公共类ListExample扩展了AbstractListModel{
静态列表internalList=新的ArrayList();
@凌驾
公共int getSize(){
返回internalList.size();
}
@凌驾
公共DemoObject getElementAt(int索引){
返回internalList.get(索引);
}
公共无效fireContentsChanged(){
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
fireContentsChanged(这个,0,-1);
}
});
}
静态类MyCellRenderer扩展了JLabel实现ListCellRenderer{
公共菌丝体(){
set不透明(true);
}
@凌驾
公共组件getListCellRenderComponent(JList有三个问题(重新创建、重置模型和自定义渲染器停止工作)

  • ,您必须将新型号设置为JList

  • 请参阅ComboBoxModel扩展AbstractListModel实现setElementAt的可变ComboxModel的重要信息(用于保存当前选择)

  • 使用
    public void fireContentsChanged(){
    是错误的,看不出使用这种方式的原因,再次即将替换当前,重置模型

  • 例如,通过成功atr运行时和针对/if事件(已触发)的重新启动测试


    我忘了这个模型是不完整的
    package example;
    
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.FlowLayout;
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.security.SecureRandom;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.AbstractAction;
    import javax.swing.AbstractListModel;
    import javax.swing.Box;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JList;
    import javax.swing.JPanel;
    import javax.swing.JProgressBar;
    import javax.swing.JScrollPane;
    import javax.swing.ListCellRenderer;
    import javax.swing.SwingUtilities;
    
    public class ListExample  extends AbstractListModel {
    
        static List<DemoObject> internalList = new ArrayList<>();
    
            @Override
            public int getSize() {
                return internalList.size();
            }
    
            @Override
            public DemoObject getElementAt(int index) {
                return internalList.get(index);
            }
    
            public void fireContentsChanged() {
                SwingUtilities.invokeLater(new Runnable() {
    
                    @Override
                    public void run() {
                        fireContentsChanged(this, 0, -1);
                    }
                });
            }
    
        static class MyCellRenderer extends JLabel implements ListCellRenderer<ListExample.DemoObject> {
            public MyCellRenderer() {
                setOpaque(true);
            }
    
            @Override
            public Component getListCellRendererComponent(JList<? extends ListExample.DemoObject> list,
                                                          ListExample.DemoObject value,
                                                          int index,
                                                          boolean isSelected,
                                                          boolean cellHasFocus) {
    
                setText("<html>" + value.toString() 
                        + "<br/>" 
                        + "<span bgcolor=\"#ff0000\">Line 2; Color = " + value.c + "</span>");
    
                Color background;
                Color foreground;
    
                // check if this cell represents the current DnD drop location
                JList.DropLocation dropLocation = list.getDropLocation();
                if (dropLocation != null
                        && !dropLocation.isInsert()
                        && dropLocation.getIndex() == index) {
    
                    background = Color.BLUE;
                    foreground = Color.WHITE;
    
                // check if this cell is selected
                } else if (isSelected) {
                    background = Color.RED;
                    foreground = Color.WHITE;
    
                // unselected, and not the DnD drop location
                } else {
                    background = value.c; //Color.WHITE;
                    foreground = Color.BLACK;
                };
    
                setBackground(background);
                setForeground(foreground);
    
                return this;
            }
        }
    
        static class DemoObject {
    
            String str;
            Color c;
    
            public DemoObject(String str, int color) {
                this.str = str;
                this.c = new Color(color);
            }
    
            @Override
            public String toString() {
                return str;
            }
    
        }
    
        static JPanel overlay;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    JFrame frame = new JFrame("Example");
                    frame.setLayout(new BorderLayout(4, 4));
    
                    // Add JTable
                    final ListExample model = new ListExample();
                    JList list = new JList(model);
                    list.setCellRenderer(new MyCellRenderer());
                    frame.add(new JScrollPane(list), BorderLayout.CENTER);
    
                    // Add button
                    Box hBox = Box.createHorizontalBox();
                    hBox.add(new JButton(new AbstractAction("Load data") {
    
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            new Thread(new Runnable() {
    
                                @Override
                                public void run() {
                                    overlay.setVisible(true);
                                    internalList.clear();
    
                                    System.out.println("Generating data ...");
    
                                    SecureRandom sr = new SecureRandom();
                                    for (int i = 0; i < 10000; i++) {
                                        internalList.add(
                                                new DemoObject(
                                                        "String: " + i + " (" + sr.nextFloat() + ")",
                                                        sr.nextInt(0xffffff)
                                                )
                                        );
    
                                        // To create the illusion, that data are
                                        // fetched via JDBC (which takes a little
                                        // while), this sleep statement is embedded
                                        // here. In a real world scenario, this wait
                                        // time is caused by talking to the database
                                        // via network
                                        if (i%10 == 0) {
                                            try {
                                                Thread.sleep(1);
                                            } catch (Exception e) {
                                            }
                                        }
                                    }
    
                                    System.out.println("Updating view ...");
    
                                    model.fireContentsChanged();
                                    overlay.setVisible(false);
    
                                    System.out.println("Finished.");
                                }
                            }).start();
                        }
                    }));
                    hBox.add(Box.createHorizontalGlue());
                    frame.add(hBox, BorderLayout.NORTH);
    
                    // Create loading overlay
                    overlay = new JPanel(new FlowLayout(FlowLayout.CENTER)) {
    
                        @Override
                        protected void paintComponent(Graphics g) {
                            g.setColor(new Color(0, 0, 0, 125));
                            g.fillRect(0, 0, getWidth(), getHeight());
                            super.paintComponent(g);
                        }
                    };
                    overlay.setOpaque(false);
                    overlay.setBackground(new Color(0, 0, 0, 125));
                    JProgressBar bar = new JProgressBar();
                    bar.setIndeterminate(true);
                    overlay.add(bar);
    
                    frame.setGlassPane(overlay);
                    frame.getGlassPane().setVisible(false);
    
                    // Create frame
                    frame.setSize(600, 400);
                    frame.setVisible(true);
                }
            });
        }
    
    }
    
       setModel(new DefaultListModel(list.toArray()) {
    
          protected void fireContentsChanged(Object obj, int i, int j) {
            if (!isFired)
              super.fireContentsChanged(obj, i, j);
          }
    
        });