问题
I am using a JXTreeTable
.
I want to show a text in a cell only if the row is collapsed. If the row is expanded the detailed values are shown in the childs so the shortened text in the parent should no longer be visible.
As far as I know this need to be implemented by providing a special ComponentProvider
used by the DefaultTableRenderer
. Anyhow the CellContext
used by the ComponentProvider
always indicates that the node is expanded. context.isExpanded()
always returns true
.
StringValue valueProvider = new StringValue()
{
@Override
public String getString(Object value)
{
return String.valueOf(value);
}
};
ComponentProvider<?> textProvider = new LabelProvider(valueProvider, JLabel.TRAILING)
{
@Override
protected String getValueAsString(CellContext context)
{
System.out.println("Context expanded " + context.isExpanded());
if (context.isExpanded())
{
return "";
}
return super.getValueAsString(context);
}
};
DefaultTableRenderer renderer = new DefaultTableRenderer(textProvider);
What do I have to change in the ComponentProvider
to detect if the row of the cell is expanded or not?
回答1:
The solution can be implemented based on the answer of dic19.
The solution is to implement a special renderer with a getTableCellRendererComponent
method that checks for a JXTreeTable
. In such a case it is evaluated if the row is expanded. The check for the leaf
flag may be added also.
Unfortunately it is not possible to modify the DefaultTableRenderer
because the CellContext is not visible in overriding classes.
public class DefaultTreeTableRenderer
extends AbstractRenderer
implements TableCellRenderer
{
private TableCellContext cellContext;
/**
* Instantiates a default table renderer with the default component provider.
*
* @see #DefaultTableRenderer(ComponentProvider)
*/
public DefaultTreeTableRenderer()
{
this((ComponentProvider<?>)null);
}
/**
* Instantiates a default table renderer with the given component provider. If the controller is null, creates
* and uses a default. The default provider is of type <code>LabelProvider</code>.
*
* @param componentProvider the provider of the configured component to use for cell rendering
*/
public DefaultTreeTableRenderer(ComponentProvider<?> componentProvider)
{
super(componentProvider);
this.cellContext = new TableCellContext();
}
/**
* Instantiates a default table renderer with a default component provider using the given converter.
*
* @param converter the converter to use for mapping the content value to a String representation.
* @see #DefaultTableRenderer(ComponentProvider)
*/
public DefaultTreeTableRenderer(StringValue converter)
{
this(new LabelProvider(converter));
}
/**
* Instantiates a default table renderer with a default component provider using the given converter and
* horizontal alignment.
*
* @param converter the converter to use for mapping the content value to a String representation.
* @see #DefaultTableRenderer(ComponentProvider)
*/
public DefaultTreeTableRenderer(StringValue converter, int alignment)
{
this(new LabelProvider(converter, alignment));
}
/**
* Intantiates a default table renderer with default component provider using both converters.
*
* @param stringValue the converter to use for the string representation
* @param iconValue the converter to use for the icon representation
*/
public DefaultTreeTableRenderer(StringValue stringValue, IconValue iconValue)
{
this(new MappedValue(stringValue, iconValue));
}
/**
* Intantiates a default table renderer with default component provider using both converters and the given
* alignment.
*
* @param stringValue the converter to use for the string representation
* @param iconValue the converter to use for the icon representation
* @param alignment the rendering component's horizontal alignment
*/
public DefaultTreeTableRenderer(StringValue stringValue, IconValue iconValue, int alignment)
{
this(new MappedValue(stringValue, iconValue), alignment);
}
// -------------- implements javax.swing.table.TableCellRenderer
/**
* Returns a configured component, appropriate to render the given list cell.
* <p>
* Note: The component's name is set to "Table.cellRenderer" for the sake of Synth-based LAFs.
*
* @param table the <code>JTable</code>
* @param value the value to assign to the cell at <code>[row, column]</code>
* @param isSelected true if cell is selected
* @param hasFocus true if cell has focus
* @param row the row of the cell to render
* @param column the column of the cell to render
* @return the default table cell renderer
*/
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column)
{
boolean expanded = true;
boolean leaf = true;
if (table instanceof JXTreeTable)
{
JXTreeTable treeTable = (JXTreeTable)table;
expanded = treeTable.isExpanded(row);
}
this.cellContext.installContext(table, value, row, column, isSelected, hasFocus, expanded, leaf);
Component comp = this.componentController.getRendererComponent(this.cellContext);
// fix issue #1040-swingx: memory leak if value not released
this.cellContext.replaceValue(null);
return comp;
}
/**
* {@inheritDoc}
*/
@Override
protected ComponentProvider<?> createDefaultComponentProvider()
{
return new LabelProvider();
}
}
回答2:
Anyhow the
CellContext
used by theComponentProvider
always indicates that the node is expanded.
This behavior goes back to the implementation of getTableCellRenderer(...) provided by DefaultTableRenderer
: both expanded
and leaf
properties are set to true
:
public class DefaultTableRenderer extends AbstractRenderer implements TableCellRenderer {
private TableCellContext cellContext;
...
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
// both 'expanded' and 'leaf' properties are set to 'true' here:
cellContext.installContext(table, value, row, column, isSelected, hasFocus, true, true);
// 'componentController' is an instance of 'ComponentProvider<?>'
Component comp = componentController.getRendererComponent(cellContext);
cellContext.replaceValue(null);
return comp;
}
...
}
It makes sense given those properties are significant in a tree cell context, not a table cell context. If you set a TreeCellRenderer
to the JXTreeTable
using the very same ComponentProvider
then it should work as expected in the first column (tree column):
ComponentProvider<?> textProvider = new LabelProvider(valueProvider, JLabel.TRAILING) {...};
...
DefaultTreeRenderer treeRenderer = new DefaultTreeRenderer(textProvider);
...
treeTable.setTreeCellRenderer(treeRenderer);
Because the CellContext
won't be a TableCellContext
but a TreeCellContext
and it will contain the correct expanded
and leaf
values:
public class DefaultTreeRenderer extends AbstractRenderer implements TreeCellRenderer {
private TreeCellContext cellContext;
...
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
// both 'expanded' and 'leaf' properties are correctly set here:
cellContext.installContext(tree, value, row, 0, selected, hasFocus, expanded, leaf);
// 'componentController' is an instance of 'ComponentProvider<?>'
Component comp = componentController.getRendererComponent(cellContext);
cellContext.replaceValue(null);
return comp;
}
...
}
来源:https://stackoverflow.com/questions/27421887/cellcontext-isexpanded-returns-always-true-in-jxtreetable