展开 折叠 展开 JTree 延迟加载的问题

2023-11-23

我已经使用延迟加载实现了一棵树。第一级节点是在创建树时创建的,而子节点仅在用户展开任何特定节点时创建。

数据来自数据库,我们向数据库发出查询以填充子节点。实现了 TreeExpansionListener 并使用 treeExpanded 方法的重写实现。扩展时,我删除所选节点的所有子节点,进行数据库查询并将记录作为子节点添加到所选节点。在将任何节点添加到树之前,都会向该节点添加一个虚拟子节点。使用 DefaultMutableTreeNode。

到目前为止一切顺利,按照预期工作正常。

问题 1 - 正如您一样,它是每次扩展的数据库调用,因此如果节点折叠并再次扩展,我将进行一次数据库旅行并再次处理...这个想法是如果已经扩展,则不要加载新的节点...

问题 2 - 如果我必须强制刷新,即重新加载树并保持扩展状态。现在处于工作状态...我怎样才能实现相同的目标并解决上述问题 1?


正如 MadProgrammer 所解释的,这里是一个小演示示例,显示了当树在节点上扩展时动态加载数据的 JTree(并且有一个漂亮的加载栏作为奖励):

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.Transient;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;

public class TestJTree {

    public static class MyTreeNode extends DefaultMutableTreeNode {

        private boolean loaded = false;

        private int depth;

        private final int index;

        public MyTreeNode(int index, int depth) {
            this.index = index;
            this.depth = depth;
            add(new DefaultMutableTreeNode("Loading...", false));
            setAllowsChildren(true);
            setUserObject("Child " + index + " at level " + depth);
        }

        private void setChildren(List<MyTreeNode> children) {
            removeAllChildren();
            setAllowsChildren(children.size() > 0);
            for (MutableTreeNode node : children) {
                add(node);
            }
            loaded = true;
        }

        @Override
        public boolean isLeaf() {
            return false;
        }

        public void loadChildren(final DefaultTreeModel model, final PropertyChangeListener progressListener) {
            if (loaded) {
                return;
            }
            SwingWorker<List<MyTreeNode>, Void> worker = new SwingWorker<List<MyTreeNode>, Void>() {
                @Override
                protected List<MyTreeNode> doInBackground() throws Exception {
                    // Here access database if needed
                    setProgress(0);
                    List<MyTreeNode> children = new ArrayList<TestJTree.MyTreeNode>();
                    if (depth < 5) {
                        for (int i = 0; i < 5; i++) {
                            // Simulate DB access time
                            Thread.sleep(300);
                            children.add(new MyTreeNode(i + 1, depth + 1));
                            setProgress((i + 1) * 20);
                        }
                    } else {
                        Thread.sleep(1000);
                    }
                    setProgress(0);
                    return children;
                }

                @Override
                protected void done() {
                    try {
                        setChildren(get());
                        model.nodeStructureChanged(MyTreeNode.this);
                    } catch (Exception e) {
                        e.printStackTrace();
                        // Notify user of error.
                    }
                    super.done();
                }
            };
            if (progressListener != null) {
                worker.getPropertyChangeSupport().addPropertyChangeListener("progress", progressListener);
            }
            worker.execute();
        }

    }

    protected void initUI() {
        JFrame frame = new JFrame(TestJTree.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        MyTreeNode root = new MyTreeNode(1, 0);
        final DefaultTreeModel model = new DefaultTreeModel(root);
        final JProgressBar bar = new JProgressBar();
        final PropertyChangeListener progressListener = new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                bar.setValue((Integer) evt.getNewValue());
            }
        };
        JTree tree = new JTree() {
            @Override
            @Transient
            public Dimension getPreferredSize() {
                Dimension preferredSize = super.getPreferredSize();
                preferredSize.width = Math.max(400, preferredSize.width);
                preferredSize.height = Math.max(400, preferredSize.height);
                return preferredSize;
            }
        };
        tree.setShowsRootHandles(true);
        tree.addTreeWillExpandListener(new TreeWillExpandListener() {

            @Override
            public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
                TreePath path = event.getPath();
                if (path.getLastPathComponent() instanceof MyTreeNode) {
                    MyTreeNode node = (MyTreeNode) path.getLastPathComponent();
                    node.loadChildren(model, progressListener);
                }
            }

            @Override
            public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {

            }
        });
        tree.setModel(model);
        root.loadChildren(model, progressListener);
        frame.add(new JScrollPane(tree));
        frame.add(bar, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
            UnsupportedLookAndFeelException {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestJTree().initUI();
            }
        });
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

展开 折叠 展开 JTree 延迟加载的问题 的相关文章

