SwingX JXTreeTableCellRenderer messes up my table - java

Here is my cell renderer class
public class MyCellRenderer extends DefaultTreeCellRenderer{
ImageIcon parentbill = new ImageIcon("images/parentbill.png");
ImageIcon childbill = new ImageIcon("images/childbill.png");
ImageIcon parentPurchase = new ImageIcon("images/parentexpense.png");
ImageIcon childPurchase = new ImageIcon("images/childexpense.png");
public MyCellRenderer(TreeTableController contr){
super();
}
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
if(leaf){
setIcon(childPurchase);
//((DefaultTreeCellRenderer) c).setClosedIcon(parentPurchase);
}else{
setIcon(parentPurchase);
}
if(expanded){
setIcon(parentPurchase);
}
return c;
}
}
And there is how I add it:
TableModel tableModel = new TableModel(root);
JXTreeTable treeTable = new JXTreeTable(tableModel);
treeController = new TreeTableController(tableModel, treeTable);
MyCellRenderer cellRenderer = new MyCellRenderer(treeController);
treeController.getTable().setTreeCellRenderer(cellRenderer);
So, my renderer is supposed to change icons for the different kinds of rows in the table.
And, he does it(wow!). But he messes how table should look at the first place, he puts some java garbage in the first cell, like this:
How can i fix it? I know, there is a method to set icons from JXTreeTable without renderer, but i want to add some conditions depending on the type of the row, so I have to override it.

Related

How can I add custom JComponent in a single JTable cell?

I want to make a JTable , where one single cell (not all rows of a column) will contain a JComponent like JdatePicker or JComboBox.
I have written this code
DefaultTableModel dm;
dm = new DefaultTableModel() {
public boolean isCellEditable(int rowIndex, int columnIndex) {
return !(columnIndex == 0); //make 0th column non-editable
}
};
Object [] columnHeaders=new Object[]{"Field", "Value"};
Object [][] data=new Object[][]{{"ID",""},{"Reg Year",""},{"Reg Date", ""}} ;
regFormTable.setModel(dm); //regFormTable is a Jtable object
I also have a class that implements TableCellrenderer:
public class datePickerCellRenderer extends JFrame implements TableCellRenderer{
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
this.add(new JDateChooser());
return this;
}
}
How can I use datePickerCellRenderer class to implement as I described. I tried a few ways. None of those worked.
[Using Netbeans GUI builder is there a way to do that?]
Plaese ask if any more code I need to add

how to use custom cell rendering in jtable for the below needs? [duplicate]

