Java 显示格式化为HTML的大型JLIST
我有一个java小程序,其中必须显示大量项(字典条目)。用户需要能够选择列表中的单个项目,因此它被实现为JList。生成列表的速度非常快,直到我决定使用HTML格式化单个项目,使显示更加令人愉快。现在列表看起来很漂亮,但是每次用户访问字典时都需要10到15秒的时间来生成它(没有格式化,它几乎是立即生成的)。我想我可以在用户第一次进入应用程序时生成列表,然后根据需要隐藏和取消隐藏列表,从而预先提高性能。但是,我想知道是否有更好的方法。也许是生成列表的更有效的方法 以下是发生减速的代码部分(在显示C和D之间): 正如你所看到的,这很简单。当“theToken”被格式化为HTML时,我得到了真正的性能提升。我能做些什么来解决这个问题Java 显示格式化为HTML的大型JLIST,java,html,jlist,Java,Html,Jlist,我有一个java小程序,其中必须显示大量项(字典条目)。用户需要能够选择列表中的单个项目,因此它被实现为JList。生成列表的速度非常快,直到我决定使用HTML格式化单个项目,使显示更加令人愉快。现在列表看起来很漂亮,但是每次用户访问字典时都需要10到15秒的时间来生成它(没有格式化,它几乎是立即生成的)。我想我可以在用户第一次进入应用程序时生成列表,然后根据需要隐藏和取消隐藏列表,从而预先提高性能。但是,我想知道是否有更好的方法。也许是生成列表的更有效的方法 以下是发生减速的代码部分(在显示C
谢谢,您使用的是哪种HTML格式?如果只是一些文本样式(字体、颜色),您可以使用
JLabel
,相应地设置其属性,并且对于JList
,上面的链接有点过时,因此这里有一些更新
简单地使用JTable可以极大地提高初始加载时的速度,但当您第一次开始滚动时会有点慢。还有一个新问题,行高需要调整。这可以通过实现TableCellRenderer
在自定义渲染器内部轻松完成,因为GetTableCellRenderComponent
方法允许您访问行、表和组件。但是,这将触发表的更新,该更新将调用相同的代码。如果您正确地编写代码,这将不会是一个问题。不过,最好还是把它放在别的地方。我向JViewport
添加了一个侦听器,只更新了当前视图中的行
或者,您可以使用编写一个ListCellRenderer
,它返回一个类似HTML的JPanel
。如果只需要一个JTextArea
,则需要设置其宽度,以确保正确设置其首选高度。同样,您必须更新行的宽度,根据JViewport
进行更新是有意义的
如果您对这两种方法的性能感到好奇,那么返回JPanel
的自定义渲染器比JLabel
s渲染HTML要快。这两种方法都相当快,尽管列表中有几千项。如前所述,当您开始滚动时,它们可能会有点慢
最后,这里有一些代码可以让您自己进行快速比较:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.Timer;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class JTableHtmlTest extends JFrame {
protected static final long serialVersionUID = 1L;
public static class Item {
public int id;
public String msg;
}
static class TableModel extends AbstractTableModel {
private static final long serialVersionUID = JListTest.serialVersionUID;
private Item[] items = new Item[] {};
public int getRowCount() {
return items.length;
}
public int getColumnCount() {
return 1;
}
public Object getValueAt(int rowIndex, int columnIndex) {
return items[rowIndex];
}
@Override
public String getColumnName(int column) {
return "";
}
public void updateItems() {
SwingWorker<Item[], Void> worker = new SwingWorker<Item[], Void>() {
@Override
protected Item[] doInBackground() throws Exception {
final Item[] tempList = new Item[3000];
for (int i = 0; i < tempList.length; i++) {
Item item = new Item();
item.id = (int) (Math.random() * 10000);
item.msg = "This is the default message that has to be"
+ " long enough to wrap around a few times so that"
+ " we know things are working. It's rather tedious to write.";
tempList[i] = item;
}
return tempList;
}
@Override
protected void done() {
try {
items = get();
fireTableDataChanged();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
worker.execute();
}
}
public static class TableRenderer implements TableCellRenderer {
private static final String strColor = "#EDF5F4";
private static final Color strideColor = Color.decode(strColor);
JLabel htmlLabel = new JLabel();
JPanel noHtmlPanel = new JPanel();
JLabel noHtmlLabel = new JLabel();
JTextArea noHTMLTextArea = new JTextArea();
Item toRender = null;
boolean useHtml = false;
public TableRenderer() {
noHTMLTextArea.setWrapStyleWord(false);
noHTMLTextArea.setLineWrap(true);
noHTMLTextArea.setOpaque(false);
Font defaultFont = noHtmlLabel.getFont();
Font boldFont = defaultFont.deriveFont(Font.BOLD);
noHtmlLabel.setFont(boldFont);
noHtmlLabel.setOpaque(false);
noHtmlPanel.setLayout(new BorderLayout());
noHtmlPanel.add(noHtmlLabel, BorderLayout.NORTH);
noHtmlPanel.add(noHTMLTextArea, BorderLayout.SOUTH);
}
public void setUseHtml(boolean useHtml) {
this.useHtml = useHtml;
}
public Component getJlabelRenderer(JTable table, Item value, int row) {
String colorString = "";
if (row % 2 == 0) {
colorString = "background-color:" + strColor + ";";
}
if (toRender != value) {
toRender = value;
htmlLabel.setText("<html><div style='padding:2px;" + "width:"
+ table.getWidth() + ";" + colorString
+ "color:black;'>"
+ "<div style='padding:2px;font-weight:500;'>"
+ "Item " + value.id + "</div>" + value.msg
+ "</div></html>");
}
return htmlLabel;
}
public Component getNoHtmlRenderer(JTable table, Item value, int row) {
if (toRender != value) {
toRender = value;
noHtmlLabel.setText("Item " + value.id);
noHTMLTextArea.setText(value.msg);
if (row % 2 == 0) {
noHtmlPanel.setBackground(strideColor);
noHtmlPanel.setOpaque(true);
} else {
noHtmlPanel.setOpaque(false);
}
}
return noHtmlPanel;
}
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
if (useHtml) {
return getJlabelRenderer(table, (Item) value, row);
} else {
return getNoHtmlRenderer(table, (Item) value, row);
}
}
}
public JTableHtmlTest() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel controlPanel = new JPanel();
JButton updaterControl = new JButton("Update 3000");
final JCheckBox useHtmlControl = new JCheckBox("Use HTML");
final TableModel model = new TableModel();
final JTable table = new JTable(model);
final TableRenderer renderer = new TableRenderer();
JScrollPane scrollPane = new JScrollPane(table);
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);
table.setDefaultRenderer(Object.class, renderer);
// Only update the JTable row heights when they are in view
final JViewport viewport = scrollPane.getViewport();
viewport.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
Rectangle viewRect = viewport.getViewRect();
int first = table.rowAtPoint(new Point(0, viewRect.y));
if (first == -1) {
return;
}
int last = table.rowAtPoint(new Point(0, viewRect.y
+ viewRect.height - 1));
if (last == -1) {
last = model.getRowCount() - 1;
}
int column = 0;
for (int row = first; row <= last; row++) {
Component comp = table.prepareRenderer(
table.getCellRenderer(row, column),
row, column);
int rowHeight = comp.getPreferredSize().height;
table.setRowHeight(row, rowHeight);
}
}
});
updaterControl.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
renderer.setUseHtml(useHtmlControl.isSelected());
model.updateItems();
}
});
Timer counter = new Timer();
counter.schedule(new TimerTask() {
@Override
public void run() {
String previousCounter = durationIndicator.getText();
final String newCounter = Integer.toString(Integer
.parseInt(previousCounter) + 1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
durationIndicator.setText(newCounter);
setTitle(newCounter);
}
});
}
}, 0, 100);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JTableHtmlTest jlt = new JTableHtmlTest();
jlt.pack();
jlt.setSize(300, 300);
jlt.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
import java.awt.*;
导入java.awt.event.*;
导入java.util.*;
导入java.util.Timer;
导入java.util.concurrent.ExecutionException;
导入javax.swing.*;
导入javax.swing.event.*;
导入javax.swing.table.*;
公共类JTableHtmlTest扩展了JFrame{
受保护的静态最终长serialVersionUID=1L;
公共静态类项{
公共int id;
公共字符串msg;
}
静态类TableModel扩展了AbstractTableModel{
私有静态最终长SerialVersionId=JListTest.SerialVersionId;
私有项[]项=新项[]{};
public int getRowCount(){
返回项目。长度;
}
public int getColumnCount(){
返回1;
}
公共对象getValueAt(int行索引、int列索引){
返回项目[行索引];
}
@凌驾
公共字符串getColumnName(int列){
返回“”;
}
公共void updateItems(){
SwingWorker worker=新SwingWorker(){
@凌驾
受保护项[]doInBackground()引发异常{
最终物品[]圣殿骑士=新物品[3000];
for(int i=0;iimport java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.Timer;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class JTableHtmlTest extends JFrame {
protected static final long serialVersionUID = 1L;
public static class Item {
public int id;
public String msg;
}
static class TableModel extends AbstractTableModel {
private static final long serialVersionUID = JListTest.serialVersionUID;
private Item[] items = new Item[] {};
public int getRowCount() {
return items.length;
}
public int getColumnCount() {
return 1;
}
public Object getValueAt(int rowIndex, int columnIndex) {
return items[rowIndex];
}
@Override
public String getColumnName(int column) {
return "";
}
public void updateItems() {
SwingWorker<Item[], Void> worker = new SwingWorker<Item[], Void>() {
@Override
protected Item[] doInBackground() throws Exception {
final Item[] tempList = new Item[3000];
for (int i = 0; i < tempList.length; i++) {
Item item = new Item();
item.id = (int) (Math.random() * 10000);
item.msg = "This is the default message that has to be"
+ " long enough to wrap around a few times so that"
+ " we know things are working. It's rather tedious to write.";
tempList[i] = item;
}
return tempList;
}
@Override
protected void done() {
try {
items = get();
fireTableDataChanged();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
worker.execute();
}
}
public static class TableRenderer implements TableCellRenderer {
private static final String strColor = "#EDF5F4";
private static final Color strideColor = Color.decode(strColor);
JLabel htmlLabel = new JLabel();
JPanel noHtmlPanel = new JPanel();
JLabel noHtmlLabel = new JLabel();
JTextArea noHTMLTextArea = new JTextArea();
Item toRender = null;
boolean useHtml = false;
public TableRenderer() {
noHTMLTextArea.setWrapStyleWord(false);
noHTMLTextArea.setLineWrap(true);
noHTMLTextArea.setOpaque(false);
Font defaultFont = noHtmlLabel.getFont();
Font boldFont = defaultFont.deriveFont(Font.BOLD);
noHtmlLabel.setFont(boldFont);
noHtmlLabel.setOpaque(false);
noHtmlPanel.setLayout(new BorderLayout());
noHtmlPanel.add(noHtmlLabel, BorderLayout.NORTH);
noHtmlPanel.add(noHTMLTextArea, BorderLayout.SOUTH);
}
public void setUseHtml(boolean useHtml) {
this.useHtml = useHtml;
}
public Component getJlabelRenderer(JTable table, Item value, int row) {
String colorString = "";
if (row % 2 == 0) {
colorString = "background-color:" + strColor + ";";
}
if (toRender != value) {
toRender = value;
htmlLabel.setText("<html><div style='padding:2px;" + "width:"
+ table.getWidth() + ";" + colorString
+ "color:black;'>"
+ "<div style='padding:2px;font-weight:500;'>"
+ "Item " + value.id + "</div>" + value.msg
+ "</div></html>");
}
return htmlLabel;
}
public Component getNoHtmlRenderer(JTable table, Item value, int row) {
if (toRender != value) {
toRender = value;
noHtmlLabel.setText("Item " + value.id);
noHTMLTextArea.setText(value.msg);
if (row % 2 == 0) {
noHtmlPanel.setBackground(strideColor);
noHtmlPanel.setOpaque(true);
} else {
noHtmlPanel.setOpaque(false);
}
}
return noHtmlPanel;
}
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
if (useHtml) {
return getJlabelRenderer(table, (Item) value, row);
} else {
return getNoHtmlRenderer(table, (Item) value, row);
}
}
}
public JTableHtmlTest() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel controlPanel = new JPanel();
JButton updaterControl = new JButton("Update 3000");
final JCheckBox useHtmlControl = new JCheckBox("Use HTML");
final TableModel model = new TableModel();
final JTable table = new JTable(model);
final TableRenderer renderer = new TableRenderer();
JScrollPane scrollPane = new JScrollPane(table);
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);
table.setDefaultRenderer(Object.class, renderer);
// Only update the JTable row heights when they are in view
final JViewport viewport = scrollPane.getViewport();
viewport.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
Rectangle viewRect = viewport.getViewRect();
int first = table.rowAtPoint(new Point(0, viewRect.y));
if (first == -1) {
return;
}
int last = table.rowAtPoint(new Point(0, viewRect.y
+ viewRect.height - 1));
if (last == -1) {
last = model.getRowCount() - 1;
}
int column = 0;
for (int row = first; row <= last; row++) {
Component comp = table.prepareRenderer(
table.getCellRenderer(row, column),
row, column);
int rowHeight = comp.getPreferredSize().height;
table.setRowHeight(row, rowHeight);
}
}
});
updaterControl.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
renderer.setUseHtml(useHtmlControl.isSelected());
model.updateItems();
}
});
Timer counter = new Timer();
counter.schedule(new TimerTask() {
@Override
public void run() {
String previousCounter = durationIndicator.getText();
final String newCounter = Integer.toString(Integer
.parseInt(previousCounter) + 1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
durationIndicator.setText(newCounter);
setTitle(newCounter);
}
});
}
}, 0, 100);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JTableHtmlTest jlt = new JTableHtmlTest();
jlt.pack();
jlt.setSize(300, 300);
jlt.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}