JavaFx TreeView TreeItem 设置额外属性

news2024/11/21 0:21:15

在使用JavaFx 编写GUI程序时,不可避免的需要创建一个树组件,下面是一个简单的树组件的代码。

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TreeViewTest extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("TreeViewTest");
        VBox vBox = new VBox();
        buildTreeView(vBox);
        Scene scene = new Scene(vBox);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    public void buildTreeView(Pane parent) {
        TreeView<String> treeView = new TreeView<>();
        TreeItem<String> rootItem = new TreeItem<>("五年级");
        for (int i = 0; i < 10; i++) {
            TreeItem<String> treeItem = new TreeItem<>("张三" + i);
            rootItem.getChildren().add(treeItem);
        }
        treeView.setRoot(rootItem);
        parent.getChildren().add(treeView);
    }
}

通过上面的代码我们就实现了一个简单的树的构建,效果如图:

但是我们构建了树,有时候并不简简单单的只做展示用,有时候我们还会对树进行操作,比如获取选择节点的详细信息,如我们上面创建的树形图展示的是一个班级的学生,那么如果我需要点击某个学生然后弹出该学生的具体信息应该怎么做呢?一个立马能想到的方法是在创建树节点的时候,将学生的额外属性封装到树节点中去,要知道TreeItem才是节点组件,TreeView只是父组件,TreeView只能设置根TreeItem,此时我们查看TreeItem的方法,

发现并没有设置额外属性的方法。

然后想到javaFx的 property属性,

 

但是也并没有找到符合我们需要的属性。

难道JavaFx 的TreeView 在设计的时候没有考虑过这个需求吗?答案是否定的,我们看一下Tree的源码:

 我们看到在类注释上有个泛型 T 它的意思是:

–此TreeView中所有树项的TreeItem值属性中包含的项的类型。

就是说,你创建TreeView 时给的是什么类型,TreeItem就封装了什么类型,然后观察TreeItem的源码,

TreeItem中{@link#getValue()值}属性的类型。

发现TreeItem中也存在T的泛型,而且可以通过TreeItem.getValue()方法得到T的实例对象,那现在一目了然了,我们在构建TreeItem的时候完全可以将我们的学生类封装进去,这样当我获取额外属性时,就可以通过getValue()方法获取了,不过另一个问题是,在这个节点上我显示的是什么,如果我封装的是对象的话,是不是显示的就是对象地址?

我们查看TreeItem的setValue()方法:

public class TreeItem<T> implements EventTarget { 

    ....略......
    /**
     * Sets the application-specific data represented by this TreeItem.
     */
    public final void setValue(T value) { 
       valueProperty().setValue(value); 
    }

    /**
     * A property representing the application-specific data contained within
     * this TreeItem.
     */
    public final ObjectProperty<T> valueProperty() {
        if (value == null) {
            value = new ObjectPropertyBase<T>() {
                @Override protected void invalidated() {
                    fireEvent(new TreeModificationEvent<T>(VALUE_CHANGED_EVENT, TreeItem.this, get()));
                }

                @Override public Object getBean() {
                    return TreeItem.this;
                }

                @Override public String getName() {
                    return "value";
                }
            };
        }
        return value;
    }

  ....略......

}

通过源码我们发现最终设置值的方法是通过ObjectProperty.setValue()来实现的,我们继续跟踪来到

javafx.beans.value.WritableObjectValue
public interface WritableObjectValue<T> extends WritableValue<T> {

    /**
     * Get the wrapped value. This must be identical to
     * the value returned from {@link #getValue()}.
     * <p>
     * This method exists only to align WritableObjectValue API with
     * {@link WritableBooleanValue} and subclasses of {@link WritableNumberValue}
     * @return The current value
     */
    T get();

    /**
     * Set the wrapped value.
     * Should be equivalent to {@link #setValue(java.lang.Object) }
     * @see #get()
     *
     * @param value
     *            The new value
     */
    void set(T value);

}

 由此我们看到确实设置的是对象,但是我们希望节点在展示的时候是String文字,而不是内存地址。等一下,这一点有点像打印对象。我们做一个测试

public class Main {
    public static void main(String[] args) {
        User user = new User("张三",33);
        System.out.println(user);

    }
   static class User {
        private String name;
        private Integer age;

        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    }
}

打印结果:

更改一下代码:

public class Main {
    public static void main(String[] args) {
        User user = new User("张三",33);
        System.out.println(user);

    }
   static class User {
        private String name;
        private Integer age;

        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

       @Override
       public String toString() {
           return "User{" +
                   "name='" + name + '\'' +
                   ", age=" + age +
                   '}';
       }
   }
}

 打印结果如下:

 我们发现改动后的代码只是添加了toString()方法而已,打印出来的内容就变成了人可以理解的内容。

那如果TreeItem封装的对象设置了toString()方法,是不是节点的显示内容就是toString()方法返回的内容呢?

更新代码如下:

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TreeViewTest extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("TreeViewTest");
        VBox vBox = new VBox();
        buildTreeView(vBox);
        Scene scene = new Scene(vBox);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    public void buildTreeView(Pane parent) {
        TreeView<Student> treeView = new TreeView<>();
        TreeItem<Student> rootItem = new TreeItem("五年级");
        for (int i = 0; i < 10; i++) {
            Student student = new Student("张三" + i, 10 + i);
            TreeItem<Student> treeItem = new TreeItem(student);
            rootItem.getChildren().add(treeItem);
        }
        treeView.setRoot(rootItem);
//        设置TreeView的点击事件
        treeView.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                TreeItem<Student> selectedItem = treeView.getSelectionModel().getSelectedItem();
                if (selectedItem == null) return;
                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setContentText(selectedItem.getValue().toString2());
                alert.show();
            }
        });
        parent.getChildren().add(treeView);
    }

    static class Student {
        private String name;
        private Integer age;

        public Student(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return name;
        }

        
        public String toString2() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
}

