How to make a JTable column to contain not JTextFields, but JTextAreas? - java

Please tell me, how to make a JTable column to contain JTextAreas,
so the cell's height will increase when user types a lot of text and
we can see more than one line (cell gets expanded; as result, row will expand too)

You need to write your own cell renderer and editor based on JTextArea:
public class Start
{
public static class JTextPaneCellEditor extends AbstractCellEditor implements TableCellEditor, KeyListener
{
private JViewport viewport;
private JTable table;
private int row;
private JTextPane pane;
public JTextPaneCellEditor(){
viewport = new JViewport();
pane = new JTextPane();
viewport.add(pane);
pane.addKeyListener(this);
}
#Override public Object getCellEditorValue(){
return pane.getText();
}
#Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column){
this.table = table;
this.row = row;
pane.setText(value.toString());
int newHeight = (int)pane.getPreferredSize().getHeight();
if(table.getRowHeight(row) < newHeight){
table.setRowHeight(row, newHeight);
}
return pane;
}
#Override public boolean isCellEditable(EventObject e){
if (e instanceof MouseEvent) {
return ((MouseEvent)e).getClickCount() >= 2;
}
return true;
}
#Override public void keyTyped(KeyEvent e){
table.setRowHeight(row, (int)pane.getPreferredSize().getHeight());
}
#Override public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
stopCellEditing();
}
}
#Override public void keyReleased(KeyEvent e){
}
}
private static class JTextPaneCellRenderer extends JViewport implements TableCellRenderer
{
JTextPane pane;
JTextPaneCellRenderer(){
pane = new JTextPane();
add(pane);
}
#Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
pane.setText(value.toString());
table.setRowHeight(row, (int)pane.getPreferredSize().getHeight());
return this;
}
}
public static void main(String[] args){
JTable table = new JTable(new String[][]{{"String String String String StringString String String String StringString String String String StringString String String String StringString String String String String"}, {"String 2"}}, new String[]{"Column"});
table.setDefaultRenderer(Object.class, new JTextPaneCellRenderer());
table.setDefaultEditor(Object.class, new JTextPaneCellEditor());
JFrame test = new JFrame();
test.add(new JScrollPane(table));
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setSize(300, 300);
test.setLocationRelativeTo(null);
test.setVisible(true);
}
}
EDIT: add viewports for better sizing. But the row is still not expanded on first edit. Does anyone have any ideas?
EDIT2: I agree with the comments. The thing you want is possible, but you need untested, hackish custom implementation. You will be better off if you redesigned your layout to exclude such JTable sorcery.

#Jakub Zaverka
I'll delete this answer later
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.*;
public class AutoWrapTest {
public JComponent makeUI() {
String[] columnNames = {"TextAreaCellRenderer"};
Object[][] data = {
{"123456789012345678901234567890"},
{"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddx"},
{"----------------------------------------------0"},
{">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>|"},};
TableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
JTable table = new JTable(model) {
private static final long serialVersionUID = 1L;
#Override
public void doLayout() {
TableColumn col = getColumnModel().getColumn(0);
for (int row = 0; row < getRowCount(); row++) {
Component c = prepareRenderer(col.getCellRenderer(), row, 0);
if (c instanceof JTextArea) {
JTextArea a = (JTextArea) c;
int h = getPreferredHeight(a) + getIntercellSpacing().height;
if (getRowHeight(row) != h) {
setRowHeight(row, h);
}
}
}
super.doLayout();
} //http://tips4java.wordpress.com/2008/10/26/text-utilities/
private int getPreferredHeight(JTextComponent c) {
Insets insets = c.getInsets();
View view = c.getUI().getRootView(c).getView(0);
int preferredHeight = (int) view.getPreferredSpan(View.Y_AXIS);
return preferredHeight + insets.top + insets.bottom;
}
};
table.setEnabled(false);
table.setShowGrid(false);
table.setTableHeader(null);
table.getColumnModel().getColumn(0).setCellRenderer(new TextAreaCellRenderer());
JScrollPane sp = new JScrollPane(table);
sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
JPanel p = new JPanel(new BorderLayout());
p.add(sp);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new AutoWrapTest().makeUI());
f.setSize(200, 200);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class TextAreaCellRenderer extends JTextArea implements TableCellRenderer {
private static final long serialVersionUID = 1L;
private final Color evenColor = new Color(230, 240, 255);
public TextAreaCellRenderer() {
super();
setLineWrap(true);
setWrapStyleWord(true);
setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
}
#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());
setBackground((row % 2 == 0) ? evenColor : getBackground());
}
setFont(table.getFont());
setText((value == null) ? "" : value.toString());
return this;
}
}