I would like to make an editable table and then check the data to make sure its valid. Im not sure how to change the color of just one cell. I would like to get a cell, for example (0,0) and color the foreground to red. I have read the other posts on SO as well as Oracle about the custom ColorRenderer, but i just don't get how i would use this.
Thanks.
Say that the cell you would like to render with a different color represents a status (I'll take Rejected and Approved as examples). I'd then implement a method in my table model called getStatus(int row) which returns the status for any given row.
Then, when that is in place, I'd go about creating a cell renderer responsible for rendering the column which the cell belongs to. The cell renderer would be something in the lines of the below code.
public class StatusColumnCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
//Cells are by default rendered as a JLabel.
JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
//Get the status for the current row.
CustomTableModel tableModel = (CustomTableModel) table.getModel();
if (tableModel.getStatus(row) == CustomTableModel.APPROVED) {
l.setBackground(Color.GREEN);
} else {
l.setBackground(Color.RED);
}
//Return the JLabel which renders the cell.
return l;
}
Then, when the renderer is in place, simply "apply" the renderer to the table with the following piece of code:
Table.getColumnModel().getColumn(columnIndex).setCellRenderer(new StatusColumnCellRenderer());
With regard to making a cell editable, simply implement the isCellEditable(int rowIndex, int columnIndex) method in your table model. You also need to implement the method
setValueAt(Object value, int rowIndex, int columnIndex) if you would like to keep the value which the user provides (which i assume you do!).
I would like to make an editable table and then check the data to make sure its valid.
Another approach would be to edit the data before it is saved to the table model to prevent invalid data from being entered.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class TableEdit extends JFrame
{
TableEdit()
{
JTable table = new JTable(5,5);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollpane = new JScrollPane(table);
getContentPane().add(scrollpane);
// Use a custom editor
TableCellEditor fce = new FiveCharacterEditor();
table.setDefaultEditor(Object.class, fce);
}
class FiveCharacterEditor extends DefaultCellEditor
{
FiveCharacterEditor()
{
super( new JTextField() );
}
public boolean stopCellEditing()
{
try
{
String editingValue = (String)getCellEditorValue();
if(editingValue.length() != 5)
{
JTextField textField = (JTextField)getComponent();
textField.setBorder(new LineBorder(Color.red));
textField.selectAll();
textField.requestFocusInWindow();
JOptionPane.showMessageDialog(
null,
"Please enter string with 5 letters.",
"Alert!",JOptionPane.ERROR_MESSAGE);
return false;
}
}
catch(ClassCastException exception)
{
return false;
}
return super.stopCellEditing();
}
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column)
{
Component c = super.getTableCellEditorComponent(
table, value, isSelected, row, column);
((JComponent)c).setBorder(new LineBorder(Color.black));
return c;
}
}
public static void main(String [] args)
{
JFrame frame = new TableEdit();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
I believe the correct way to do colouring in a table is via a ColorHighlighter. The table renderers have problems to render different colours in the same column.
Here is an example of how to use highlighters. In this case it is for highlighting a cell that is not editable.
public class IsCellEditablePredicate implements HighlightPredicate {
private JXTable table;
public IsCellEditablePredicate (final JXTable table) {
this.table = table;
}
#Override
public boolean isHighlighted(Component component, ComponentAdapter componentAdapter) {
return !table.isCellEditable(componentAdapter.row,
componentAdapter.column);
}
}
and then in your code for setuping the table you add the highlighter and its colour parameters:
ColorHighlighter grayHighlighter = new ColorHighlighter(new IsCellEditablePredicate(table));
grayHighlighter.setBackground(Color.LIGHT_GRAY);
grayHighlighter.setForeground(table.getForeground());
grayHighlighter.setSelectedBackground(table.getSelectionBackground().darker());
grayHighlighter.setSelectedForeground(table.getSelectionForeground().darker());
table.setHighlighters(grayHighlighter);
This is the simplest way to color a particular Column or cell in a jTable.
First just create a simple class of CustomRenderer
class CustomRenderer extends DefaultTableCellRenderer <br />
{
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);
setForeground(Color.blue); >
return c;
}
}
This code gets the column of cell to render
TableColumn col = tblExamHistoryAll.getColumnModel().getColumn(5);
DefaultTableModel model3 = (DefaultTableModel)tblExamHistoryAll.getModel();
col.setCellRenderer(new CustomRenderer());
This is to clear all previous rows from your table. If you do not want them just remove these lines
model3.getDataVector().removeAllElements();
model3.fireTableDataChanged();
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int col) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
int control = row;
control = control % 2;
control = (control == 0) ? 1 : 0;
if (control == 1) {
c.setBackground(Color.green);
} else {
c.setBackground(Color.cyan);
}
return c;
}
The most straightforward way is to write a simple TableCellRenderer by extending the DefaultTableCellRenderer and overwriting the getTableCellRendererComponent method to setBackground( Color.RED ). For example:
final JTable table = new JTable(...);
table.setCellRenderer( new DefaultTableCellRenderer() {
public Component getTableCellRenderer(JTable table, Object value, ...) {
super.getTableCellRenderer(...);
if ( value should be highlighted ) {
setBackground( Color.RED );
}
return this;
}
});
You can extend DefaultTableCellRenderer, override getTableCellRendererComponent and call something like
if (myConditions) setBackground(myColor);
before returning "this" when conditions apply but it has a very annoying side-effect of changing the default back-color due to the way DefaultTableCellRenderer.setBackGround is coded.
The trick I found was to entirely duplicate the code of DefaultTableCellRenderer in a class named HackedDefaultTableCellRenderer, add a method that calls directly the Component's setBackground implementation:
public void setComponentBackground(Color c) {
super.setBackground(c);
}
then derive my customized rendered from this hacked class instead of from DefaultTableCellRenderer, and finally call setComponentBackground instead of setBackground in my customized getTableCellRendererComponent.
The drawback is that this HackedDefaultTableCellRenderer relies on a snapshot of DefaultTableCellRenderer.

