I want to use a custom TreeCellRenderer containing three text fields only when a node is SELECTED, while use the default renderer when the node is NOT SELECTED. The problem
Some facts:
On the whole, there is no way to implement your requirement without going dirty. Basically, you have to listen to selection changes - because the renderer has different size requirement in selected vs. not selected - and then do your best to invalidate the ui's internal cache. Basically two options:
Below is a snippet for the first (couldn't make the second work on a quick test, but faintly remember that I did it ...)
protected TreeSelectionListener createReflectiveSelectionListener() {
TreeSelectionListener l = new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
invalidateLayoutCache();
}
protected void invalidateLayoutCache() {
BasicTreeUI ui = (BasicTreeUI) tree.getUI();
try {
Method method = BasicTreeUI.class.getDeclaredMethod("configureLayoutCache");
method.setAccessible(true);
method.invoke(ui);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
e1.printStackTrace();
}
}
};
return l;
}
Just found the second - similar dirtyness-level as the first - option:
protected TreeSelectionListener createFakeDataEventSelectionListener() {
TreeSelectionListener l = new TreeSelectionListener() {
@Override
public void valueChanged(final TreeSelectionEvent e) {
fireDataChanged(e.getOldLeadSelectionPath());
fireDataChanged(e.getNewLeadSelectionPath());
}
private void fireDataChanged(TreePath lead) {
if (lead == null) return;
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
TreeNode last = (TreeNode) lead.getLastPathComponent();
model.nodeChanged(last);
}
};
return l;
}