Les liens ci-dessus sont un peu obsolètes donc voici quelque chose de plus à jour. Le simple fait d'utiliser JTable est une amélioration considérable de la vitesse de chargement initiale, mais un peu lent lorsque vous commencez à défiler. Et vous avez le nouveau problème que la hauteur de ligne doit ajuster. Cela peut être fait à l'intérieur d'un moteur de rendu personnalisé assez facilement en mettant en œuvre TableCellRenderer
puisque la méthode getTableCellRendererComponent
vous donne accès à la ligne, la table et le composant. Cela entraînera cependant une mise à jour de la table qui appellera le même code. Si vous codez correctement, ce ne sera pas un problème. Pourtant, il est préférable de le mettre ailleurs. J'ai ajouté un écouteur au JViewport
et seulement mis à jour les lignes qui sont actuellement en vue. Vous pouvez également écrire un ListCellRenderer
qui renvoie un JPanel
qui ressemble à du code HTML. Si vous avez seulement besoin d'un JTextArea
, vous devez définir sa largeur pour vous assurer que sa hauteur préférée est correctement définie like in this answer. Encore une fois, vous devez mettre à jour la largeur de la ligne et il est logique de le faire en fonction du JViewport
.
Si vous êtes intéressé par les performances des deux approches, un rendu personnalisé renvoyant un JPanel
est plus rapide que JLabel
s rendu HTML. Les deux sont raisonnablement rapides mais même avec des listes avec quelques milliers d'articles. Comme mentionné, ils peuvent être un peu lent lorsque vous faites défiler initialement.
Enfin, voici un code qui vous permet de faire une comparaison rapide vous:
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();
}
}
});
}
}
Je vois où vous voulez en venir, mais je besoin de quelque chose qui va me permettre d'afficher une entrée multiple ligne. Voici une entrée formatée typique:
@Elliott: vous pouvez utiliser un composant personnalisé (ou même simplement un LabelUI personnalisé: http://codeguru.earthweb.com/java/articles/198.shtml) pour rendre un texte multiligne tout en évitant l'analyse HTML (je profilerais d'abord pour confirmer si c'est effectivement le goulot d'étranglement). Alternativement, vous pouvez essayer d'utiliser une JTable à une seule colonne au lieu d'une JList; IIRC JTable est conçu pour de grandes quantités de données beaucoup plus que JList et ne restitue que les éléments réellement visibles. –
J'ai terminé en utilisant un composant JTextArea pour afficher le texte. Il a fait l'affaire. La suggestion ListCellRenderer m'a cependant orienté dans la bonne direction. J'ai utilisé l'exemple de code suivant pour m'aider à passer ceci: http://forums.sun.com/thread.jspa?threadID=552711 – Elliott