Change JTree icons based on custom Object states

I have a JTree, based on several custom classes. I want to give several Nodes a specific icon. Therefore i did the following code based on this link: Dynamically change icon of specific nodes in JTree
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer() {
private static final long serialVersionUID = 1L;
private Icon good = new ImageIcon(getClass().getResource("/good.png"));
private Icon dunno = new ImageIcon(getClass().getResource("/dunno.png"));
private Icon bad = new ImageIcon(getClass().getResource("/bad.png"));
#Override
public Component getTreeCellRendererComponent(JTree tree,
Object value, boolean selected, boolean expanded,
boolean isLeaf, int row, boolean focused) {
Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, isLeaf, row, focused);
// JTreePanelNode node = (JTreePanelNode)c; - not possible
return c;
}
};
this.getTree().setCellRenderer(renderer);
Each of my Nodes is an object of JTreePanelNode (custom class), which saves a specific state which can be set via setState(String s) and get via getState(). So what i want is to something like this:
if(node.getState().equals("good")) ..
else if(node.getState.equals("bad")) ..
else ..
How can i achieve something like that? From what i understand the renderer goes through every node with getTreeCellRendererComponent and applies a specific icon which i can choose with setIcon and several ifs(). However i cannot cast to JTreePanelNode. Any solution? Thanks :)
All depends on your JTreePanelNode Class. if it implements the TreeNode interface you are good to go with:
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
Component comp = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
row, hasFocus);
TreeNode current = (TreeNode)value;
if (leaf) {
//set leaf icon
} else if (expanded) {
//set expanded icon
} else {
// set default state
}
if (hasFocus)
//set what it looks like if focused
else if (selected)
//set what it looks like if selected
else
//set default l&f
comp.setIcon(whatevericonset in above conditions);
return comp;
}
Of course you can add many more states depending on your node class.getState().
you can get access to the Object represented in that tree:
#Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean isLeaf, int row, boolean focused) {
Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, isLeaf, row, focused);
DefaultMutableTreeNode node = (DefaultMutableTreeNode ) value;
Object representedObject = node.getUserObject();
JLabel superLabel = super.getTreeCellRendererComponent();
String text = label.getText();
if(object.isGood() ){ //i don't know your code
superLabel .setText (text +"goooooooood");
}else{
superLabel .setText (text +"badbadbabd");
}
return superLabel ;
}

how to extend BooleanRenderer

