gpt4 book ai didi

java - 为什么 JList 的 fireContentsChanged 调用会卡住整个 GUI?

转载 作者:行者123 更新时间:2023-12-01 12:52:10 24 4
gpt4 key购买 nike

在使用 Java 中的自定义单元格渲染器重新渲染 JTable 时,我遇到了一些卡住 SWING GUI 的问题。于是我就问了“Why does a JTable view update block the entire GUI?”这个问题。答案指出了这样一个事实:不修改 JTable 和覆盖 doLayoutJList 可能是更好的选择。因此,我使用 JList 实现了该示例,并遇到了同样的问题:在生成数据时,一切正常并且进度条移动。但是当 View 更新时,程序卡住并且进度条停止移动。

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

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

更新:我环顾四周,发现了这个问题“https://stackoverflow.com/a/20813122/2429611”。有句话说:

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.

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

<小时/>
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);
}
});
}

}

最佳答案

存在三个问题(重新创建、重置模型和自定义渲染器停止工作)

  1. JList (JComboBox hasn't) has an issue by removing more than 999 items ,你必须为JList设置一个新模型

  2. 请参阅 ComboBoxModel 扩展 AbstractListModel 为 setElementAt 实现 MutableComboBoxModel 的重要内容(以保存当前选择)

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

    <

。例如成功执行 atr 运行时并通过递归测试/if 事件(已触发)

   setModel(new DefaultListModel(list.toArray()) {

protected void fireContentsChanged(Object obj, int i, int j) {
if (!isFired)
super.fireContentsChanged(obj, i, j);
}

});

关于java - 为什么 JList 的 fireContentsChanged 调用会卡住整个 GUI?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24138186/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com