JList更新冻结显示

JList更新冻结显示

本文介绍了JList更新冻结显示,但不冻结JFrame setTitle的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我使用大量html格式的项目更新JList,则控件将停止响应并且指示符将不会更新.这很有意义,事件线程很忙.标题仍然可以设置.为什么会这样?

If I update a JList with a long number of html formatted items then the controls stop responding and indicators won't update. This makes sense, the event thread is busy. The title can still be set though. Why is this?

以下是一些(很长的)代码,证明了这一点:

Here's some (long) code demonstrating this:

import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.InvocationTargetException;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;

public class JListTest extends JFrame {

    class TestListModel extends AbstractListModel<String> {

        private static final long serialVersionUID = JListTest.serialVersionUID;
        private boolean useHtml;
        private String[] formattedList = new String[] {};

        public int getSize() {
            return formattedList.length;
        }

        public String getElementAt(int index) {
            return formattedList[index];
        }

        public void setUseHtml(boolean useHtml) {
            this.useHtml = useHtml;
        }

        public String getNewListItem() {
            if (useHtml) {
                return "<html><div style='padding:2px"
                      + ";background-color:#EDF5F4;color:black'><div style='padding:2px;font-weight:500;'>"
                      + "Item " + (100 * Math.random())
                      + "</div>"
                      + "This will change!"
                      + "</div></html>";
            } else {
                return "Item " + (100 * Math.random());
            }
        }

        public void updateItems() {
            formattedList = new String[] {"<html><h1>Loading!</h1></html>"};
            fireContentsChanged(this, 0, 1);

            Thread buildItems = new Thread() {
                @Override
                public void run() {
                    final String[] tempList = new String[3000];
                    for (int i=0; i<tempList.length; i++) {
                        tempList[i] = getNewListItem();
                    }
                    // Just show the string bashing's done
                    try {
                        SwingUtilities.invokeAndWait(new Runnable() {
                            public void run() {
                                formattedList = new String[] {"<html><h1>Updating!</h1></html>"};
                                fireContentsChanged(TestListModel.this, 0, 1);
                            }
                        });
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // Update
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            formattedList = tempList;
                            fireContentsChanged(TestListModel.this, 0, formattedList.length);
                        }
                    });
                }
            };
            buildItems.start();
        }
    }

    protected static final long serialVersionUID = 1L;

    public JListTest() {

        JPanel controlPanel = new JPanel();
        JButton updaterControl = new JButton("Add 3000");
        final JCheckBox useHtmlControl = new JCheckBox("Use HTML");
        final TestListModel model = new TestListModel();
        JList<String> list = new JList<String>(model);
        JScrollPane scrollPane = new JScrollPane(list);
        final JLabel durationIndicator = new JLabel("0");

        controlPanel.add(useHtmlControl, BorderLayout.WEST);
        controlPanel.add(updaterControl, BorderLayout.EAST);

        getContentPane().add(controlPanel, BorderLayout.PAGE_START);
        getContentPane().add(scrollPane, BorderLayout.CENTER);
        getContentPane().add(durationIndicator, BorderLayout.PAGE_END);

        useHtmlControl.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                model.setUseHtml(useHtmlControl.isSelected());
            }
        });
        useHtmlControl.setSelected(false);

        updaterControl.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                model.updateItems();
            }
        });

        Timer counter = new Timer();
        counter.schedule(new TimerTask() {
            @Override
            public void run() {
                String previousCounter = durationIndicator.getText();
                String newCounter = Integer.toString(
                    Integer.parseInt(previousCounter) + 1);
                durationIndicator.setText(newCounter);
                setTitle(newCounter);
            }
        }, 0, 100);
    }

    public static void main(String args[]) {
        JListTest jlt = new JListTest();
        jlt.pack();
        jlt.setSize(300, 300);
        jlt.setVisible( true );
    }
}

推荐答案

答案很明显-因为Window标题不是Swing组件,而是OS的本机实体.

The answer is pretty obvious - because Window title is not a Swing component, it's OS native entity.

因此更改不必通过摇摆事件队列,但请转到 XDecoratedPeer.updateWMName 直接在Unix或其他操作系统中使用.

So changes don't have to go through Swing Event Queue, but go to XDecoratedPeer.updateWMName directly in case of Unix and to some other class in other OSes.

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

The more interesting question would be how to avoid that UI blocking, but I don't think that's possible with just Swing, you'll have to implement some lazy loading, or rendering in batches.

这篇关于JList更新冻结显示,但不冻结JFrame setTitle的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-30 08:38