Change JTree row height resizing behavior when rendering

拜拜、爱过 提交于 2019-12-04 06:55:13

Some facts:

  • BasicTreeUI keeps a cache of node sizes
  • there's no public api to force it to revalidate that cache
  • node size requirements are assumed to depend exclusively on data, not on visual state, that is change of selection state will not trigger any internal update
  • an aside: setting size inside the renderer/editor has no effect: whatever you do, the ui will change it as it deems appropriate

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:

  • use reflection to access protected methods of the ui
  • fake model events that would lead to an internal re-calculation of the cache

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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!