随机推荐

  • Cython prange 对于 4 个线程来说比范围要慢

    我目前正在尝试遵循一个简单的示例 使用 cython 的 prange 并行化循环 我已经安装了允许 openmp 的 OpenBlas 0 2 14 并针对 openblas 从源代码编译了 numpy 1 10 1 和 scipy 0
  • 使用 PHP 从 XML 中删除空标签

    Question 如何删除 PHP 中的空 xml 标签 Example value1 2 value2 4 value3 xml
  • 作为限电的一部分,密码身份验证被暂时禁用。请改用个人访问令牌[重复]

    这个问题在这里已经有答案了 我使用用户名密码来推送我的代码 它工作了几个月 但突然我无法做到这一点并收到此错误 Username for https github com shreyas jadhav Password for https
  • 返回 PHP 中字符第一次出现之前的字符串部分

    这个问题在这里已经有答案了 在 PHP 中 返回第一次出现特定字符之前的字符串部分的最简单方法是什么 例如 如果我有一个字符串 那只敏捷的棕色狐狸跳过了等等 并且我正在过滤空格字符 该函数将返回 The 对于谷歌用户 strtok对此更好
  • 从函数调用时 matplotlib 滑块不起作用

    我有以下代码 显示带有滑动条的图表 from matplotlib widgets import Slider import matplotlib pyplot as plt from numpy import arange sin pi
  • 无法启动活动 ComponentInfo.....java.lang.IllegalStateException:已附加

    我收到了该错误 正如您所看到的 我正在添加从第一个活动中获取的数据并将其存储到第二个活动中的数组中 然后我使用数组填充列表视图 所以问题是每当我单击第一个视图上的保存按钮时公共类 Main2Activity 扩展 AppCompatActi
  • 即使支持 HTML5 视频,浏览器也会加载 HTML5 后备图像

    我有一些带有动画 GIF 的 HTML5 视频作为后备 遗憾的是 尽管支持 HTML5 视频 但 GIF 仍在加载 在不使用 javascript 的情况下 有没有办法阻止浏览器下载 HTML5 后备内容 如果没有 我只会使用 jquery
  • 如何用诅咒显示预着色字符串?

    我正在用Python 编写一个curses 程序 我是诅咒的初学者 但我使用终端控制序列进行彩色输出 现在有一些代码片段要在窗口内打印 我希望它们的语法突出显示 并且最好使用像 pygments 这样的库来完成 它使用控制序列输出突出显示的
  • 为什么 PowerShell(带有 Perl)要删除简单 print 语句中的双引号?

    我是 Linux 的长期用户 但对 Windows 和 PowerShell 还很陌生 我刚刚第一次安装Windows7和Strawberry Perl 5 我现在想使用 Windows PowerShell 进行简单的命令行打印 看起来
  • cx_Freeze 导致 Python 3.7.0 崩溃

    cx Freeze 6 0b1 最新版本 是否支持 Python 3 7 0 我刚刚创建了一个简单的项目 它适用于 Python 3 5 4 但不适用于 Python 3 7 0 它显示 Python 致命错误 initfsencoding
  • TestNG 可以看到我的 Spock (JUnit) 测试结果吗?

    需要让 TestNG 来运行我的 Spock 测试 因为 TestNG 在系统的其余部分中使用 由于 TestNG 支持运行 JUnit 测试 我尝试了以下方法
  • 如何调试“安全句柄已关闭”错误

    我继承的代码不断崩溃 并出现以下错误 根本没有改变 System ObjectDisposedException Safe handle has been closed at Microsoft Win32 UnsafeNativeMeth
  • Spring bean 范围。单例和原型

    假设有两个类ClassA和ClassB 假设 ClassB 依赖于 ClassA 在配置文件中 如果我们将 ClassA 的范围定义为单例 将 ClassB 的范围定义为 Prototype 那么每次创建 ClassA 的 bean 实例时
  • ES2021 (ES12) 中的 WeakRef 和终结器是什么

    我想了解什么是WeakRef和终结器ES2021 with a 真正的简单例子 and Where使用它们 I know WeakRef是一个类 这将允许开发人员创建对对象的弱引用 而终结器或FinalizationRegistry允许您注
  • Django 使用 Allauth 进行其余身份验证

    我已经用 Allauth 实现了 django Rest auth 如果我通过 google 登录 它工作正常access token但有一种情况 某些客户端设备需要通过谷歌登录id token 如果我使用 我会收到错误id token代替
  • 改造:如何在没有内容编码的情况下解析 GZIP 响应:gzip 标头

    我正在尝试处理 GZIP 的服务器响应 响应带有标头 Content Type application x gzip 但没有标题 Content Encoding gzip 如果我使用代理添加该标头 响应就会被很好地解析 我对服务器没有任何
  • 使用 JS 更改 svg 元素的位置

    尝试制作一个在按下按钮时移动的 svg 矩形 现在我只想通过函数修改 x function modX document getElementById rectangle transform translate 295 115 var x 2
  • 进程间通信建议[关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我正在寻找一种轻量级 快速且简单的方法来处理 Linux 计算机上某些程序之间的进程间通信 目前 我正在考虑命名管道 因为它是由操作系统本身提供的 关于性能或可用性有什么注意事项吗
  • 汇编语言 - 如何进行取模?

    x86 汇编中是否有类似模运算符或指令之类的东西 如果您的模数 除数是已知常数 并且您关心性能 请参阅this and this 对于直到运行时才知道的循环不变值 乘法逆甚至是可能的 例如看https libdivide com 但是如果没
  • 展开 折叠 展开 JTree 延迟加载的问题

    我已经使用延迟加载实现了一棵树 第一级节点是在创建树时创建的 而子节点仅在用户展开任何特定节点时创建 数据来自数据库 我们向数据库发出查询以填充子节点 实现了 TreeExpansionListener 并使用 treeExpanded 方