I'm trying to implement mouse hover effects for my JTable.
(When the mouse goes over a table's row the row's background changes).
In order to do that, I extended the DefaultTableCellRenderer like this:
public class FileTableCellRenderer extends DefaultTableCellRenderer{
public FileTableCellRenderer() {
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
FileTable fileTable = (FileTable)table;
Component c = super.getTableCellRendererComponent(fileTable, value, isSelected, hasFocus, row, column);
if(!isSelected){
if(row == fileTable.getCursorRow())
{
c.setBackground(Color.pink);
c.setForeground(Color.darkGray);
}
else
{
c.setBackground(Color.white);
c.setForeground(Color.darkGray);
}
}
this.setText(value.toString());
return this;
}
}
I set the JTable's defaultRenderer, and it works. The problem is I have one column which is Boolean. before I set my renderer I had this cute checkbox as default renderer for it.
Now, it just shows "true" or "false".
On the other hand, if I leave the defualt BooleanRenderer for the Boolean column, it will not be highlighted with the whole row...
I also tried to extned the JTable.BooleanRenderer, but it seems to be protected, so I cannot even extend it.
How can I leave this checkbox of the BooleanRenderer, but change background color with the rest of the row?
This cannot be done using inheritance since BooleanRenderer is a non-public inner class of JTable. But you can use composition instead. E.g., create a wrapper class that will accept a TableCellRenderer ('parent') as a constructor argument. If you pass a BooleanRenderer from your table as a parent, calling its getTableCellRendererComponent() method will return a Checkbox component, so you'll be able to make any further adjustments to it (I use code from the question to set the background color):
import javax.swing.*;
import javax.swing.plaf.UIResource;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
public class BooleanCellRenderer implements TableCellRenderer, UIResource {
private final TableCellRenderer parent;
public BooleanCellRenderer(TableCellRenderer parent) {
this.parent = parent;
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = parent.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
FileTable fileTable = (FileTable) table;
if (!isSelected) {
if (row == fileTable.getCursorRow()) {
c.setBackground(Color.pink);
c.setForeground(Color.darkGray);
} else {
c.setBackground(Color.white);
c.setForeground(Color.darkGray);
}
}
return c;
}
}
Then, in your main GUI class containing a JTable, take the table's default Boolean renderer and pass it to the wrapper:
FileTable fileTable = new FileTable();
fileTable.setDefaultRenderer(Boolean.class, new BooleanCellRenderer(fileTable.getDefaultRenderer(Boolean.class)));
You can leave the FileTableCellRenderer to render String cells:
FileTable fileTable = new FileTable();
fileTable.setDefaultRenderer(String.class, new FileTableCellRenderer());
fileTable.setDefaultRenderer(Boolean.class, new

How to get full highlighting (with border) on JTable Renderer

There is a common method when using JTable TableCellRenderers for setting the background and foreground when the cell is selected. Here is an example question that was asked:
Why does my Java custom cell renderer not show highlighting when the row/cell is selected?
This solution is lacking one thing ... the border around the cell. (Note I am not asking about a border around the row, as was asked here.) The border should highlight when the cell is selected. It is not acceptable to just create your own Border, and set it, because the border you create may not fit in with the Look & Feel.
I've successfully got the border by initializing a default renderer, and then scavenging it for its border, as follows:
private final DefaultTableCellRenderer defTblRend = new DefaultTableCellRenderer();
private final JComponent renderer = new ComplexCell(); // Whatever object type extends JComponent
#Override public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column)
{
// ... Set values on "renderer" object here ...
renderer.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
renderer.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
renderer.setOpaque(!renderer.getBackground().equals(table.getBackground()));
JComponent comp = (JComponent)defTblRend.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
renderer.setBorder(comp.getBorder());
return renderer;
}
Is there a better way?
You might be able to use the UIManager. See UIManager Defaults. "Table.focusCellHighlightBorder" would appear to be the property you want.
ADDED BY ORIGINAL POSTER:
Here is the solution I came up with based on camickr's info. Optimizations/cleanup welcome.
Set up static borders so they are available wherever you need them (I put them in a class called "UiUtils"):
public static final Border focusedCellBorder = UIManager.getBorder("Table.focusCellHighlightBorder");
public static final Border unfocusedCellBorder = createEmptyBorder();
private static Border createEmptyBorder()
{
Insets i = focusedCellBorder.getBorderInsets(new JLabel());
return BorderFactory.createEmptyBorder(i.top, i.left, i.bottom, i.right);
}
Renderer
#Override public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column)
{
// [... set component values here ...]
label.setBorder(hasFocus ? UiUtils.focusedCellBorder : UiUtils.unfocusedCellBorder);
return label;
}

Categories

Resources