I have a MultilineCellRenderer which should wrap the multiple lines in JTable cell.
public class MultiLineTableCellRenderer
extends JTextArea implements TableCellRenderer {
/**
*
*/
private static final long serialVersionUID = 1L;
public MultiLineTableCellRenderer() {
setLineWrap(true);
setWrapStyleWord(true);
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
setText(value.toString());//or something in value, like value.getNote()..
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setSize(table.getColumnModel().getColumn(column).getWidth(),
getPreferredSize().height);
if (table.getRowHeight(row) != getPreferredSize().height) {
table.setRowHeight(row, getPreferredSize().height);
}
return this;
}
}
I am creating and assigning this cell renderer as default cell renderer for myjtable(cnr_DATA)
MultiLineTableCellRenderer r = new MultiLineTableCellRenderer();
cnr_DATA.setDefaultRenderer(String.class, r);
cnr_DATA.setModel(new DefaultTableModel(data,columns){
public Class getColumnClass(int col){
return String.class;
};
});
I am also updating the content of jtable dynamically from the database
DefaultTableModel model = (DefaultTableModel)cnr_DATA.getModel();
removeAllCurrentRows(model);
Vector<DocumentRow> data =
RecycleSQL.readRecycledDocuments();//this line returning vector of objects
for(DocumentRow object:data)
model.addRow(new string[]{object.getFilename(),
object.getTitle(),object.getLastTouched()
,object.getLastTouchedBy()});
model.setRowCount(data.size());
cnr_DATA.revalidate();
My problem is that mycellrenderer is not being called and is not wrapping the data. Could some one please advice me how to call it after updating the content of the JTable.
Update according to the suggestion of Madprogrammer and hovercraft
After modifying the code according to the suggestion. Now the cellrenderer is being called but it is resting the row height to default value. This is the logs from debug statement
[2013-08-02 01:20:53,335] [AWT-EventQueue-0] DEBUG MultiLineTableCellRenderer - setting row height 3 128
[2013-08-02 01:20:53,335] [AWT-EventQueue-0] DEBUG MultiLineTableCellRenderer - setting row height 3 16
which means, that after setting the height of the row correctly it is resting it back to the default value
This looks suspect to me:
cnr_DATA.setDefaultRenderer(String.class, r); // ?? String.class
Are you sure that the model holds String data, and that the column type returned by getColumnClass(...) returns String? Consider instead setting the cell renderer for the column that needs it.
Related
I ahve a JTable that is supposed to be 2 columns (String, JComboBox). When i initialize the table everything looks good. As soon as a I select a value in the table the JComboBox cell aquires the data type of the selected item.
I want to keep the JCOmboBox there and have it fire the events of data change and the Table ignore data changes in that column and keep the ComboBox populated.
My table has this as an override
#Override
public TableCellEditor getCellEditor(int row, int column) {
Object value = super.getValueAt(row, column);
if (value != null) {
if (value instanceof JComboBox) {
return new DefaultCellEditor((JComboBox) value);
}
return getDefaultEditor(value.getClass());
}
return super.getCellEditor(row, column);
}
Implementation
JComboBox uploadBox = new JComboBox();
uploadBox.addItem(MyPanel.UPLOAD_OPTIONS.PROMPT);
uploadBox.addItem(MyPanel.UPLOAD_OPTIONS.UPLOAD);
uploadBox.addItem(MyPanel.UPLOAD_OPTIONS.DONT_UPLOAD);
Object[][] tableData = new Object[][]{
{"Upload data on save", uploadBox}
};
table.setModel(
new DefaultTableModel(tableData, new String[]{"Description", "Options"}) {
Class[] types = new Class[]{String.class, JComboBox.class};
boolean[] canEdit = new boolean[]{false, true};
#Override
public Class getColumnClass(int columnIndex) {
return types[columnIndex];
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return canEdit[columnIndex];
}
});
table.getColumnModel().getColumn(1).setCellRenderer(new TableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable jtable, Object o, boolean bln, boolean bln1, int i, int i1) {
return (Component)o;
}
});
answer is quite simple don't put JComboBox to the XxxTableModel or to set getColumClass for JComboBox.class, this is wrong (sure is possible but with bunch of side effects), XxxTableModel (is designated for) can hold directly only standard Java data types (String, Date, Icon/ImageIcon, Integer, Double etc... )
XxxTableModel should be store (if you don't want to parsing between Java data types) the same data type like as is stored in DefaultComboBoxModel (noting clear what constans are MyPanel.XXX), e.g in XxxTableModel is stored String value when DefaultComboBoxModel has the same data types, similair logics for Date, Icon/ImageIcon, Integer or Double
for more info to read Oracle tutorial How to use Tables - Using a Combo Box as an Editor
My problem is that I want to change the individual background color of a cell in one column in a jTable. The code I have come up with changes the color to one and it applies to all the columns. What am I doing wrong?
This is my code
public void fillReserveTable() {
MemberDAO dao = DATA.MemberDAO.getInstance();
ResultSet res2 = dao.fillReservationTable();
try {
if (res2.next()) {
res2.beforeFirst();
reserveTable.setModel(DbUtils.resultSetToTableModel(res2));
setUpOnHold(reserveTable, reserveTable.getColumnModel().getColumn(4));
reserveTable.getColumnModel().getColumn(3).setCellRenderer(new CustomRenderer());
jScrollPane14.setVisible(true);
}else{
jScrollPane14.setVisible(false);
}
} catch (SQLException e) {
}
}
class CustomRenderer extends DefaultTableCellRenderer {
MemberDAO dao = DATA.MemberDAO.getInstance();
ResultSet res2 = dao.fillReservationTable();
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component cellComponent = super.getTableCellRendererComponent(reserveTable, value, isSelected, hasFocus, row, column);
int row2 = 0;
try {
while (res2.next()) {
String status = reserveTable.getValueAt(row2, 3).toString();
if (status.equals("Available")) {
cellComponent.setBackground(Color.green);
} else {
cellComponent.setBackground(Color.red);
}
row2++;
}
} catch (SQLException e) {
}
return cellComponent;
}
}
Cell rendering happens very frequently. You don't want to execute an SQL call as part of your rendering. Also, you should log the SQLException when it happens instead of silently swallowing it.
In this case, you're storing a result set as a field in the cell renderer. The first time you render, you iterate to the end of the result set.
Instead of querying for the status, use the value parameter which is passed to the renderer. This will be the value in the cell being rendered. If you need some other cell's value, get it from the TableModel.
In this code, I'm adding the data from Database. I want to set cell renderer with a label. But if I run this code I got only check box.
try {
List<Group> listgrChild = grMgmtModel.performList();
for (final Group group : listgrChild) {
table.getColumnModel().getColumn(0)
.setCellRenderer(new TableCellRenderer() {
// the method gives the component like whome the
// cell must
// be rendered
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean isFocused,
int row, int col) {
boolean marked = new Boolean(String
.valueOf(value));
JCheckBox rendererComponent = new JCheckBox();
if (marked) {
rendererComponent.setSelected(true);
}
return rendererComponent;
}
});
tbModel.addRow(new Object[] { group.getGroupName() });
}
You comment, "renderComponent.setText("Hello") is giving only last value."
Verify that your TableModel has individual storage for each row's check box state and label value. In this example, the class Value holds the relevant data:
private static class Value implements Comparable<Value> {
private Boolean selected;
private Double value;
…
}
The corresponding TableModel manages a List<Value> and the required renderer and editor use the data from each Value instance accordingly. As an aside, Value implements the Comparable interface for convenience in sorting.
I wrote a class that implements TableCellRenderer, since I want to put checkboxes inside the jTable.
In the getTableCellRendererComponent method of this class, i have the condition :
if(isSelected){ do ..... }
inside this if condition, how can I know the row number ?
code :
private static class ValueRenderer extends JCheckBox
implements TableCellRenderer {
private static final Color hilite = new Color(0xE8E8E8);
public ValueRenderer() {
this.setOpaque(true);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,boolean hasFocus, int row, int col) {
Value v = (Value) value;
this.setSelected(v.selected);
if(isSelected)
{
if(v.selected==true)
System.out.println("checked");
else System.out.println("unchecked");
}
return this;
}
}
private static class Value {
private Boolean selected;
public Value(Boolean selected) {
this.selected = selected;
}
}
Why are you creating a Value class and a custom renderer? From the code it is just a Boolean. Just add the Boolean directly to the TableModel and then override the getColumnClass() method of the JTable or TableModel to return Boolean and the table will use the default Boolean renderer.
Read the JTable API and follow the link to the Swing tutorial on How to Use Tables for an example that uses Booleans.
Use the row parameter passed to your renderer. It's zero based just like arrays in Java.
I want to put JEditorPane in JTable cell.
I've written this:
jTabel1.setDefaultRenderer(String.class, new StringEditorPane());
.........
class StringEditorPane extends JEditorPane
implements TableCellRenderer {
public StringEditorPane() {
setContentType("text/html");
}
public Component getTableCellRendererComponent(
JTable table, Object styledString,
boolean isSelected, boolean hasFocus,
int row, int column) {
if (isSelected) {
String styledText = (String) styledString;
setText(styledText);
setBackground(getSelectionColor());
return this;
} else {
String styledText = (String) styledString;
setText(styledText);
setBackground(Color.white);
return this;
}
}
}
I can compile it and it show JEditorPane but it also throws an exception and I don't know why.
Exception:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.text.DefaultStyledDocument.getParagraphElement(DefaultStyledDocument.java:445)
at javax.swing.text.StyledEditorKit$AttributeTracker.updateInputAttributes(StyledEditorKit.java:223)
at javax.swing.text.StyledEditorKit$AttributeTracker.caretUpdate(StyledEditorKit.java:258)
at javax.swing.text.JTextComponent.fireCaretUpdate(JTextComponent.java:391)
at javax.swing.text.JTextComponent$MutableCaretEvent.fire(JTextComponent.java:4387)
at javax.swing.text.JTextComponent$MutableCaretEvent.stateChanged(JTextComponent.java:4409)
at javax.swing.text.DefaultCaret.fireStateChanged(DefaultCaret.java:782)
at javax.swing.text.DefaultCaret.changeCaretPosition(DefaultCaret.java:1257)
at javax.swing.text.DefaultCaret.handleSetDot(DefaultCaret.java:1153)
at javax.swing.text.DefaultCaret.setDot(DefaultCaret.java:1134)
at javax.swing.text.DefaultCaret$Handler.removeUpdate(DefaultCaret.java:1777)
at javax.swing.text.AbstractDocument.fireRemoveUpdate(AbstractDocument.java:243)
at javax.swing.text.AbstractDocument.handleRemove(AbstractDocument.java:608)
at javax.swing.text.AbstractDocument.remove(AbstractDocument.java:576)
at javax.swing.JEditorPane.setText(JEditorPane.java:1493)
at myProject.StringEditorPane.getTableCellRendererComponent(MainWindow.java:136)
at javax.swing.JTable.prepareRenderer(JTable.java:5720)
........
And the 136 line from MainWindow.java:
setText(styledText);
from getTableCellRendererComponent function.
It seems the crash is thrown from removing old content.
Try to replace document with a new instance. Before setText() call
setDocument(getEditorKit().createDefaultDocument());
Looks like you need to handle a null value for your styledText variable.
Not sure why you need a custom renderer. The default renderer for the String class is a JLabel and JLabels support HTML.