Related

Filter JTable with search word without losing background color

I have followed the tutorial to filter and highlight text in a JTable here.
The only thing I added is the LookAndFeel, which is set to Nimbus. The code works, except when I select a row, the back and foreground colors of the row are lost.
Without renderer:
With renderer:
In the code, the renderer creates a new label (LabelHighlighted extends JLabel) which overwrites the painComponent method. I guess somehow this method should take the background color of the row in the table.
#Override
protected void paintComponent(Graphics g) {
if (rectangles.size() > 0) {
Graphics2D g2d = (Graphics2D) g;
Color c = g2d.getColor();
for (Rectangle2D rectangle : rectangles) {
g2d.setColor(colorHighlight);
g2d.fill(rectangle);
g2d.setColor(Color.LIGHT_GRAY);
g2d.draw(rectangle);
}
g2d.setColor(c);
}
super.paintComponent(g);
}
Note: I know the JXTable variant of JTable has some more options for filtering and highlighting rows but I did not find a solution yet...
Renderer:
public class RendererHighlighted extends DefaultTableCellRenderer {
private JTextField searchField;
public RendererHighlighted(JTextField searchField) {
this.searchField = searchField;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean selected, boolean hasFocus,
int row, int column) {
Component c = super.getTableCellRendererComponent(table, value, selected, hasFocus, row, column);
JLabel original = (JLabel) c;
LabelHighlighted label = new LabelHighlighted();
label.setFont(original.getFont());
label.setText(original.getText());
label.setBackground(original.getForeground());
label.setForeground(original.getForeground());
label.setHorizontalTextPosition(original.getHorizontalTextPosition());
label.highlightText(searchField.getText());
return label;
}
}
LabelHighlighted:
public class LabelHighlighted extends JLabel {
private List<Rectangle2D> rectangles = new ArrayList<>();
private Color colorHighlight = Color.YELLOW;
public void reset() {
rectangles.clear();
repaint();
}
public void highlightText(String textToHighlight) {
if (textToHighlight == null) {
return;
}
reset();
final String textToMatch = textToHighlight.toLowerCase().trim();
if (textToMatch.length() == 0) {
return;
}
textToHighlight = textToHighlight.trim();
final String labelText = getText().toLowerCase();
if (labelText.contains(textToMatch)) {
FontMetrics fm = getFontMetrics(getFont());
float w = -1;
final float h = fm.getHeight() - 1;
int i = 0;
while (true) {
i = labelText.indexOf(textToMatch, i);
if (i == -1) {
break;
}
if (w == -1) {
String matchingText = getText().substring(i,
i + textToHighlight.length());
w = fm.stringWidth(matchingText);
}
String preText = getText().substring(0, i);
float x = fm.stringWidth(preText);
rectangles.add(new Rectangle2D.Float(x, 1, w, h));
i = i + textToMatch.length();
}
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
if (rectangles.size() > 0) {
Graphics2D g2d = (Graphics2D) g;
Color c = g2d.getColor();
for (Rectangle2D rectangle : rectangles) {
g2d.setColor(colorHighlight);
g2d.fill(rectangle);
g2d.setColor(Color.LIGHT_GRAY);
g2d.draw(rectangle);
}
g2d.setColor(c);
}
super.paintComponent(g);
}
}
It might be easy to use HTML tags for JLabel.
<span style='color:#000000; background-color:#FFFF00'>%s</span>
import java.awt.*;
import java.util.Objects;
import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
class RendererHighlighted extends DefaultTableCellRenderer {
private final JTextField searchField;
public RendererHighlighted(JTextField searchField) {
this.searchField = searchField;
}
#Override public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
String txt = Objects.toString(value, "");
String pattern = searchField.getText();
if (Objects.nonNull(pattern) && !pattern.isEmpty()) {
Matcher matcher = Pattern.compile(pattern).matcher(txt);
int pos = 0;
StringBuilder buf = new StringBuilder("<html>");
while (matcher.find(pos)) {
int start = matcher.start();
int end = matcher.end();
buf.append(String.format(
"%s<span style='color:#000000; background-color:#FFFF00'>%s</span>",
txt.substring(pos, start), txt.substring(start, end)));
pos = end;
}
buf.append(txt.substring(pos));
txt = buf.toString();
}
super.getTableCellRendererComponent(table, txt, isSelected, hasFocus, row, column);
return this;
}
}
public class HtmlHighlightCellTest {
public JComponent makeUI() {
String[] columnNames = {"A", "B"};
Object[][] data = {
{"aaa", "bbaacc"}, {"bbb", "defg"},
{"ccccbbbbaaabbbbaaeabee", "xxx"}, {"dddaaabbbbb", "ccbbaa"},
{"cc cc bbbb aaa bbbb e", "xxx"}, {"ddd aaa b bbbb", "cc bbaa"}
};
TableModel model = new DefaultTableModel(data, columnNames) {
#Override public boolean isCellEditable(int row, int column) {
return false;
}
#Override public Class<?> getColumnClass(int column) {
return String.class;
}
};
JTable table = new JTable(model);
table.setFillsViewportHeight(true);
TableRowSorter<? extends TableModel> sorter = new TableRowSorter<>(model);
table.setRowSorter(sorter);
JTextField field = new JTextField();
RendererHighlighted renderer = new RendererHighlighted(field);
table.setDefaultRenderer(String.class, renderer);
field.getDocument().addDocumentListener(new DocumentListener() {
#Override public void insertUpdate(DocumentEvent e) {
update();
}
#Override public void removeUpdate(DocumentEvent e) {
update();
}
#Override public void changedUpdate(DocumentEvent e) {}
private void update() {
String pattern = field.getText().trim();
if (pattern.isEmpty()) {
sorter.setRowFilter(null);
} else {
sorter.setRowFilter(RowFilter.regexFilter("(?i)" + pattern));
}
}
});
JPanel sp = new JPanel(new BorderLayout(2, 2));
sp.add(new JLabel("regex pattern:"), BorderLayout.WEST);
sp.add(field);
sp.add(Box.createVerticalStrut(2), BorderLayout.SOUTH);
sp.setBorder(BorderFactory.createTitledBorder("Search"));
JPanel p = new JPanel(new BorderLayout(2, 2));
p.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
p.add(sp, BorderLayout.NORTH);
p.add(new JScrollPane(table));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception ex) {
ex.printStackTrace();
}
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new HtmlHighlightCellTest().makeUI());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}

