JTable中的换行,右对齐,自动调整行高
Posted
技术标签:
【中文标题】JTable中的换行,右对齐,自动调整行高【英文标题】:Wrapping Line, Right Align,Auto Resize Row Height In JTable 【发布时间】:2019-01-19 06:00:45 【问题描述】:我编写了一个 Java 应用程序,我需要一个具有一些特性的 JTable
类对象:
-
自动包装线
右对齐
自动调整行高(这意味着例如一行的大小为 25,但表中另一行的大小为 50,内容大小为一行)
渲染速度必须高
但是我的代码运行速度不快并且没有完全的***功能,我在最后一个问题中编写了我的应用程序的最小版本:
这是我的 gui 类:
import javax.swing.*;
import java.awt.*;
public class GUI extends JFrame
private BankTable table;
private JScrollPane scrollPane;
public GUI()
super("Bank Table");
JPanel contentPanel = new JPanel();
setContentPane(contentPanel);
contentPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
setLayout(new BorderLayout());
setMinimumSize(new Dimension(1000,700));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
makeTable();
scrollPane = new JScrollPane(table);
scrollPane.getVerticalScrollBar().setUnitIncrement(50);
add(scrollPane,BorderLayout.CENTER);
setVisible(true);
public void makeTable()
String[][]data= new String[][]"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/01",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/02",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/03",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/04",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/05",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/06",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/07",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/08",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/09",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/10",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/11",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/12",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/13",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/14",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/15",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/16",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/17",
"0212670003009", "ص 318", "77081111111111111111111111111111111111634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/18",
"0212670003009", "ص 318", "77081222222222222222222222222222634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/19",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/20",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/21",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/22",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/23",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/24",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/25",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/26",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/27",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/28",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/29",
"0212670003009", "ص 318", "77081634","38000000","0","331142","2102","وصول چک","08:56:46","1397/05/30";
String[] columns= new String[]"شماره حساب", "اطلاعات اضافه", "مانده","واریز","برداشت","فیش/ حواله","کد شعبه","شرح","ساعت","تاریخ";
table = new BankTable(data,columns);
table.updateRowHeights();
System.out.println("Table");
public static void main(String args[])
GUI gui = new GUI();
这是表格的渲染:
import java.awt.*;
import javax.swing.*;
import javax.swing.table.TableCellRenderer;
public class TextAreaRenderer extends JTextArea
implements TableCellRenderer
public TextAreaRenderer()
setLineWrap(true);
setWrapStyleWord(true);
setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
setEditable(false);
setCursor(null);
setOpaque(false);
setFocusable(false);
setLineWrap(true);
setWrapStyleWord(true);
public Component getTableCellRendererComponent(JTable jTable,
Object obj, boolean isSelected, boolean hasFocus, int row,
int column)
setText((String)obj);
setFont(new Font("bnazanin", Font.BOLD, 15));
return this;
这是表类:
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
public class BankTable extends JTable
public BankTable(String[][] data,String[] columns)
super(data,columns);
setForeground(Color.BLACK);
setBounds(60,80,400,600);
changeTableHeader();
DefaultTableCellRenderer rightRenderer = new DefaultTableCellRenderer();
rightRenderer.setHorizontalAlignment(JLabel.RIGHT);
TextAreaRenderer textAreaRenderer = new TextAreaRenderer();
for(int i=0 ; i<columns.length ; i++)
getColumnModel().getColumn(i).setCellRenderer(textAreaRenderer);
public void changeTableHeader()
getTableHeader().setBackground(new Color(57,77,112));
getTableHeader().setForeground(Color.WHITE);
getTableHeader().setFont(new Font("Calibri Light", Font.BOLD, 20));
@Override
public boolean isCellEditable(int i, int i1)
return false;
public void updateRowHeights()
for (int row = 0; row < getRowCount(); row++)
int rowHeight = getRowHeight();
for (int column = 0; column < getColumnCount(); column++)
Component comp = prepareRenderer(getCellRenderer(row, column), row, column);
rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
setRowHeight(row, rowHeight + 20);
编辑: This is a simple for my table
【问题讨论】:
"Autowrapper" - Java-Swing adding multiple lines in jtable's cell “右对齐” -JLabel#setHorizontalAlignment
“自动调整行高” - Vertical and Horizontal Allignment in JTextPane
我的代码具有自动换行单元格,但是我之前使用过此代码,但渲染速度在两个代码中都没有解决。 @MadProgrammer
“渲染速度必须很高” - 好吧,这将是一个问题,因为对于每一行,您需要计算每列的高度并确定高度行需要。这应该谨慎进行,并且仅在您绝对需要时才进行 - 例如当模型更改或模型本身更改或 JTable
无效时。然后,您将需要缓存结果,以便将来可以快速完成任何渲染
【参考方案1】:
因为这里有价值的是一些旧代码。
它使用带换行的 JTextArea,但将文本区域中的行限制为 2 行。然后您可以滚动文本区域以查看其他行。
也许这种方法有助于满足您的要求?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class TableTextArea extends JFrame
public TableTextArea()
JTable table = new JTable(40, 5);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
table.setRowHeight(40);
table.setValueAt("one two three four five six seven eight nine ten", 0, 2);
table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 1, 2);
table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 0, 4);
table.setValueAt("one two three four five six seven eight nine ten", 2, 2);
table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 3, 2);
table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 4, 4);
table.setValueAt("one two three four five six seven eight nine ten", 5, 2);
table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 6, 2);
table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 7, 4);
table.setValueAt("one two three four five six seven eight nine ten", 8, 2);
table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 9, 2);
table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 10, 4);
table.setValueAt("one two three four five six seven eight nine ten", 11, 2);
table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 12, 2);
table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 13, 4);
table.setValueAt("one two three four five six seven eight nine ten", 14, 2);
table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 15, 2);
table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 16, 4);
table.setValueAt("one two three four five six seven eight nine ten", 17, 2);
table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 18, 2);
table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 19, 4);
table.setValueAt("one two three four five six seven eight nine ten", 20, 2);
table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 21, 2);
table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 22, 4);
table.setValueAt("one two three four five six seven eight nine ten", 23, 2);
table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 24, 2);
table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 25, 4);
table.setValueAt("one two three four five six seven eight nine ten", 26, 2);
table.setValueAt("aaa bbb ccccc dddd eeee fff ggggg hhhhh iiii jjj", 27, 2);
table.setValueAt("1111 2222 3333 4444 5555 6666 7777 8888 9999 0000", 28, 4);
JScrollPane scrollPane = new JScrollPane( table );
add( scrollPane );
// Override default renderer for a specific column
TableCellRenderer renderer = new TextAreaRenderer();
table.getColumnModel().getColumn(2).setCellRenderer( renderer );
table.getColumnModel().getColumn(4).setCellRenderer( renderer );
table.changeSelection(0, 0, false, false);
public static void main(String[] args)
SwingUtilities.invokeLater(new Runnable()
public void run()
TableTextArea frame = new TableTextArea();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
);
/*
**
*/
class TextAreaRenderer implements TableCellRenderer
private JTextArea renderTextArea;
private JScrollPane renderScrollPane;
private JTextArea focusTextArea;
private JScrollPane focusScrollPane;
private boolean firstTime = true;
public TextAreaRenderer()
renderTextArea = new JTextArea();
renderTextArea.setEditable( false );
renderTextArea.setLineWrap( true );
renderTextArea.setWrapStyleWord( true );
renderScrollPane = new JScrollPane( renderTextArea );
renderScrollPane.setBorder(null);
renderScrollPane.revalidate();
focusTextArea = new JTextArea();
focusTextArea.setEditable( false );
focusTextArea.setLineWrap( true );
focusTextArea.setWrapStyleWord( true );
focusScrollPane = new JScrollPane( focusTextArea );
focusScrollPane.setBorder(null);
public Component getTableCellRendererComponent(
final JTable table, Object value, boolean isSelected, boolean hasFocus, final int row, final int column)
// For some reason the scrollbars don't appear on the first cell renderered.
// Forcing a repaint of the cell seems to fix the problem.
if (firstTime)
firstTime = false;
Rectangle cellRectangle = table.getCellRect(row, column, false);
// renderScrollPane.setBounds(cellRectangle);
// table.add(renderScrollPane);
// renderScrollPane.revalidate();
table.repaint(cellRectangle);
System.out.println(row + " :: " + column + " : " + hasFocus);
table.remove(focusScrollPane);
renderTextArea.setText( value != null ? value.toString() : "" );
renderTextArea.setCaretPosition(0);
if (hasFocus)
renderTextArea.setBackground( table.getSelectionBackground() );
SwingUtilities.invokeLater( new Runnable()
public void run()
addRealTextAreaToTable(table, row, column);
);
else if (isSelected)
renderTextArea.setBackground( table.getSelectionBackground() );
else
renderTextArea.setBackground( table.getBackground() );
return renderScrollPane;
private void addRealTextAreaToTable(JTable table, int row, int column)
System.out.println(row + " :: " + column);
Object value = table.getValueAt(row, column);
focusTextArea.setText( value != null ? value.toString() : "" );
focusTextArea.setCaretPosition(0);
// focusTextArea.setBackground( table.getBackground() );
focusTextArea.setBackground( table.getSelectionBackground() );
Rectangle cellRectangle = table.getCellRect(row, column, false);
focusScrollPane.setBounds(cellRectangle);
table.add(focusScrollPane);
focusScrollPane.revalidate();
focusTextArea.requestFocusInWindow();
【讨论】:
值得尝试,但这段代码很糟糕,因为我希望行的大小自动更改不,就像您的代码在某些单元格中有滚动一样。请看一下我现在上传到问题的简单表格【参考方案2】:所以,我花了一些时间来反对这个尝试不同的真实性。
以TextAreaRenderer
开头。我更喜欢使用DefaultTableCelllRenderer
,但在玩弄了它之后,我无法让它令人满意地工作。因此,相反,我采用了它自己的大部分优化并将它们应用于TextAreaRenderer
本身。
您真正想做的一件事是减少每个getTableCellRendererComponent
将进行的更改量。 JTextArea
已经是一个复杂的组件了。
我删除了setOpaque
调用并将setFont
调用移至构造函数。我还添加了选择支持(这是我测试的一部分)
public class TextAreaRenderer extends JTextArea
implements TableCellRenderer
public TextAreaRenderer()
setLineWrap(true);
setWrapStyleWord(true);
setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
setEditable(false);
setCursor(null);
//setOpaque(false);
setFocusable(false);
setLineWrap(true);
setWrapStyleWord(true);
setFont(new Font("bnazanin", Font.BOLD, 15));
getCaret().setBlinkRate(0);
public Component getTableCellRendererComponent(JTable jTable,
Object obj, boolean isSelected, boolean hasFocus, int row,
int column)
setText((String) obj);
if (isSelected)
System.out.println("!!Selected");
setBackground(jTable.getSelectionBackground());
setForeground(jTable.getSelectionForeground());
else
setBackground(jTable.getBackground());
setForeground(jTable.getForeground());
return this;
/**
* Overridden for performance reasons. See the
* <a href="#override">Implementation Note</a>
* for more information.
*/
public boolean isOpaque()
Color back = getBackground();
Component p = getParent();
if (p != null)
p = p.getParent();
// p should now be the JTable.
boolean colorMatch = (back != null) && (p != null)
&& back.equals(p.getBackground())
&& p.isOpaque();
return !colorMatch && super.isOpaque();
/**
* Overridden for performance reasons. See the
* <a href="#override">Implementation Note</a>
* for more information.
*
* @since 1.5
*/
public void invalidate()
/**
* Overridden for performance reasons. See the
* <a href="#override">Implementation Note</a>
* for more information.
*/
public void validate()
/**
* Overridden for performance reasons. See the
* <a href="#override">Implementation Note</a>
* for more information.
*/
public void revalidate()
/**
* Overridden for performance reasons. See the
* <a href="#override">Implementation Note</a>
* for more information.
*/
public void repaint(long tm, int x, int y, int width, int height)
/**
* Overridden for performance reasons. See the
* <a href="#override">Implementation Note</a>
* for more information.
*/
public void repaint(Rectangle r)
/**
* Overridden for performance reasons. See the
* <a href="#override">Implementation Note</a>
* for more information.
*
* @since 1.5
*/
public void repaint()
/**
* Overridden for performance reasons. See the
* <a href="#override">Implementation Note</a>
* for more information.
*/
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue)
然后我攻击了BlankTable
...
其中一个重大变化是表格现在能够动态计算行的高度。因为计算开销很大,所以这个操作的结果被缓存了。不过,问题是JTable
也有它自己的内部缓存......这是私有的?......所以与其追踪反射路线,我们需要提供一些补偿来规避这个 API 的一些副作用创建。
当调用 setRowHeight
时,JTable
调用 invalidate
和 repaint
本身。当我们执行我们的计算时,我们希望停止它,但是在某些情况下我们仍然应该允许工作(例如当列被调整大小并且JTable
是invalidated
)
public class BankTable extends JTable
public BankTable(String[][] data, String[] columns)
super(data, columns);
changeTableHeader();
setGridColor(Color.RED);
TableCellRenderer textAreaRenderer = new TextAreaRenderer();
for (int i = 0; i < columns.length; i++)
getColumnModel().getColumn(i).setCellRenderer(textAreaRenderer);
public void changeTableHeader()
getTableHeader().setBackground(new Color(57, 77, 112));
getTableHeader().setForeground(Color.WHITE);
getTableHeader().setFont(new Font("Calibri Light", Font.BOLD, 20));
@Override
public boolean isCellEditable(int i, int i1)
return false;
private Map<Integer, Integer> rowMap = new HashMap<>();
private boolean quietUpdate = false;
private boolean forceUpdate = false;
@Override
public void invalidate()
rowMap.clear();
forceUpdate = true;
super.invalidate();
forceUpdate = false;
@Override
protected void resizeAndRepaint()
if (quietUpdate)
if (forceUpdate)
super.resizeAndRepaint();
else
super.resizeAndRepaint();
@Override
public int getRowHeight(int row)
Integer rowHeight = rowMap.get(row);
if (rowHeight == null)
TableColumnModel model = getColumnModel();
rowHeight = getRowHeight();
for (int column = 0; column < getColumnCount(); column++)
int colWidth = model.getColumn(column).getWidth();
Component comp = prepareRenderer(getCellRenderer(row, column), row, column);
comp.setSize(new Dimension(colWidth, Integer.MAX_VALUE));
rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
rowMap.put(row, rowHeight);
quietUpdate = true;
setRowHeight(row, rowHeight);
quietUpdate = false;
return rowHeight;
@Override
public void tableChanged(TableModelEvent e)
if (rowMap == null)
super.tableChanged(e);
return;
if (e == null || e.getFirstRow() == TableModelEvent.HEADER_ROW)
rowMap.clear();
super.tableChanged(e);
return;
if (e.getType() == TableModelEvent.INSERT)
super.tableChanged(e);
return;
int modelColumn = e.getColumn();
int start = e.getFirstRow();
int end = e.getLastRow();
if (e.getType() == TableModelEvent.DELETE || e.getType() == TableModelEvent.UPDATE)
for (int row = start; row <= end; row++)
rowMap.remove(row);
super.tableChanged(e);
return;
if (end == Integer.MAX_VALUE)
rowMap.clear();
super.tableChanged(e); //To change body of generated methods, choose Tools | Templates.
还有一些其他方面可能需要进一步优化(我没有测试排序表,所以 tableChanged
需要更新,我也没有测试单元格的更改)
在初始加载后,我发现渲染是合理的。由于使用中的组件、字体等系统问题,你的里程可能还算公平。
【讨论】:
此表具有我需要的所有功能,但现在渲染速度非常低。所以问题没有解决。但是底部链接中有许多更改的答案代码运行得很好......但是JTable本身不适合复杂使用***.com/questions/51797852/… 天啊,对我来说,渲染效果比你原来的改进了很多——不知道你在做什么 我测试了您的代码,但有所改进,但渲染速度仍然很慢。 我不确定与什么相比。一般来说,我的测试速度在一个合理的水平上,不会比我通常体验的多或少——尽管解决方案比我需要做的大多数事情更复杂——只要你只是滚动,事情就会在短时间内变得混乱调整表/列的大小,但(对我来说)是需要重新计算行高的预期开销。文本布局已经是一个复杂的过程。我会考虑尝试降低整体解决方案的复杂性,并以较小的增量重新引入它们,以查看某些问题可能出现的位置 好的。反正坦克。但我需要更快的速度...... :)以上是关于JTable中的换行,右对齐,自动调整行高的主要内容,如果未能解决你的问题,请参考以下文章