效果如图:

可以发现我们取到了封装的额外属性。

当然实际情况可能会更复杂,比如不同层级的TreeItem可能封装的对象不同,此时我们在定义TreeView时,泛型最好指定一个基类,比如BaseModel,然后各个属性类去继承该基类,然后实现各自的toString()方法,在获取属性值时,先判断当前选中的节点的层级,然后从基类强转到实际的属性类即可!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/110324.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

clickhouse笔记05--快速部署3节点集群

clickhouse笔记05--快速部署3节点集群1 介绍2 方法步骤2.1 部署 zookeeper 集群2.2 拉起 clickhouse 集群2.3 测试集群3 注意事项4 说明1 介绍 clickhouse笔记01–快速部署clickhouse 介绍了如何快速部署单节点clickhouse服务&#xff0c;本文基于该博文继续介绍如何快速部署3…

Java进阶—JUC编程

1、线程和进程 获取CPU核数 /*** author java小豪* version 1.0.0* date 2022/12/15* description 测试*/ public class Test {public static void main(String[] args) {// 获取CPU核数// CPU 密集型&#xff0c;IO密集型System.out.println(Runtime.getRuntime().available…

响应式营销策划文化传媒公司网站模板源码

模板信息&#xff1a; 模板编号&#xff1a;8071 模板编码&#xff1a;UTF8 模板颜色&#xff1a;蓝色 模板分类&#xff1a;设计、广告、文化、影视 适合行业&#xff1a;影视传媒类企业 模板介绍&#xff1a; 本模板自带eyoucms内核&#xff0c;无需再下载eyou系统&#xf…

qt5实现pdf阅读器(三)——pdfjs

目录 1、参考 2、实现 3、开发记录 1、参考 使用Qt的WebEngine和javascript的pdf.js模块构建的PDF查看器。 参考链接1&#xff1a;GitHub - Archie3d/qpdf: PDF viewer widget for Qt 参考链接2&#xff1a;GitHub - yshurik/qpdfjs: Desktop PDF Viewer based on Qt and…

讯飞听见SaaS服务迈入全新时代

配图来自Canva可画 随着数字化时代的来临&#xff0c;国内各企业为了提升行业竞争力&#xff0c;纷纷开始利用数字化技术&#xff0c;来实现以降本增效为核心的数字化转型&#xff0c;得益于此&#xff0c;助力企业数字化转型升级的SaaS也开始进一步升温。 众所周知&#xff…

【代码审计-2】PHP框架MVC类文件上传断点测试挖掘

1.文件上传漏洞挖掘&#xff1a; (1)关键字搜索&#xff08;函数、键字、全局变量等&#xff09;&#xff1a;比如$_FILES&#xff0c;move_uploades_file等 (2)应该功能抓包&#xff1a;寻找任何可能存在上传的应用功能点&#xff0c;比如前台会员中心&#xff0c;后台新闻添…

电力系统两阶段随机优化(Matlab实现)

目录 目录 1 概述 2 单级随机优化算法 2.1 随机化-最小化 2.2 随机逐次凸近似 &#xff08;SCA&#xff09; 3 两级随机优化算法 3.1 批处理算法 3.2 在线算法 4 Matlab代码实现 1 概述 在与随机系统状态向量关联的两阶段随机优化问题中&#xff0c;优化变量分为两组…

Web前端105天-day32-HTML5_CORE

HTML5CORE02 目录 前言 一、复习 二、拖拽 三、上传服务器 四、Canvas 五、地图 总结 前言 HTML5CORE02学习开始 一、复习 跨域 浏览器的同源策略导致在网页中, 通过 AJAX 发送网络请求时, 默认只能向同源的服务器请求同源: 协议 端口号 域名 三者都相同产生跨域的原因…

RocketMQ疑难杂症之No route info of this topic解决方案

成因&#xff1a; 由于配置了 docker 虚拟 IP&#xff0c;导致 brocker 总是代理到 docker 的虚拟 IP 上。 原理&#xff1a; RocketMQ 的 broker 启动类 org.apache.rocketmq.broker.BrokerStartup 启动的时候会读取代码中的默认配置&#xff0c;关于 broker 的配置在 org.apa…

【关于时间序列的ML】项目 8 :使用 Facebook Prophet 模型预测股票价格

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

30.深度学习模型压缩方法-4

30.1 低秩分解 基于低秩分解的深度神经网络压缩与加速的核心思想是利用矩阵或张量分解技术估计并分解深度模型中的原始卷积核 卷积计算是整个卷积神经网络中计算复杂 度 最 高 的 计 算 操 作,通 过 分 解4D 卷积核张量,可以有效地减少模型内部的冗余性此外对于2D的全 连…

Hive+Spark离线数仓工业项目实战--项目介绍及环境构建(1)

项目简介 通过大数据技术架构&#xff0c;解决工业物联网制造行业的数据存储和分析、可视化、个性化推荐问题。一站制造项目主要基于Hive数仓分层来存储各个业务指标数据&#xff0c;基于sparkSQL做数据分析。核心业务涉及运营商、呼叫中心、工单、油站、仓储物料。 推荐教程…

DSP_TMS320F28377D_eCAP学习笔记

博主学习eCAP的使用主要是用于处理霍尔传感器&#xff0c;计算电机的电角度以及角速度。首先还是看了点哔哩哔哩的学习视频。 eCAP介绍 脉冲量的输入是在数字控制系统中最常见的一类输入量&#xff0c;控制器专门设置了脉冲捕获模块 (eCAP)来处理脉冲量&#xff0c;通过脉冲捕…

路由器的工作原理(计算机网络-网络层)

目录 路由器的构成 转发和路由选择的区别 典型的路由器结构 交换结构 输出端口 路由器与交换机的比较 两种基于存储转发的分组交换设备的比较 交换机和路由器各有的应用场合 三层交换机 三层交换机的应用 路由器的构成 路由器的任务 路由器是一种具有多个输入端口和多…

MT8385 Android AB分区系统升级(命令模式)

AB系统分区升级使用的是update_engine,RecoverySystem 只适用于单分区的系统升级 1.解压开update.zip 可以查看到palyload的属性 2.使用ADB命令update_engine_client即可对AB分区进行升级 使用adb shell 命令进行升级 update_engine_client --payload xxx --update --header…

【TypeScript】TS类型声明(二)

&#x1f431;个人主页&#xff1a;不叫猫先生 &#x1f64b;‍♂️作者简介&#xff1a;前端领域新星创作者、华为云享专家、阿里云专家博主&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; &#x1f4ab;系列专栏&#xff…

k8s HPA升级 KEDA 基于prometheus的数据指标进行弹性伸缩

说明&#xff1a;KEDA有啥用&#xff0c;相对HPA有啥优势。HPA针对于cpu,内存来进行弹性伸缩&#xff0c;有点不太精确。KEDA可以接入prometheus&#xff0c;根据prometheus的数据指标进行弹性伸缩&#xff0c;相比更加的精准实用。 安装k8s环境部署prometheus 创建ns&#xf…

【软件测试】那些35岁以上的测试人哪去了?

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 先根据大体年龄阶段…

B+树详解,一次就懂

⭐注意&#xff1a;不会直接讲 B树的结构&#xff0c;会从最简单的二叉树开始讲起来。如果认真看完&#xff0c;我想你对树类型的数据结构的理解又上了一个新的台阶。 ⭐如果有误&#xff0c;请大家指出。下文均是在B站学习的过程中&#xff0c;总结的笔记和心得体会 索引结构 …

四、网络层(五)IP组播

目录 5.1 组播的概念 5.2 IP组播的地址 5.3 因特网组管理协议&#xff08;IGMP&#xff09; 5.4 组播路由算法 5.1 组播的概念 为了更好地支持像视频会议这类一对多的通信&#xff0c;需要源主机一次发送的单个分组&#xff0c;能抵达用一个组地址标识的若干台目的主…