Show selected Row and Column in CellRenderer

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);
}
};

How to remove/set JTextArea border in JTable cell in Nimbus look and feel

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);
}
}
}

Having multi-line text on a ListCell using JList and ListCellRenderer

This class instance is returned by my ListCellRenderer:
public class SessionQALine extends JPanel {
private JTextArea question;
private JLabel answer;
public SessionQALine() {
setLayout(new BoxLayout(this,BoxLayout.X_AXIS));
setOpaque(false);
question = new JTextArea();
question.setLineWrap(true);
question.setWrapStyleWord(true);
question.setFont(new Font(Font.SERIF, Font.ITALIC|Font.BOLD, 14));
question.setOpaque(false);
answer = new JLabel();
answer.setFont(new Font(Font.SERIF, Font.BOLD, 10));
answer.setOpaque(false);
add(question);
add(Box.createHorizontalGlue());
add(answer);
}
public void setQuestion(String q) {
question.setText(q);
}
public void setAnswer(String q) {
answer.setText(q);
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawLine(0, getHeight()-1, getWidth(), getHeight()-1);
}
}
This is part of my ListCellRenderer:
private SessionQALine qaLine = new SessionQALine();
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
qaLine.setQuestion(questions.get(index));
qaLine.setAnswer(answers.get(index));
return qaLine;
}
everything works fine when the strings fit in one line, though if it needs more then one line, the second line and on seems not to be taken under consideration, the JList paints the cells and these line just never show, do you know how i can fix that?
for JList or JTable is easiest to use doLayout(), rather than getPreferredSize from java.swing.text.FieldView
most comfortable will be to put JTextArea to the JScrollPane, for quite nicer output to the GUI,
notice then have to redirect MouseScrollEvents from parent JScrollPane to the JScrollPane under Mouse Cursor, (five-six code_lines moreover a few times solved here)
use Borders or JSeparator instead of drawLine()
do you meaning
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.*;
//http://tips4java.wordpress.com/2008/10/26/text-utilities/
public class AutoWrapTest {
public JComponent makeUI() {
String[] columnNames = {" Text Area Cell Renderer "};
Object[][] data = {
{"123456789012345678901234567890"},
{"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddx"},
{"----------------------------------------------0"},
{">>>>>>>>>>>>>dddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "dddddddxdddddddddddddddddddddddddddddddddddddddddddddd"
+ "dddddddddddx>>>>>>>>>>>>>>>>>>>>>>>>>|"},
{">>>>>>>>>>>>ddddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "ddddddx>>>>>>>>>>>>>>>>>>>>>>>>>>|"},
{"a|"},
{">>>>>>>>bbbb>>>>>>>>>>>>>>>>>>>|"},
{">>>>>>>>>>>>>>>>>>|"},
{">>>>>>>>>>>>>dddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "dddddddxdddddddddddddd123456789012345678901234567890dddddd"
+ "dddddddddddddddddddddddddddddddddddddx>>>>>>>>>>>>>>>>>>>>"
+ ">>>>>|"},
{">>>>>>>>>>>>>dddddddddddddd123456789012345678901234567890dddddd"
+ "dddddddddddddddddddddddddddddddddddddxdddddddddddddd123456"
+ "789012345678901234567890dddddddddddddddddddddddddddddddddd"
+ "ddddd123456789012345678901234567890ddddx>>>>>>>>>>>>>>>>>>"
+ ">>>>>>>|"},};
TableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
JTable table = new JTable(model) {
private static final long serialVersionUID = 1L;
#Override
public void doLayout() {
TableColumn col = getColumnModel().getColumn(0);
for (int row = 0; row < getRowCount(); row++) {
Component c = prepareRenderer(col.getCellRenderer(), row, 0);
if (c instanceof JTextArea) {
JTextArea a = (JTextArea) c;
int h = getPreferredHeight(a) + getIntercellSpacing().height;
if (getRowHeight(row) != h) {
setRowHeight(row, h);
}
}
}
super.doLayout();
}
private int getPreferredHeight(JTextComponent c) {
Insets insets = c.getInsets();
View view = c.getUI().getRootView(c).getView(0);
int preferredHeight = (int) view.getPreferredSpan(View.Y_AXIS);
return preferredHeight + insets.top + insets.bottom;
}
};
table.setEnabled(false);
table.setShowGrid(false);
table.setTableHeader(null);
table.getColumnModel().getColumn(0).setCellRenderer(new TextAreaCellRenderer());
//table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane sp = new JScrollPane(table);
sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
sp.setPreferredSize(new Dimension(250, 533));
JPanel p = new JPanel(new BorderLayout());
p.add(sp);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new AutoWrapTest().makeUI());
f.setLocation(100, 100);
f.pack();
f.setVisible(true);
}
}
class TextAreaCellRenderer extends JTextArea implements TableCellRenderer {
private static final long serialVersionUID = 1L;
private final Color evenColor = new Color(230, 240, 255);
public TextAreaCellRenderer() {
super();
setLineWrap(true);
setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
}
#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());
setBackground((row % 2 == 0) ? evenColor : getBackground());
}
setFont(table.getFont());
setText((value == null) ? "" : value.toString());
return this;
}
}

How to highlight a particular column header in a JTable

I need to highlight a particular column header in a JTable.Is it possible to do that?
Also is it possible to draw a vertical line inside a JTable ?
Both are possible. Example:
public class Test extends JPanel{
private JTable table;
private String COLUMN1 = "COLUMN1";
private String COLUMN2 = "COLUMN2";
public Test() {
setLayout(new BorderLayout());
table = new LineTable(new Object[][]{{"1", "2"}, {"3", "4"}}, new Object[]{COLUMN1, COLUMN2});
TableColumn col = table.getColumn(COLUMN1);
col.setIdentifier(COLUMN1);
col.setHeaderValue("Column1");
col = table.getColumn(COLUMN2);
col.setIdentifier(COLUMN2);
col.setHeaderValue(new ColorHeaderValue("Column2"));
col.setHeaderRenderer(new ColorHeaderRenderer());
col.setCellRenderer(new LineCellRenderer());
JPanel pn = new JPanel();
pn.setLayout(new BoxLayout(pn, BoxLayout.X_AXIS));
pn.add(new JButton(new AbstractAction("Highlight Column2 in red"){
#Override
public void actionPerformed(ActionEvent e){
setColumnColor(COLUMN2, Color.RED);
}
}));
pn.add(new JButton(new AbstractAction("Clear Column2 header color"){
#Override
public void actionPerformed(ActionEvent e){
setColumnColor(COLUMN2, null);
}
}));
pn.add(Box.createHorizontalGlue());
add(pn, BorderLayout.NORTH);
add(new JScrollPane(table), BorderLayout.CENTER);
}
private void setColumnColor(final String columnID, final Color cl){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
Object headerValue = table.getColumn(columnID).getHeaderValue();
if(headerValue instanceof ColorHeaderValue){
ColorHeaderValue clHeaderValue = (ColorHeaderValue) headerValue;
clHeaderValue.setBrgColor(cl);
table.getTableHeader().repaint();
}
}
});
}
private static class LineTable extends JTable{
public LineTable(Object[][] rowData, Object[] columnNames) {
super(rowData, columnNames);
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
if (g != null){
g.drawLine(0, 0, this.getWidth(), getHeight());
}
}
}
private static class LineCellRenderer extends DefaultTableCellRenderer{
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
if (g != null){
int halfX = getWidth()/2;
g.drawLine(halfX, 0, halfX, getHeight());
}
}
}
private static class ColorHeaderRenderer extends DefaultTableCellHeaderRenderer{
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
Component res = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (value instanceof ColorHeaderValue){
ColorHeaderValue headerValue = (ColorHeaderValue) value;
if (headerValue.getBrgColor() != null){
setBackground(headerValue.getBrgColor());
}
}
return res;
}
}
private static class ColorHeaderValue{
private Color brgColor;
private String title;
public ColorHeaderValue(String title) {
this.title = title;
}
public final Color getBrgColor(){
return brgColor;
}
public final void setBrgColor(Color brgColor){
this.brgColor = brgColor;
}
public String toString(){
return title;
}
}
public static void main(String[] args){
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Add content to the window.
frame.add(new Test());
// Display the window.
frame.pack();
frame.setSize(300, 200);
frame.setVisible(true);
}}

Categories

Resources