Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The links above are a bit out of date so here's something more up to date.</p> <p>Simply using JTable is a huge improvement in speed on initial load but a little slow when you first start scrolling. And you have the new problem that the row height needs adjusting. This can be done inside of a custom renderer easy enough by implementing <code>TableCellRenderer</code> since the <code>getTableCellRendererComponent</code> method gives you access to the row, the table and the component. This will however fire a update of the table which will call the same code. If you code appropriately, this won't be a problem. Still, it's better practice to put it somewhere else. I added a listener to the <code>JViewport</code> and only updated the rows that are currently in view. <a href="https://stackoverflow.com/questions/8195959/swing-jtable-event-when-row-is-visible-or-when-scrolled-to-the-bottom/8196061#8196061">The code I based this on is here</a></p> <p>Alternatively, you can use write a <code>ListCellRenderer</code> that returns a <code>JPanel</code> that looks like the HTML. If you only need a <code>JTextArea</code> then you'll need to set its width to ensure it's preferred height is set correctly <a href="https://stackoverflow.com/questions/965023/how-to-wrap-lines-in-a-jtable-cell/20812845#20812845">like in this answer</a>. Again, you have to update the row's width and it makes sense to do this based on the <code>JViewport</code>.</p> <p>If you're curious about the performance of both approaches, then a custom renderer returning a <code>JPanel</code> is faster than <code>JLabel</code>s rendering HTML. Both are reasonably quick though even with lists with a few thousand items. As mentioned, they can be a little slow when you initially scroll.</p> <p>Finally, here's some code that lets you make a quick comparison yourself:</p> <pre><code>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&lt;Item[], Void&gt; worker = new SwingWorker&lt;Item[], Void&gt;() { @Override protected Item[] doInBackground() throws Exception { final Item[] tempList = new Item[3000]; for (int i = 0; i &lt; 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("&lt;html&gt;&lt;div style='padding:2px;" + "width:" + table.getWidth() + ";" + colorString + "color:black;'&gt;" + "&lt;div style='padding:2px;font-weight:500;'&gt;" + "Item " + value.id + "&lt;/div&gt;" + value.msg + "&lt;/div&gt;&lt;/html&gt;"); } 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 &lt;= 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(); } } }); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload