目录

  • 通过接口自动构建TreeView树形菜单
    • sql建表,预装数据
    • 查询结果集
    • main函数渲染结果
    • 核心算法源码
    • 总结

通过接口自动构建TreeView树形菜单

进行javafx开发时候,渲染树形菜单代码比较繁琐,本文将通过查询到的sql结果集,自动装配TreeView。其中装配算法通过java的引用重定向,递归回调等实现,,代码算法逻辑难道较大,小白慎入。且该算法可以升级到一切父子结构菜单,通过返回json串,只需要一次调用,即可渲染10层,100层菜单树。算法效率很高。复杂度仅仅为O(N)(N是所有节点个数)。

下例展示5层菜单的无延迟极快渲染

sql建表,预装数据


CREATE TABLE IF NOT EXISTS `menu0` (`id` int(11) DEFAULT NULL,`name` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='0级菜单';
INSERT INTO `menu0` (`id`, `name`) VALUES(1, '世界');CREATE TABLE IF NOT EXISTS `menu1` (`id` int(11) DEFAULT NULL,`name` varchar(50) DEFAULT NULL,`parent_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='一级菜单';
INSERT INTO `menu1` (`id`, `name`, `parent_id`) VALUES(1, '亚洲', 1),(2, '美洲', 1),(3, '欧洲', 1);CREATE TABLE IF NOT EXISTS `menu2` (`id` int(11) DEFAULT NULL,`name` varchar(50) DEFAULT NULL,`parent_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='二级菜单';
INSERT INTO `menu2` (`id`, `name`, `parent_id`) VALUES(1, '中国', 1),(2, '韩国', 1),(4, '美国', 2),(3, '日本', 1),(5, '加拿大', 2),(6, '墨西哥', 2),(7, '巴拿马', 2),(8, '英国', 3),(9, '法国', 3);CREATE TABLE IF NOT EXISTS `menu3` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(50) DEFAULT NULL,`parent_id` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COMMENT='三级菜单';
INSERT INTO `menu3` (`id`, `name`, `parent_id`) VALUES(1, '澳门', 1),(2, '香港', 1),(3, '首尔', 2),(4, '釜山', 2),(5, '纽约', 4),(6, '华盛顿', 4),(7, '安徽', 1),(8, '长崎', 3),(9, '东京', 3),(10, '多伦多', 5),(11, '阿瓜斯卡连特斯', 6),(12, '阿瓜斯卡连特斯1', 6),(13, '巴黎', 9),(14, '伦敦', 8),(15, '伯明翰', 8);CREATE TABLE IF NOT EXISTS `menu4` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(50) DEFAULT NULL,`parent_id` int(11) DEFAULT NULL,`parent_name` varchar(50) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COMMENT='四级菜单';
INSERT INTO `menu4` (`id`, `name`, `parent_id`, `parent_name`) VALUES(1, '澳门半岛', 1, '澳门'),(2, '九龙', 2, '香港'),(3, '江南区', 3, '首尔'),(4, '西临沙上区', 4, '釜山'),(5, '布朗克斯', 5, '纽约'),(6, '奥林匹亚市', 6, '华盛顿'),(7, '安庆', 7, '安徽'),(8, '半岛', 8, '长崎'),(9, '千代田区 ', 9, '东京'),(10, '士嘉堡', 10, '多伦多'),(11, 'a区', 11, '阿瓜斯卡连特斯'),(12, 'a1区', 12, '阿瓜斯卡连特斯1'),(13, '第1区', 13, '巴黎'),(14, '伦敦城', 14, '伦敦'),(15, 'a', 15, '伯明翰'),(16, '氹仔岛', 1, '澳门'),(17, '江东区', 3, '首尔'),(19, '布朗克斯', 5, '纽约'),(20, '布鲁克林', 5, '纽约'),(21, '斯波坎', 6, '华盛顿'),(22, '合肥', 7, '安徽'),(23, '蚌埠', 7, '安徽'),(24, '港区', 9, '东京'),(25, '中央区', 9, '东京'),(26, '第2区 ', 13, '巴黎'),(27, '第3区 ', 13, '巴黎'),(28, '西伦敦', 14, '伦敦');

查询结果集

selectcast(t0.id as char) f_f_1_menuId,t0.name f_f_1_menuName,cast(t1.id as char) f_f_2_menuId,t1.name f_f_2_menuName,cast(t2.id as char) f_f_3_menuId,t2.name f_f_3_menuName,cast(t3.id as char) f_f_4_menuId,t3.name f_f_4_menuName,cast(t4.id as char) f_f_5_menuId,t4.name f_f_5_menuNamefrom  menu0 t0 left join menu1 t1 on t0.id=t1.parent_idleft join menu2 t2 on t1.id=t2.parent_idleft join menu3 t3 on t2.id=t3.parent_idleft join menu4 t4 on t3.id=t4.parent_id

如下sql结果为:

main函数渲染结果

public class Main extends Application {private MysqlUtils mysqlUtils = new MysqlUtils();private MenuNode menuNode = new MenuNode();@Overridepublic void start(Stage primaryStage) {try {Pane p = new Pane();p.setPrefHeight(500);p.setPrefWidth(400);Scene scene = new Scene(p,800,800);scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());//@1 sql获取菜单集合,只需要查询菜单列表,调用一个接口,就自动获取treeview,你不需要去写任何sql以外的代码。String sql ="select\r\n" + "     cast(t0.id as char) f_f_1_menuId,\r\n" + "       t0.name f_f_1_menuName,\r\n" + "\r\n" + "     cast(t1.id as char) f_f_2_menuId,\r\n" + "       t1.name f_f_2_menuName,\r\n" + "\r\n" + "     cast(t2.id as char) f_f_3_menuId,\r\n" + "       t2.name f_f_3_menuName,\r\n" + "\r\n" + "     cast(t3.id as char) f_f_4_menuId,\r\n" + "       t3.name f_f_4_menuName,\r\n" + "     \r\n" + "        cast(t4.id as char) f_f_5_menuId,\r\n" + "       t4.name f_f_5_menuName\r\n" + "\r\n" + "      from  menu0 t0 \r\n" + "     left join menu1 t1 on t0.id=t1.parent_id\r\n" + "\r\n" + "       left join menu2 t2 on t1.id=t2.parent_id\r\n" + "\r\n" + "       left join menu3 t3 on t2.id=t3.parent_id\r\n" + "       left join menu4 t4 on t3.id=t4.parent_id";List<Map<String, Object>> muneList = mysqlUtils.getList(sql);//@2 调用公共接口,一键渲染得到treeview对象;TreeView<String> tree = menuNode.getMenuTreeview(muneList);tree.setPrefHeight(800);tree.setPrefWidth(800);//@3 写入scenep.getChildren().add(tree);primaryStage.setScene(scene);primaryStage.show();} catch(Exception e) {e.printStackTrace();}}public static void main(String[] args) {launch(args);}
}

运行代码得到结果如下:

核心算法源码

public static MenuNode getMenu(List<Map<String, Object>> muneList,MenuNode rootMenuNode, String... arg) throws Exception {MenuNode rootMenu = rootMenuNode;String menuStartWith = menuFieldRegDefalt;if(arg.length > 0) {//针对arg有参数,menuStartWith = arg[0];if(!RegexpTool.isMatch(menuStartWith, menuFieldRegLeft)) {throw new Exception(String.format("arg[0] pattern is not '%s'", menuFieldRegLeft) );}}/*** 1、获取菜单层次*/int maxLevel = 0;//菜单最大层数boolean f_1th_map = true;//第一次遍历muneList标记for(Map<String, Object> map : muneList) {//遍历数据行(f1_*,f1_*,f2_*,f2_*格式的数据)(后改成f_f_1_*)if(f_1th_map) {//第一次遍历记录maxLevelfor(Entry<String, Object> entry : map.entrySet()) {if(!RegexpTool.isMatch(entry.getKey(), menuFieldRegLeft + ".*")) {continue;}else {if(!RegexpTool.isMatch(entry.getKey(), menuFieldReg)) {throw new Exception(String.format("muneList field about mune %s pattern is not '%s'", entry.getKey(), menuFieldReg));}}String levelStr = RegexpTool.getOneByReg(entry.getKey(), "(?<="+menuStartWith+")\\d+");int level = Integer.parseInt(levelStr == null ? "0" : levelStr);//获取当前菜单层级。if(maxLevel < level) {maxLevel = level;}}f_1th_map = false;}int i = 0;List<MenuNode> enuNodeList_1 = new ArrayList<>();MenuNode menuNode = null;String parentId = "";while(maxLevel > i) {//依次处理 f1,f2,f3,f4...........,该行各个层级的数据,放入rootMenu 对应的位置。if(i == 0) {enuNodeList_1 = rootMenu.getMenuSub();}else {enuNodeList_1 = menuNode.getMenuSub();}/*** 获取map值。*/String parentID = (String) map.get(String.format("%s%d_%s", menuStartWith,i+1,"parentID"));String menuId = (String) map.get(String.format("%s%d_%s", menuStartWith,i+1,"menuId"));String menuName = (String) map.get(String.format("%s%d_%s", menuStartWith,i+1,"menuName"));String orderById = (String) map.get(String.format("%s%d_%s", menuStartWith,i+1,"orderById"));String remark = (String) map.get(String.format("%s%d_%s", menuStartWith,i+1,"remark"));String icon = (String) map.get(String.format("%s%d_%s", menuStartWith,i+1,"icon"));String style = (String) map.get(String.format("%s%d_%s", menuStartWith,i+1,"style"));String show = (String) map.get(String.format("%s%d_%s", menuStartWith,i+1,"show"));String path = (String) map.get(String.format("%s%d_%s", menuStartWith,i+1,"path"));boolean expanded = (boolean) (map.get(String.format("%s%d_%s", menuStartWith,i+1,"expanded")) == null ? false :map.get(String.format("%s%d_%s", menuStartWith,i+1,"expanded")));if(menuId == null) {break;}if(enuNodeList_1.size() == 0) {menuNode = new MenuNode(parentID == null ? "-1" : parentID, menuId == null ? "0" : menuId, menuName == null ? "0" : menuName, orderById == null ? "" : orderById,remark == null ? "" : remark, icon == null ? "" : icon, style == null ? "" : style, StringUtils.isBlank(show) ? "1" : show, expanded, path);enuNodeList_1.add(menuNode);}else {//如果size>0,且相等于当前,则menuNode重新指向;如果size=0且不相等,则新建。boolean f_sizem0e = false;//flagfor(MenuNode m : enuNodeList_1) {if(m.getMenuId().equals(menuId)) {menuNode = m;f_sizem0e = true;break;}}if(!f_sizem0e) {menuNode = new MenuNode(parentID == null ? "-1" : parentID, menuId == null ? "0" : menuId, menuName == null ? "0" : menuName, orderById == null ? "" : orderById,remark == null ? "" : remark, icon == null ? "" : icon, style == null ? "" : style, StringUtils.isBlank(show) ? "1" : show, expanded, path);enuNodeList_1.add(menuNode);}}enuNodeList_1 = menuNode.getMenuSub();//重新指向下一个menuNodei++;}}return rootMenu;}

总结

通过一个sql查询结果集,调用该源码公共接口,直接渲染模型。该算法,解决了遍历的空间复杂度,时间复杂度问题,合理利用java的对象引用概念,递归模式,灵活指向父子对象,完成百层,千层菜单渲染。而且你可以升级我的源码,将可以通过sql直接得到前端web界面需要的父子结果菜单json串,从而快捷渲染树形菜单。且比你的传统获取菜单方式快捷,方便。而且关于该源码算法,也是研读了base64算法源码,得来的灵感。当然该算法对java引用的理解要求高。我相信你如果喜欢java,通过java实现复杂算法逻辑,实现复杂的业务逻辑,你可以下载该源码,执行完sql建表语句后,可以在jdk环境下直接运行。欢迎大家一起交流,你会发现java很美妙。最近也改造了不少javafx相关源码,你会发现这是一件有趣的事情。且在这个过程中你会体会到对象这个概念在java中是如何诠释地淋漓尽致。万物皆对象。且我的博客以后会发很多类似文章。
博主希望实现公司项目地复杂算法逻辑,对于java性能优化,sql优化有较多实践。欢迎各位,不吝赐教。其实我也是一个菜鸟,很多都不懂,只是喜欢java 对象,它很优雅。
算法java项目:

  • csdn地址:treeview树形菜单渲染算法
  • 原站地址:treeview树形菜单渲染算法

欢迎阅读源码,交流。正在搭建中网站:albagu.com;

javafx treeview菜单千层渲染算法相关推荐

  1. 千层套路 - Vue 3.0 初始化源码探秘

    关注若川视野, 回复"pdf" 领取资料,回复"1",可加群长期交流学习 刘崇桢,微医云服务团队前端工程师,左手抱娃.右手持家的非典型码农. 9 月初 Vue. ...

  2. 《预训练周刊》第40期: 量子预训练、千层BERT与GPT

    No.40 智源社区 预训练组 预 训 练 研究 观点 资源 活动 周刊订阅 告诉大家一个好消息,<预训练周刊>已经开启"订阅功能",以后我们会向您自动推送最新版的&l ...

  3. DeepMind激起千层浪的这篇论文,并非无所不能

    皇甫琦 葛冬冬 撰稿 金磊 整理自 凹非寺 量子位 报道 | 公众号 QbitAI 本文对DeepMind近期的神经网络求解MIP(混合整数规划)的论文进行了一些初步解读.事实上,相较于此领域近期的类 ...

  4. 高糊视频秒变4K!Facebook发布低分辨率视频实时渲染算法,网友:是好东西,但是玩不起...

    贾浩楠 发自 凹非寺 量子位 报道 | 公众号 QbitAI 还记得那个引来巨大争议,最后把LeCun逼退推特的低分辨率图像还原算法PULSE吗? PULSE是针对低分辨率图像进行还原的,而就在PUL ...

  5. sql server 2014 判断一个列某个字段是否相同_Select * from user的千层套路——一个sql是如何执行的...

    Select * from user的千层套路 作为一个程序员,可以说是无时无刻不与sql语句进行打交道,可是你真的了解MySQl的基本框架吗?以及你所写的每一条SQL是如何运行的吗?就比如下面这条平 ...

  6. SSM框架之酒店管理系统三(菜单数据库设计,菜单列表查询渲染)

    SSM框架之酒店管理系统三(菜单数据库设计,菜单列表查询渲染) 参考LAYUI MINI官网给出的数据库设计规范 Java示例(spring) · layuimini开发手册 (99php.cn) 数 ...

  7. 【图数据】股权网络穿透一千层需要多久?

    [图数据]股权网络穿透一千层需要多久? 图数据关系路径穿透测试 图数据库选型 图数据模型说明 股权网络穿透一百层 穿透一百层查询语句 穿透一百层10次测试执行结果 股权网络穿透一千层 穿透一千层查询语 ...

  8. 高糊视频秒变4K!Facebook发布低分辨率视频实时渲染算法,网友:是好东西,但是玩不起

    还记得那个引来巨大争议,最后把LeCun逼退推特的低分辨率图像还原算法PULSE吗? PULSE是针对低分辨率图像进行还原的,而就在PULSE问世不久后,一个针对模糊视频进行实时高分辨率渲染的算法问世 ...

  9. DL之DNN:基于神经网络(从1层~50层)DNN算法实现对非线性数据集点进行绘制决策边界

    DL之DNN:基于神经网络(从1层~50层)DNN算法实现对非线性数据集点进行绘制决策边界 目录 输出结果 设计代码 输出结果 设计代码 首先查看数据集 import numpy as np from ...

最新文章

  1. PTA 栈 (20分)(全网首发)(实现一个栈Stack,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值的操作)的时间复杂度为O(1))
  2. 计算机一级办公软件选择题,计算机一级MSOffice习题
  3. C++安全方向openssl(三):3.2 md5算法原理详解以及代码实现
  4. java rcp教程_Eclipse RCP教程 - 13 - 练习:创建Eclipse RCP程序 | JavaFX中文资料
  5. 机器学习实战练手项目
  6. 中南大学计算机软件专业曾进,中南大学_2012年校级优秀毕业生名单
  7. Nacos注册中心AP架构源码(Distro)上篇
  8. 求最大公约数 最大公因数 语言实现输出一个整数的最大公约数(因数),四种算法实现
  9. 制作半透明的毛玻璃效果教程
  10. 计算机网络(五) | 数据链路层:MAC地址、以太网协议、MTU和ARP协议
  11. Y9000P 2022独显直连
  12. python判断身份证是否合法的函数_oracle中验证身份证是否合法的函数脚本
  13. 微信连wifi3.1总结
  14. 破窑赋--11.11在一个小吃店看到
  15. (CVPR-2018)Non-local Neural Networks
  16. (Python)五子棋
  17. sql server 创建动态交叉表
  18. SQL中的连接查询与嵌套查询
  19. 伪类、伪元素及五星好评css实现
  20. java打字游戏和解析_java类与对象案例之打字游戏

热门文章

  1. leetcode LCP 10. 二叉树任务调度
  2. 实用围棋作战理论——围棋十诀,据说是从唐朝流传下来的哦
  3. Hibernate 中的attachDirty,attachClean,merge,findByProperty和findByExample
  4. 074 定积分之推广积分中值定理
  5. LMT LicManager大幅提升Solidworks许可效率成效分析
  6. 【计算机毕业设计】电影院售票网站
  7. Java入门——多态详解
  8. U2Net论文解读及代码测试
  9. 微信小程序的番茄闹钟
  10. 国内AI绘画软件“数画”的相机溯源码功能太强大,彻底消灭盗图