CellContext.isExpanded() всегда возвращает true в JXTreeTable

Я использую JXTreeTable, Я хочу показать текст в ячейке, только если строка свернута. Если строка развернута, подробные значения отображаются в дочерних элементах, поэтому сокращенный текст в родительском элементе больше не должен отображаться.

Насколько я знаю, это должно быть реализовано путем предоставления специального ComponentProvider используется DefaultTableRenderer, Во всяком случае CellContext используется ComponentProvider всегда указывает, что узел расширен. context.isExpanded() всегда возвращается 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);

Что я должен изменить в ComponentProvider определить, расширен ли ряд ячейки или нет?

2 ответа

Решение

Решение может быть реализовано на основе ответа dic19.

Решение состоит в том, чтобы реализовать специальный рендер с getTableCellRendererComponent метод, который проверяет наличие JXTreeTable, В таком случае он оценивается, если строка развернута. Чек для leaf Флаг может быть добавлен также.

К сожалению, невозможно изменить DefaultTableRenderer потому что CellContext не виден в переопределяющих классах.

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

}

Anyhow the CellContext used by the ComponentProvider always indicates that the node is expanded.

This behavior goes back to the implementation of getTableCellRenderer(...) provided by DefaultTableRenderer: both expanded а также leaf свойства установлены в 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. Если вы установите TreeCellRenderer к 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);

Поскольку CellContext won't be a TableCellContext но TreeCellContext and it will contain the correct expanded а также leaf ценности:

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

    ...
}
Другие вопросы по тегам