【问题标题】:JList update freezes display but not JFrame setTitleJList 更新冻结显示,但不冻结 JFrame setTitle
【发布时间】:2013-12-28 07:10:52
【问题描述】:

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

这里有一些(长)代码展示了这一点:

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 );
    }
}

【问题讨论】:

    标签: jframe jlist event-dispatch-thread


    【解决方案1】:

    答案很明显——因为 Window title 不是 Swing 组件,它是 OS 原生实体。

    因此,更改不必通过Swing Event Queue,而是在 Unix 的情况下直接转到 XDecoratedPeer.updateWMName,在其他操作系统中转到其他类。

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

    【讨论】:

    猜你喜欢
    • 2018-07-18
    • 2012-02-11
    • 1970-01-01
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 2015-07-15
    • 2011-08-07
    相关资源
    最近更新 更多