如果我使用大量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 );
}
}
答案 0 :(得分:1)
答案非常明显 - 因为Window title不是Swing组件,它是OS本机实体。
因此,更改不必通过Swing Event Queue,但在Unix的情况下直接转到XDecoratedPeer.updateWMName,在其他操作系统中转到其他类。
更有趣的问题是如何避免UI阻塞,但我认为只有Swing才有可能,你必须实现一些延迟加载或批量渲染。