使用Java中的自定義單元格渲染器重新渲染JTable時,我遇到了一些凍結SWING GUI的問題。所以我問了這個問題「Why does a JTable view update block the entire GUI?」。答案指出了一個事實,即一個沒有修改JTable並覆蓋的JList可能是一個更好的選擇。所以我用JList實現了這個例子,並遇到了同樣的問題:在生成數據時,一切正常,進度條移動。但是當視圖更新時,程序凍結並且進度條停止移動。爲什麼JList的fireContentsChanged調用會凍結整個GUI?
請注意,睡眠聲明僅僅是爲了讓世代花費更長,更實際的時間(通過JDBC讀取數千個數據集並在其中創建對象需要很長時間)。人們可以刪除它並增加生成項目的數量。但是你可以清楚地看到,HTML渲染速度很慢。但我需要這種顏色和兩條線(如果不一定是那麼多不同的顏色)。
那麼你能告訴我,我的錯誤在哪裏?我認爲,美國東部時間和其他工作是通過單獨的線程分開的,我看不出任何錯誤。
更新:我環顧了SO,發現這個問題「https://stackoverflow.com/a/20813122/2429611」。有說:
更有趣的問題是如何避免該UI阻塞,但我不認爲這是可能的只是擺動,你將不得不實施一些延遲加載,或批量渲染。
這意味着,我無法解決我的問題。它是否正確?
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);
}
});
}
}
我忘了這個模型是不完整的 – mKorbel