Basically I have a JTable, and this JTabel will have a product in one cell, and then in the cell directly below it the cost.
The product name should be aligned to the left.
The product cost should be aligned to the right.
I don't actually care what the alignment of other cells in each row is.
So I need to set the alignment of either individual cells, or individual rows. I've found ways to set the alignment of the table, and ways to set the alignment of the columns, but never the rows/individual cells.
sscce:
public class Main extends JFrame{
public static void main(String args[]){
new Main();
}
public Main(){
super("Demo");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setExtendedState(MAXIMIZED_BOTH);
setVisible(true);
setLayout(new BorderLayout());
TableModel dataModel = new AbstractTableModel() {
Object rows[] = new Object[50];
public int getColumnCount(){return 1;}
public int getRowCount(){return rows.length;}
public Object getValueAt(int row, int col){
return rows[row];
}
public boolean isCellEditable(int row, int col){
return false;
}
public void setValueAt(Object value, int row, int col) {
rows[row] = value;
fireTableCellUpdated(row,0);
}
};
JTable receipt = new JTable(dataModel);
receipt.setBorder(BorderFactory.createEtchedBorder());
receipt.setShowGrid(false);
add(receipt,BorderLayout.CENTER);
for(int i = 0; i < 10; i+=2){
receipt.setValueAt("ProductNameHere",i,0);
receipt.setValueAt("Cost",i+1,0);
}
validate();
repaint();
}
}
The default renderer for Number is a right aligned label. In this example, no special renderer is required to right align INT_COL, which is labeled Index and has type Integer.class.
If this is not helpful, please edit your question to include an sscce that shows your current approach and your cost data type.
Addendum: Alternatively, override prepareRender(), as shown here.
JTable receipt = new JTable(dataModel) {
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {
JLabel c = (JLabel) super.prepareRenderer(renderer, row, col);
if (row % 2 == 0) {
c.setHorizontalAlignment(JLabel.LEFT);
} else {
c.setHorizontalAlignment(JLabel.RIGHT);
}
return c;
}
};
SSCCE:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
public class Main extends JFrame {
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Main();
}
});
}
public Main() {
super("Demo");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableModel dataModel = new AbstractTableModel() {
Object rows[] = new Object[10];
#Override
public int getColumnCount() {
return 1;
}
#Override
public int getRowCount() {
return rows.length;
}
#Override
public Object getValueAt(int row, int col) {
return rows[row];
}
#Override
public boolean isCellEditable(int row, int col) {
return false;
}
#Override
public void setValueAt(Object value, int row, int col) {
rows[row] = value;
fireTableCellUpdated(row, 0);
}
};
JTable receipt = new JTable(dataModel) {
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {
JLabel c = (JLabel) super.prepareRenderer(renderer, row, col);
if (row % 2 == 0) {
c.setHorizontalAlignment(JLabel.LEFT);
} else {
c.setHorizontalAlignment(JLabel.RIGHT);
}
return c;
}
};
receipt.setBorder(BorderFactory.createEtchedBorder());
receipt.setShowGrid(false);
add(receipt, BorderLayout.CENTER);
for (int i = 0; i < 10; i += 2) {
receipt.setValueAt("ProductNameHere", i, 0);
receipt.setValueAt(Integer.valueOf(i + 1), i + 1, 0);
}
pack();
setLocationByPlatform(true);
setVisible(true);
}
}
Related
I have written a renderer and my program does not color the cell and I don't know why. When I try to color the whole row it also colors only 3 of the 7 rows. Can someone please help me?
public void isLow(JTable jTableBestandstabelle) {
jTableBestandstabelle.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
#Override
public Component getTableCellRendererComponent(
JTable aTable, Object aNumberValue, boolean aIsSelected,
boolean aHasFocus, int aRow, int aColumn
) {
if (aNumberValue == null) {
return this;
}
Component renderer = super.getTableCellRendererComponent(
aTable, aNumberValue, aIsSelected, aHasFocus, aRow, aColumn
);
int m = (int) jTableBestandstabelle.getValueAt(aRow, 4);
int a = (int) jTableBestandstabelle.getValueAt(aRow, 5);
if (a < m && column == 5) {
renderer.setForeground(Color.black);
renderer.setBackground(Color.red);
} else {
renderer.setForeground(Color.black);
}
return this;
}
});
}
public void isLow(JTable jTableBestandstabelle) {
jTableBestandstabelle.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
#Override
public Component getTableCellRendererComponent(
JTable aTable, Object aNumberValue, boolean aIsSelected,
boolean aHasFocus, int aRow, int aColumn
) {
if (aNumberValue == null) {
return this;
}
Component renderer = super.getTableCellRendererComponent(
aTable, aNumberValue, aIsSelected, aHasFocus, aRow, aColumn
);
int m = (int) jTableBestandstabelle.getValueAt(aRow, 4);
int a = (int) jTableBestandstabelle.getValueAt(aRow, 5);
if (a < m) {
renderer.setForeground(Color.black);
renderer.setBackground(Color.red);
} else {
renderer.setForeground(Color.black);
}
return this;
}
});
}
You have two problem in your code:
You use a boolean columns in your table (last column). So if you want to present a checkbox in the column you cannot use a DefaultTableCellRenderer
When you use table.setDefaultRenderer(Object.class, renderer) this will not work for some primitive tapes like Boolean.class or Integer.class (don't know why). So you need to set the renderer for these classes too (table.setDefaultRenderer(Integer.class, renderer) and table.setDefaultRenderer(Boolean.class, renderer)). But due to the point 1 its not a good idea.
Here is mine solution:
import java.awt.Color;
import java.awt.Component;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
/**
* <code>TestTable</code>.
*/
public class TestTable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new TestTable()::startUp);
}
private void startUp() {
DefaultTableModel model = new DefaultTableModel(0, 7) {
#Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == 6) {
return Boolean.class; // last column is boolean
} else if (columnIndex == 0 && columnIndex > 3) {
return Integer.class; // 1, 4, 5 are integers
}
return super.getColumnClass(columnIndex);
}
};
model.addRow(new Object[] {1, "Test1", "Test2", "Test3", 6, 5, false});
model.addRow(new Object[] {1, "Test11", "Test22", "Test33", 4, 5, true});
JTable table = new JTable(model);
for (int i = 0; i < table.getColumnCount(); i++) {
TableColumn col = table.getColumnModel().getColumn(i);
int modelCol = table.convertColumnIndexToModel(i);
col.setCellRenderer(new MyCellRenderer(table.getDefaultRenderer(model.getColumnClass(modelCol))));
}
JFrame frm = new JFrame("Table test");
frm.add(new JScrollPane(table));
frm.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frm.pack();
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
private static class MyCellRenderer implements TableCellRenderer {
private final TableCellRenderer origin;
public MyCellRenderer(TableCellRenderer origin) {
this.origin = origin;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
Component c = origin.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
int m = (int) table.getValueAt(row, 4);
int a = (int) table.getValueAt(row, 5);
if (a < m) {
c.setForeground(Color.black);
c.setBackground(Color.red);
} else {
c.setForeground(Color.black);
c.setBackground(Color.white);
}
return c;
}
}
}
Below I provide my replicable code. The problem is that it fills all cells with the gray color. However, I just need to make a gray-colored cell "moving" from column 0 to the last column (for the row 0).
Moreover, how to create more than one cell "moving" in a queue?
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.table.DefaultTableCellRenderer;
public class test2 {
/**
* #param args
*/
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
gtest t= new gtest("TEST");
f.pack();
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
}
}
class gtest extends JFrame
{
private static JTable table;
private int index;
public gtest(String title)
{
table = new JTable(6, 10);
table.setDefaultRenderer(Object.class, new PaintCell());
add(table);
startAnimation();
}
private void startAnimation() {
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
index++;
if (index > table.getRowCount() * table.getColumnCount())
index = 0;
table.repaint();
}
});
//timer.setRepeats(true);
timer.start();
}
class PaintCell extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
Component cell = super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
int id = row * table.getRowCount() + column;
cell.setBackground(id < index ? Color.LIGHT_GRAY : null);
return cell;
}
}
}
Change...
int id = row * table.getRowCount() + column;
cell.setBackground(id < index ? Color.LIGHT_GRAY : null);
To...
int checkRow = index / table.getColumnCount();
int checkCol = index % table.getColumnCount();
cell.setBackground(checkRow == row && checkCol == column ? Color.LIGHT_GRAY : null);
This will calculate the row and column based on the current value of index and the compare to the cells row/column of the cell renderer
I have a JTable and everytime I select a cell, I want to print its row and column index. I use getSelectedRow() and getSelectedColumn() methods for that reason. Running the code below:
Class TestTimeTable
public class TestTimeTable extends JFrame{
private final int rows = 10;
private final int cols = 8;
private final String daysOfTheWeek[] = {"MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"};
private final JPanel jTablePanel;
private final JScrollPane scrollPane;
private final JTable timeTable;
private final Object[][] rowData;
public TestTimeTable(){
this.rowData = new Object[this.rows][this.cols];
this.timeTable = new JTable(this.rowData,this.daysOfTheWeek){
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
this.timeTable.setRowHeight(200, 200);
this.timeTable.setFillsViewportHeight(true);
this.timeTable.setOpaque(true);
this.timeTable.setColumnSelectionAllowed(true);
this.timeTable.setRowSelectionAllowed(true);
this.timeTable.setCellSelectionEnabled(true);
this.timeTable.setDefaultRenderer(Object.class, new BoardTableCellRenderer());
this.scrollPane = new JScrollPane(this.timeTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.jTablePanel = new JPanel();
this.jTablePanel.add(this.scrollPane);
getContentPane().add(new JScrollPane(this.timeTable), BorderLayout.CENTER);
}
public int getColumn(){
return this.timeTable.getSelectedColumn();
}
public int getRow(){
return this.timeTable.getSelectedRow();
}
public JTable getTimeTable(){
return this.timeTable;
}
public void createAndShowUI(){
setSize(600, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] argas){
TestTimeTable tt = new TestTimeTable();
tt.createAndShowGUI();
}
}
Class BoardTableCellRenderer
class BoardTableCellRenderer extends DefaultTableCellRenderer {
Component c;
private static final long serialVersionUID = 1L;
private final Color selectionBlue = new Color(131,166,198);
private final MatteBorder border = new MatteBorder(1, 1, 0, 0, Color.BLACK);
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (table.isCellSelected(row, column)){
c.setBackground(this.selectionBlue);
setBorder(this.border);
} else {
c.setBackground(Color.WHITE);
}
if(isSelected){
JOptionPane.showMessageDialog(null, table.getSelectedRow() + ""+table.getSelectedColumn(),null, JOptionPane.INFORMATION_MESSAGE);
}
return c;
}
}
Everytime I select a cell, the JOptionPane frame appears and then the app freezes. So I have to interrupt it all the time. Could somebody please tell me why is this happening? What could I do to fix it?
use, override boolean isSelected, boolean hasFocus (built_in methods) from getTableCellRendererComponent instead of referencing back to JTable - table.isCellSelected(row, column), ba reseting Color for rest of cells in else statement, e.g. simple torso
.
private class StatusRenderer implements TableCellRenderer {
private static final long serialVersionUID = 1L;
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setBackground(table.getSelectionBackground());
} else {
setBackground(table.getBackground());
}
return this;
}
}
change ListSelectionMode for JTable
remove every this.Xxx, are useless
don't to setSize, use JFrame.pack() instead and/or set size for JScrollPane e.g. table.setPreferredScrollableViewportSize(table.getPreferredSize());(for reasonable numbers or rows and columns, otherwise use Dimension(x, x))
EDIT
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.UIResource;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
public class TableRolloverDemo {
private JFrame frame = new JFrame("TableRolloverDemo");
private JTable table = new JTable();
private String[] columnNames = new String[]{"Column"};
private Object[][] data = new Object[][]{{false}, {false}, {true}, {true},
{false}, {false}, {true}, {true}, {false}, {false}, {true}, {true}};
public TableRolloverDemo() {
final DefaultTableModel model = new DefaultTableModel(data, columnNames) {
//private boolean ImInLoop = false;
#Override
public Class<?> getColumnClass(int columnIndex) {
return Boolean.class;
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
if (columnIndex == 0) {
return true;
} else {
return false;
}
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 0) {
//if (!ImInLoop) {
// ImInLoop = true;
Boolean bol = (Boolean) aValue;
super.setValueAt(aValue, rowIndex, columnIndex);
for (int i = 0; i < this.getRowCount(); i++) {
if (i != rowIndex) {
super.setValueAt(!bol, i, columnIndex);
}
}
// ImInLoop = false;
//}
} else {
super.setValueAt(aValue, rowIndex, columnIndex);
}
}
};
RolloverMouseAdapter rolloverAdapter = new RolloverMouseAdapter(table);
RolloverBooleanRenderer renderer = new RolloverBooleanRenderer(rolloverAdapter);
table.addMouseListener(rolloverAdapter);
table.addMouseMotionListener(rolloverAdapter);
table.setDefaultRenderer(Boolean.class, renderer);
table.setModel(model);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private class RolloverMouseAdapter extends MouseAdapter {
private int row = -1;
private int column = -1;
private JTable table;
public RolloverMouseAdapter(JTable table) {
this.table = table;
}
public boolean isRolloverCell(int row, int column) {
return this.row == row && this.column == column;
}
#Override
public void mouseMoved(MouseEvent e) {
int lastRow = row;
int lastColumn = column;
row = table.rowAtPoint(e.getPoint());
column = table.columnAtPoint(e.getPoint());
if (row == lastRow && column == lastColumn) {
return;
}
if (row >= 0 && column >= 0) {
table.repaint(table.getCellRect(row, column, false));
}
if (lastRow >= 0 && lastColumn >= 0) {
table.repaint(table.getCellRect(lastRow, lastColumn, false));
}
}
#Override
public void mouseExited(MouseEvent e) {
if (row >= 0 && column >= 0) {
table.repaint(table.getCellRect(row, column, false));
}
row = column = -1;
}
}
private class RolloverBooleanRenderer extends JCheckBox implements
TableCellRenderer, UIResource {
private final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
private RolloverMouseAdapter adapter;
public RolloverBooleanRenderer(RolloverMouseAdapter adapter) {
super();
this.adapter = adapter;
setHorizontalAlignment(JLabel.CENTER);
setBorderPainted(true);
}
#Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
getModel().setRollover(adapter.isRolloverCell(row, column));
if (isSelected) {
setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setSelected((value != null && ((Boolean) value).booleanValue()));
if (hasFocus) {
setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
} else {
setBorder(noFocusBorder);
}
return this;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TableRolloverDemo tableRolloverDemo = new TableRolloverDemo();
}
});
}
}
I have a JTable and everytime I select a cell, I want to print its row and column index.
I would override the changeSelection(...) method of the JTable:
JTable table = new JTable(data, columnNames)
{
public void xxxchangeSelection(
int row, int column, boolean toggle, boolean extend)
{
super.changeSelection(row, column, toggle, extend);
System.out.println(row + " : " + column);
}
};
I'm trying to present some data in JTable. I've created Jtable everything is clear apart from changing background color of some particular rows - thouse in which user tick a checkbox on the last colum. It has to work dynamically. Could you give me some tips, code, etc. please?
Something like this?
import java.awt.BorderLayout;
import java.util.Vector;
import javax.swing.*;
import java.awt.*;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;
public class JTableTest extends JFrame implements TableModel{
Vector<Object[]> lines = new Vector<Object[]>();
private String[] headers = {"String","Boolean"};
public JTableTest(){
for (int t = 0; t < 100; t++) lines.addElement(new Object[]{"Row "+t,Boolean.FALSE});
JPanel p = (JPanel)getContentPane();
p.setLayout(new BorderLayout());
JTable table = new JTable();
table.setDefaultRenderer(String.class, new MyRenderer());
p.add(new JScrollPane(table));
table.setModel(this);
p.setPreferredSize(new Dimension(400,200));
pack();
setVisible(true);
}
public static void main(String[] args){
new JTableTest();
}
#Override
public int getRowCount() {
return lines.size()+1;
}
#Override
public int getColumnCount() {
return headers.length;
}
#Override
public String getColumnName(int columnIndex) {
return headers[columnIndex];
}
#Override
public Class<?> getColumnClass(int col) {
if (col == 1) return Boolean.class;
return String.class;
}
#Override
public boolean isCellEditable(int row, int col) {
return col==1;
}
#Override
public Object getValueAt(int row, int col) {
return lines.elementAt(row)[col];
}
#Override
public void setValueAt(Object aValue, int row, int col) {
lines.elementAt(row)[col] = aValue;
}
#Override
public void addTableModelListener(TableModelListener l) {
}
#Override
public void removeTableModelListener(TableModelListener l) {
}
private class MyRenderer extends DefaultTableCellRenderer{
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (lines.elementAt(row)[1] == Boolean.TRUE) c.setBackground(Color.orange);
else c.setBackground(table.getBackground());
table.repaint();
return c;
}
}
}
Edit: I have added a SSCCE code
I have extended JTextArea in TableCellRenderer because I wanted to achieve the Multiline text wrapping Mentioned in this SO question and that is working fine. Now I have ran into weird problem with Nimbus look and feel. Nimbus is adding a border with every cell as shown in the below picture.
My Class:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class TestJTableMultiline extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
public TestJTableMultiline() {
super("Multi-Line Cell Example");
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
DefaultTableModel dm = new DefaultTableModel() {
/**
*
*/
private static final long serialVersionUID = 1L;
public Class<String> getColumnClass(int columnIndex) {
return String.class;
}
public boolean isCellEditable(int row, int column) {
return false;
}
};
dm.setDataVector(
new Object[][]{
{"A0, Line1\nA0, Line2\nA0, Line3",
"B0, Line1\nB0, Line2",
"C0, Line1"},
{"A1, Line1",
"B1, Line1\nB1, Line2",
"C1, Line1"},
{"A2, Line1",
"B2, Line1",
"C2, Line1"}
},
new Object[] {"A", "B", "C"});
JTable table = new JTable(dm);
table.setDefaultRenderer(String.class, new MultiLineTableCellRenderer());
TableRowSorter<? extends TableModel> sort = new TableRowSorter<DefaultTableModel>(dm);
table.setRowSorter(sort);
JScrollPane scroll = new JScrollPane(table);
getContentPane().add(scroll);
setLocationByPlatform(true);
setSize(400, 430);
setVisible(true);
}
public static void main(String[] args) {
try{
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
System.out.println("choosed nimbus");
break;
}
}
}catch(Exception e){
e.printStackTrace();
}
TestJTableMultiline frame = new TestJTableMultiline();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
class MultiLineTableCellRenderer extends JTextArea
implements TableCellRenderer {
/**
*
*/
private static final long serialVersionUID = 1L;
private List<List<Integer>> rowColHeight = new ArrayList<List<Integer>>();
public MultiLineTableCellRenderer() {
setLineWrap(true);
setWrapStyleWord(true);
setOpaque(true);
}
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setFont(table.getFont());
if (hasFocus) {
setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
if (table.isCellEditable(row, column)) {
setForeground(UIManager.getColor("Table.focusCellForeground"));
setBackground(UIManager.getColor("Table.focusCellBackground"));
}
} else {
setBorder(new EmptyBorder(1, 2, 1, 2));
}
if (value != null) {
setText(value.toString());
} else {
setText("");
}
adjustRowHeight(table, row, column);
return this;
}
/**
* Calculate the new preferred height for a given row, and sets the height on the table.
*/
private void adjustRowHeight(JTable table, int row, int column) {
//The trick to get this to work properly is to set the width of the column to the
//textarea. The reason for this is that getPreferredSize(), without a width tries
//to place all the text in one line. By setting the size with the with of the column,
//getPreferredSize() returnes the proper height which the row should have in
//order to make room for the text.
int cWidth = table.getTableHeader().getColumnModel().getColumn(column).getWidth();
setSize(new Dimension(cWidth, 1000));
int prefH = getPreferredSize().height;
while (rowColHeight.size() <= row) {
rowColHeight.add(new ArrayList<Integer>(column));
}
List<Integer> colHeights = rowColHeight.get(row);
while (colHeights.size() <= column) {
colHeights.add(0);
}
colHeights.set(column, prefH);
int maxH = prefH;
for (Integer colHeight : colHeights) {
if (colHeight > maxH) {
maxH = colHeight;
}
}
if (table.getRowHeight(row) != maxH) {
table.setRowHeight(row, maxH);
}
}
}
What has been tried:
I have tried setBorder(null) and setBorder(BorderFactory.createLineBorder(Color.black)) and various other color like forground and background color of the table.
Then I looked at this SO question and tried that solution as well but I am not able to resolve the border problem. I have also tried removing setBorder call altogether but the results are same.
I have also tried removing the cell border in jtable mentioned in this SO question
How can I resolve this border problem with Nimbus look and feel.
Note: I am getting nice view with other look and feel.
This might work in JDK 1.7.0 or later:
MultiLineTableCellRenderer r = new MultiLineTableCellRenderer();
UIDefaults d = new UIDefaults();
d.put("TextArea.borderPainter", new Painter() {
#Override public void paint(Graphics2D g, Object o, int w, int h) {}
});
r.putClientProperty("Nimbus.Overrides", d);
r.putClientProperty("Nimbus.Overrides.InheritDefaults", false);
table.setDefaultRenderer(String.class, r);
SSCCE
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.*;
import javax.swing.table.*;
import javax.swing.UIManager.LookAndFeelInfo;
public class TestJTableMultiline2 {
public JComponent makeUI() {
String[] columnNames = {"A", "B", "C"};
Object[][] data = {
{"A0, Line1\nA0, Line2\nA0, Line3", "B0, Line1\nB0, Line2", "C0, Line1"},
{"A1, Line1", "B1, Line1\nB1, Line2", "C1, Line1"},
{"A2, Line1", "B2, Line1", "C2, Line1"}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
#Override public Class<?> getColumnClass(int column) {
return String.class;
}
#Override public boolean isCellEditable(int row, int column) {
return false;
}
};
JTable table = new JTable(model);
table.setAutoCreateRowSorter(true);
MultiLineTableCellRenderer r = new MultiLineTableCellRenderer();
UIDefaults d = new UIDefaults();
d.put("TextArea.borderPainter", new Painter() {
#Override public void paint(Graphics2D g, Object o, int w, int h) {}
});
r.putClientProperty("Nimbus.Overrides", d);
r.putClientProperty("Nimbus.Overrides.InheritDefaults", false);
table.setDefaultRenderer(String.class, r);
return new JScrollPane(table);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch(Exception e) {
e.printStackTrace();
}
JFrame f = new JFrame("Multi-Line Cell Example 2");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new TestJTableMultiline2().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class MultiLineTableCellRenderer extends JTextArea implements TableCellRenderer {
private List<List<Integer>> rowColHeight = new ArrayList<List<Integer>>();
//private Border fhb = UIManager.getBorder("Table.focusCellHighlightBorder");
//private Border epb = BorderFactory.createEmptyBorder(2,5,2,5);
public MultiLineTableCellRenderer() {
super();
setLineWrap(true);
setWrapStyleWord(true);
setOpaque(true);
//System.out.println(fhb.getBorderInsets(this));
//setBorder(epb);
}
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
setFont(table.getFont());
setText(value != null ? value.toString() : "");
setMargin(new Insets(2,5,2,5));
//setBorder(hasFocus ? fhb : epb);
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
adjustRowHeight(table, row, column);
return this;
}
/**
* Calculate the new preferred height for a given row, and sets the height on the table.
* http://blog.botunge.dk/post/2009/10/09/JTable-multiline-cell-renderer.aspx
*/
private void adjustRowHeight(JTable table, int row, int column) {
//The trick to get this to work properly is to set the width of the column to the
//textarea. The reason for this is that getPreferredSize(), without a width tries
//to place all the text in one line. By setting the size with the with of the column,
//getPreferredSize() returnes the proper height which the row should have in
//order to make room for the text.
//int cWidth = table.getTableHeader().getColumnModel().getColumn(column).getWidth();
int cWidth = table.getCellRect(row, column, false).width; //Ignore IntercellSpacing
setSize(new Dimension(cWidth, 1000));
int prefH = getPreferredSize().height;
while (rowColHeight.size() <= row) {
rowColHeight.add(new ArrayList<Integer>(column));
}
List<Integer> colHeights = rowColHeight.get(row);
while (colHeights.size() <= column) {
colHeights.add(0);
}
colHeights.set(column, prefH);
int maxH = prefH;
for (Integer colHeight : colHeights) {
if (colHeight > maxH) {
maxH = colHeight;
}
}
if (table.getRowHeight(row) != maxH) {
table.setRowHeight(row, maxH);
}
}
}